READ_MEDIA_IMAGES¶
Allows reading image files (photos, screenshots) from shared storage via MediaStore. Introduced in Android 13 as a granular replacement for READ_EXTERNAL_STORAGE, giving users control over which media types an app can access.
Technical Details¶
| Attribute | Value |
|---|---|
| Permission | android.permission.READ_MEDIA_IMAGES |
| Protection Level | dangerous |
| Permission Group | READ_MEDIA_VISUAL (Android 14+) |
| Grant Method | Runtime permission dialog |
| Introduced | API 33 (Android 13) |
What It Enables¶
Query MediaStore.Images for all photos and screenshots on the device. Includes EXIF metadata (GPS coordinates, camera model, timestamps).
Abuse in Malware¶
Photo Exfiltration¶
Steal personal photos for blackmail, identity theft, or intelligence gathering. Screenshots may contain sensitive information (banking app screens, private messages, authentication codes).
EXIF Location Data¶
Photos contain GPS coordinates in EXIF metadata, revealing where and when they were taken, even without location permission.
Document Theft via Screenshots¶
Users often screenshot sensitive documents, banking details, and passwords. These are accessible through this permission.
Notable Families¶
| Family | Usage |
|---|---|
| SparkCat | Uses Google ML Kit OCR to scan gallery photos for cryptocurrency wallet seed phrases |
| SpyAgent | OCR-based scanning of device photos for crypto mnemonic seed phrases targeting Korean users |
| SpyLoan | Exfiltrates personal photos for blackmail and extortion of loan defaulters |
SparkCat and SpyAgent represent an emerging threat pattern: on-device OCR to extract cryptocurrency recovery phrases from screenshots. Both families scan the gallery using MediaStore.Images, process each image through text recognition, and selectively exfiltrate images matching BIP-39 seed phrase patterns. SpyLoan takes a different approach, collecting personal photos during "identity verification" and weaponizing them if borrowers default on predatory loans.
READ_EXTERNAL_STORAGE vs Granular Permissions¶
SparkCat is a notable example of the permission transition in action. Its manifest declares both READ_EXTERNAL_STORAGE (for pre-Android 13 devices) and READ_MEDIA_IMAGES (for API 33+), ensuring the OCR scanning works across all Android versions. SpyLoan similarly declares both because its Play Store distribution requires targeting current API levels.
- SparkCat declares both
READ_EXTERNAL_STORAGEandREAD_MEDIA_IMAGESin its manifest - Anubis uses
READ_EXTERNAL_STORAGEfor file browsing and exfiltration on older Android versions - Mamont uses
READ_EXTERNAL_STORAGEfor photo and file access - FireScam uses
READ_EXTERNAL_STORAGEfor device storage access
Families that only declare READ_EXTERNAL_STORAGE without READ_MEDIA_IMAGES will lose photo access on devices running Android 13+ if they target API 33+. However, many sideloaded malware families deliberately target API 32 or lower to avoid the granular permission split entirely.
Abuse Code Example¶
public class ImageScanner {
private final ContentResolver resolver;
private final TextRecognizer recognizer;
private final List<String> seedWords;
public ImageScanner(ContentResolver resolver, List<String> seedWords) {
this.resolver = resolver;
this.seedWords = seedWords;
this.recognizer = TextRecognition.getClient(
new TextRecognizerOptions.Builder().build()
);
}
public void scanGalleryForSeedPhrases() {
String[] projection = {
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATE_ADDED
};
Cursor cursor = resolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
null, null,
MediaStore.Images.Media.DATE_ADDED + " DESC"
);
if (cursor == null) return;
while (cursor.moveToNext()) {
long id = cursor.getLong(0);
Uri imageUri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id
);
processImage(imageUri);
}
cursor.close();
}
private void processImage(Uri uri) {
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(resolver, uri);
InputImage inputImage = InputImage.fromBitmap(bitmap, 0);
recognizer.process(inputImage)
.addOnSuccessListener(text -> {
String detected = text.getText().toLowerCase();
int matchCount = 0;
for (String word : seedWords) {
if (detected.contains(word)) matchCount++;
}
if (matchCount >= 8) {
exfiltrateImage(uri);
}
});
} catch (Exception e) {
}
}
private void exfiltrateImage(Uri uri) {
}
}
This pattern mirrors SparkCat's approach: enumerate all images, run OCR on each, match against BIP-39 wordlist patterns, and selectively exfiltrate images that contain enough seed phrase words to indicate a wallet backup screenshot.
Android Version Changes¶
Android 13 (API 33): introduced as replacement for READ_EXTERNAL_STORAGE for media access. Apps targeting API 33+ must request this specific permission for image access.
Android 14 (API 34): users can grant partial access (select specific photos) instead of full access. The app may not see all images. This significantly impacts OCR-based stealers like SparkCat, as partial access limits the gallery surface available for scanning. However, malware can re-prompt the user to "select all" or use social engineering to obtain full access.
Android 14 (API 34): READ_MEDIA_IMAGES grouped with READ_MEDIA_VIDEO in the READ_MEDIA_VISUAL permission group. Granting one grants the other.
Pre-Android 13: apps use READ_EXTERNAL_STORAGE which grants access to all file types including images, making image-specific abuse harder to distinguish.
Detection¶
In the manifest:
Analysis Indicators¶
- Google ML Kit or Tesseract OCR library bundled in an app that has no text-recognition feature in its UI is a strong indicator of SparkCat-style abuse.
- Look for
MediaStore.Imagesqueries combined with image processing APIs (Bitmap,InputImage,TextRecognizer). - Apps that enumerate all images in the gallery without displaying them to the user are performing reconnaissance or bulk scanning.
- Check for EXIF metadata extraction --
ExifInterfaceusage combined withINTERNETindicates location data exfiltration. ContentObserverregistration onMediaStore.Imagesfor real-time monitoring of new screenshots is common in stalkerware and OCR stealers.- On pre-Android 13 samples,
READ_EXTERNAL_STORAGEwithMediaStore.Imagesqueries achieves the same result -- the broader permission masks image-specific intent.
See Also¶
- READ_EXTERNAL_STORAGE -- the pre-Android 13 permission that granted access to all media types including images
- READ_MEDIA_VIDEO -- grouped with
READ_MEDIA_IMAGESin theREAD_MEDIA_VISUALpermission group on Android 14+ (granting one grants the other) - READ_MEDIA_AUDIO -- companion granular permission for audio access
- Clipboard Hijacking -- related cryptocurrency theft technique that targets seed phrases copied to clipboard rather than photographed