DEV Community

Jason Miller
Jason Miller

Posted on Originally published at axeploit.com

No CVE Is Coming for Android-Image-Cropper. Audit Anyway.

A report on r/netsec claims an arbitrary file overwrite in Android-Image-Cropper, the library behind the crop screen in a huge number of apps. The original thread is unreachable, there's no CVE, and anyone claiming to know the exact affected versions is guessing. Audit anyway.

The uncertainty buys you nothing. The ArthurHub repo (6.4k stars, 1.4k forks) states flatly in its README: "The Project is NOT currently maintained." The changelog ends at 2.8.0 with an Android O crash fix, no security entries anywhere. There is no maintainer left to ship a patch, so every release of that line stays exposed whatever the precise trigger turns out to be. An abandoned file-handling library whose setup requested WRITE_EXTERNAL_STORAGE does not belong in a shipping app. That judgment needs no advisory.

One codebase, three Maven coordinates

This is where audits actually fail. The lineage runs edmodo to ArthurHub to the maintained CanHub fork, and each hop left a coordinate behind:

com.theartofdev.edmodo:android-image-cropper:2.8.+   (ArthurHub line, abandoned)
com.github.arthurhub:android-image-cropper:2.7.0     (JitPack build of the same)
com.vanniktech:android-image-cropper:4.7.0           (CanHub fork, maintained)
Enter fullscreen mode Exit fullscreen mode

An SCA rule keyed on one groupId sees at most a third of this family. Blacklist com.theartofdev.edmodo and the same jar arrives clean via com.github.arthurhub. And that first version string, 2.8.+, is its own problem: two builds a week apart can resolve different artifacts, so even a correct audit expires.

The audit you can run this afternoon

./gradlew :app:dependencies --configuration releaseRuntimeClasspath > deps.txt
grep -niE "theartofdev|arthurhub|canhub|vanniktech" deps.txt
Enter fullscreen mode Exit fullscreen mode

A hit you don't remember adding means the cropper arrived transitively, often inside a messaging or onboarding SDK. Run ./gradlew :app:dependencyInsight --configuration releaseRuntimeClasspath --dependency android-image-cropper to name the parent.

Then check what the manifest merge granted with aapt dump permissions app-release.apk. If WRITE_EXTERNAL_STORAGE appears and your only broad-storage consumer is the crop flow, the library is inflating your blast radius.

Now your own call sites:

grep -rnE "CropImage\.activity|setImageUriAsync|getUri\(\)|CropImageView" app/src
Enter fullscreen mode Exit fullscreen mode

The API is Uri in, Uri out. At each call site, ask who chooses where the cropped file lands. If the destination derives from anything outside your process (an intent extra, a deep link parameter, the source image's filename) and nothing confines it to a directory you own, that is the overwrite pattern. On pre-scoped-storage devices with the write permission granted, "anywhere" includes shared storage other apps depend on.

Fix in order of preference. Migrate to CanHub: pin 4.3.3, rewrite every import from com.theartofdev.edmodo.cropper to com.canhub.cropper, then climb minor by minor to 4.7.0. If it has to wait, wrap the old library so your code owns both ends of the Uri contract: CropImageView inside your own Activity, an output file you generate under getExternalFilesDir(), a name you chose, never derived from the source Uri. CanHub's stated direction is that Uri handling belongs to the app, so the wrapper is your end state either way.

What you can do today:

  • Run both greps above against releaseRuntimeClasspath and your source tree; use dependencyInsight to find which SDK drags the cropper in.
  • Replace every + wildcard version with a pinned one, and fail CI on new ones.
  • Own the output destination: app-generated filename in app-private storage, never derived from the input.
  • Teach your SCA to match artifact families (forks, JitPack mirrors) and to flag archived repos as findings even when no advisory exists.

Has your tooling ever flagged a dependency for being abandoned rather than for a CVE? Curious how many teams treat maintenance state as a finding on its own.

Longer writeup if you want the full verification trail and migration path: https://axeploit.com/blog/one-cropper-three-coordinates-finding-the-android-image-overwrite-in-your-dependency-tree

Top comments (0)