The snippet below shows sample code that uses the MediaStore API to write a file to shared storage in a path like /storage/emulated/0/Download/ which does not require any permissions to access and is shared with other apps.
packageorg.owasp.mastestappimportandroid.content.ContentValuesimportandroid.util.Logimportandroid.content.Contextimportandroid.os.Environmentimportandroid.provider.MediaStoreimportjava.io.OutputStreamclassMastgTest(privatevalcontext:Context){funmastgTest():String{try{valresolver=context.contentResolvervalcontentValues=ContentValues().apply{put(MediaStore.MediaColumns.DISPLAY_NAME,"secretFile.txt")put(MediaStore.MediaColumns.MIME_TYPE,"text/plain")put(MediaStore.MediaColumns.RELATIVE_PATH,Environment.DIRECTORY_DOWNLOADS)}valtextUri=resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI,contentValues)textUri?.let{valoutputStream:OutputStream? =resolver.openOutputStream(it)outputStream?.use{it.write("MAS_API_KEY=8767086b9f6f976g-a8df76\n".toByteArray())it.flush()}Log.d("MediaStore","File written to external storage successfully.")return"SUCCESS!!\n\nMediaStore inserted to $textUri"}?:run{Log.e("MediaStore","Error inserting URI to MediaStore.")return"FAILURE!!\n\nMediaStore couldn't insert data."}}catch(exception:Exception){Log.e("MediaStore","Error writing file to URI from MediaStore",exception)return"FAILURE!!\n\nMediaStore couldn't insert data."}}}
packageorg.owasp.mastestapp;importandroid.content.ContentResolver;importandroid.content.ContentValues;importandroid.content.Context;importandroid.net.Uri;importandroid.os.Environment;importandroid.provider.MediaStore;importandroid.util.Log;importjava.io.OutputStream;importkotlin.Metadata;importkotlin.Unit;importkotlin.io.CloseableKt;importkotlin.jvm.internal.Intrinsics;importkotlin.text.Charsets;/* compiled from: MastgTest.kt */@Metadata(d1={"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0000\b\u0007\u0018\u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0002\u0010\u0004J\u0006\u0010\u0005\u001a\u00020\u0006R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\u0007"},d2={"Lorg/owasp/mastestapp/MastgTest;","","context","Landroid/content/Context;","(Landroid/content/Context;)V","mastgTest","","app_debug"},k=1,mv={1,9,0},xi=48)/* loaded from: classes4.dex */publicfinalclassMastgTest{publicstaticfinalint$stable=8;privatefinalContextcontext;publicMastgTest(Contextcontext){Intrinsics.checkNotNullParameter(context,"context");this.context=context;}publicfinalStringmastgTest(){try{ContentResolverresolver=this.context.getContentResolver();ContentValuescontentValues=newContentValues();contentValues.put("_display_name","secretFile.txt");contentValues.put("mime_type","text/plain");contentValues.put("relative_path",Environment.DIRECTORY_DOCUMENTS);UritextUri=resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues);if(textUri!=null){OutputStreamoutputStream=resolver.openOutputStream(textUri);if(outputStream!=null){OutputStreamoutputStream2=outputStream;OutputStreamit=outputStream2;byte[]bytes="MAS_API_KEY=8767086b9f6f976g-a8df76\n".getBytes(Charsets.UTF_8);Intrinsics.checkNotNullExpressionValue(bytes,"this as java.lang.String).getBytes(charset)");it.write(bytes);it.flush();Unitunit=Unit.INSTANCE;CloseableKt.closeFinally(outputStream2,null);}Log.d("MediaStore","File written to external storage successfully.");return"SUCCESS!!\n\nMediaStore inserted to "+textUri;}MastgTestmastgTest=this;Log.e("MediaStore","Error inserting URI to MediaStore.");return"FAILURE!!\n\nMediaStore couldn't insert data.";}catch(Exceptionexception){Log.e("MediaStore","Error writing file to URI from MediaStore",exception);return"FAILURE!!\n\nMediaStore couldn't insert data.";}}}
rules:-id:mastg-android-data-unencrypted-shared-storage-no-user-interaction-external-api-publicseverity:WARNINGlanguages:-javametadata:summary:Thisrulelooksformethodsthatreturnslocationsto"external storage"whichissharedwithotherappsmessage:"[MASVS-STORAGE] Make sure to encrypt files at these locations if necessary"pattern-either:-pattern:$X.getExternalStorageDirectory(...)-pattern:$X.getExternalStoragePublicDirectory(...)-pattern:$X.getDownloadCacheDirectory(...)-pattern:Intent.ACTION_CREATE_DOCUMENT-id:mastg-android-data-unencrypted-shared-storage-no-user-interaction-external-api-scopedseverity:WARNINGlanguages:-javametadata:summary:Thisrulelooksformethodsthatreturnslocationsto"scoped external storage"message:"[MASVS-STORAGE] These locations might be accessible to other apps on Android 10 and below given relevant permissions"pattern-either:-pattern:$X.getExternalFilesDir(...)-pattern:$X.getExternalFilesDirs(...)-pattern:$X.getExternalCacheDir(...)-pattern:$X.getExternalCacheDirs(...)-pattern:$X.getExternalMediaDirs(...)-id:mastg-android-data-unencrypted-shared-storage-no-user-interaction-mediastoreseverity:WARNINGlanguages:-javametadata:summary:ThisrulescansforusesofMediaStoreAPIthatwritesdatatotheexternalstorage.Thisdatacanbeaccessedbyotherapps.message:"[MASVS-STORAGE] Make sure to want this data to be shared with other apps"pattern-either:-pattern:importandroid.provider.MediaStore-pattern:$X.MediaStore
The first location is the import statement for the MediaStore API and the second location is where the MediaStore API is used to write to shared storage.
After reviewing the decompiled code at the locations specified in the output (file and line number) we can conclude that the test fails because the file written by this instance contains sensitive data, specifically a API key.