The snippet below shows sample code that creates a file in external storage using the getExternalFilesDir API which returns a path to the app's external files directory (e.g. /storage/emulated/0/Android/data/org.owasp.mastestapp/files) and does not require any permissions to access. Scoped storage applies since the app targets Android 12 (API level 31) which is higher than Android 10 (API level 29).
packageorg.owasp.mastestappimportandroid.content.Contextimportandroid.util.Logimportjava.io.Fileimportjava.io.FileOutputStreamimportjava.io.IOExceptionclassMastgTest(privatevalcontext:Context){funmastgTest():String{valexternalStorageDir=context.getExternalFilesDir(null)valfileName=File(externalStorageDir,"secret.txt")valfileContent="secr3tPa\$\$W0rd\n"try{FileOutputStream(fileName).use{output->output.write(fileContent.toByteArray())Log.d("WriteExternalStorage","File written to external storage successfully.")}}catch(e:IOException){Log.e("WriteExternalStorage","Error writing file to external storage",e)return"ERROR!!\n\nError writing file to external storage"}return"SUCCESS!!\n\nFile $fileName with content $fileContent saved to $externalStorageDir"}}
packageorg.owasp.mastestapp;importandroid.content.Context;importandroid.util.Log;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importkotlin.Metadata;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(){FileexternalStorageDir=this.context.getExternalFilesDir(null);FilefileName=newFile(externalStorageDir,"secret.txt");try{FileOutputStreamfileOutputStream=newFileOutputStream(fileName);FileOutputStreamoutput=fileOutputStream;byte[]bytes="secr3tPa$$W0rd\n".getBytes(Charsets.UTF_8);Intrinsics.checkNotNullExpressionValue(bytes,"this as java.lang.String).getBytes(charset)");output.write(bytes);Log.d("WriteExternalStorage","File written to external storage successfully.");CloseableKt.closeFinally(fileOutputStream,null);return"SUCCESS!!\n\nFile "+fileName+" with content secr3tPa$$W0rd\n saved to "+externalStorageDir;}catch(IOExceptione){Log.e("WriteExternalStorage","Error writing file to external storage",e);return"ERROR!!\n\nError writing file to external storage";}}}
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 rule has identified one location in the code file where an API, getExternalFilesDir, is used to write to external storage with scoped storage restrictions.
After reviewing the decompiled code at the location 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 password.