OWASP Mobile Application Security Testing Guide: MASTG KNOW 0042

---
masvs_category: MASVS-STORAGE
platform: android
title: External Storage
---

Android devices support [shared external storage](https://developer.android.com/training/data-storage#filesExternal "Using External Storage"). This storage may be removable (such as an SD card) or emulated (non-removable). A malicious app with proper permissions running on Android 10 or below can access data that you write to "external" [app-specific-directories](https://developer.android.com/training/data-storage/app-specific). The user can also modify these files when USB mass storage is enabled.

The files stored in these directories are [removed when your app is uninstalled](https://developer.android.com/training/data-storage/app-specific#external).

External storage must be used carefully as there are many risks associated with it. For example an attacker may be able to retrieve sensitive data or [obtain arbitrary control of the application](https://blog.checkpoint.com/2018/08/12/man-in-the-disk-a-new-attack-surface-for-android-apps/ "Man in the disk").

**Android Security Guidelines**: Android recommends not storing sensitive data on external storage and to perform input validation on all data stored on external storage. See the [Android Security Guidelines](https://developer.android.com/privacy-and-security/security-tips#external-storage "Android Security Guidelines"). Android also provides a [guide](https://developer.android.com/privacy-and-security/security-best-practices#external-storage "Store data in external storage based on use case") on how to use external storage securely.

## Scoped Storage

To give users more control over their files and to limit file clutter, apps that target Android 10 (API level 29) and higher are given scoped access into external storage, or [scoped storage](https://developer.android.com/training/data-storage#scoped-storage), by default. When scoped storage is enabled, apps cannot access the app-specific directories that belong to other apps.

The Android developers documentation provides a detailed guide highlighting common [storage use cases and best practices](https://developer.android.com/training/data-storage/use-cases) differentiating between handling media and non-media files and considering scoped storage.

**Opting out**: Apps targeting Android 10 (API level 29) or lower can [temporarily opt out of scoped storage](https://developer.android.com/training/data-storage/use-cases#opt-out-in-production-app) using `android:requestLegacyExternalStorage="true"` in their app manifest. Once the app targets Android 11 (API level 30), the system ignores the `requestLegacyExternalStorage` attribute when running on Android 11 devices.

> [App attribution for media files (Android Developers)](https://developer.android.com/training/data-storage/shared/media#app-attribution):
> When [scoped storage](https://developer.android.com/training/data-storage#scoped-storage) is enabled for an app that targets Android 10 or higher, the system attributes an app to each media file, which determines the files that your app can access when it hasn't requested any storage permissions. Each file can be attributed to only one app. Therefore, if your app creates a media file that's stored in the photos, videos, or audio files media collection, your app has access to the file.
>
> If the user uninstalls and reinstalls your app, however, you must request [READ_EXTERNAL_STORAGE](https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE) to access the files that your app originally created. This permission request is required because the system considers the file to be attributed to the previously installed version of the app, rather than the newly installed one.

For example, trying to access a file stored using the `MediaStore` API with a `content://` URI like `content://media/external_primary` would only work as long as the image _belongs_ to the invoking app (due to `owner_package_name` attribute in the `MediaStore`). If the app calls a `content://` URI that does not belong to the app, it will fail with a `SecurityException`:

```sh
Cannot open content uri: content://media/external_primary/images/media/[PII_REDACTED]
java.lang.SecurityException: org.owasp.mastestapp has no access to content://media/external_primary/images/media/[PII_REDACTED]
```

You can validate this by querying the MediaStore via @MASTG-TOOL-0004, for example:

- `adb shell content query --uri content://media/external_primary/images/media`
- `adb shell content query --uri content://media/external_primary/file`

To be able to access the content, the app must have the necessary permissions e.g., `READ_EXTERNAL_STORAGE` before Android 10 API level 29, `READ_MEDIA_IMAGES` or `MANAGE_EXTERNAL_STORAGE` from Android 10 API level 29 onwards.

> `READ_EXTERNAL_STORAGE` is deprecated (and is not granted) when targeting Android 13 (API level 33) and above. If you need to query or interact with MediaStore or media files on the shared storage, you should instead use one or more new storage permissions: `READ_MEDIA_IMAGES`, `READ_MEDIA_VIDEO` or `READ_MEDIA_AUDIO`.
>
> Scoped storage is enforced starting on Android 10 (API level 29) (or Android 11 if using `requestLegacyExternalStorage`). In particular, `WRITE_EXTERNAL_STORAGE` will no longer provide write access to all files; it will provide the equivalent of `READ_EXTERNAL_STORAGE` instead.
>
> As of Android 13 (API level 33), if you need to query or interact with MediaStore or media files on the shared storage, you should be using instead one or more new storage permissions: `READ_MEDIA_IMAGES`, `READ_MEDIA_VIDEO` or `READ_MEDIA_AUDIO`.

After declaring the permission in the manifest you can grant it with @MASTG-TOOL-0004:

```sh
adb shell pm grant org.owasp.mastestapp android.permission.READ_MEDIA_IMAGES
```

You can revoke the permission with:

```sh
adb shell pm revoke org.owasp.mastestapp android.permission.READ_MEDIA_IMAGES
```

## External Storage APIs

There are APIs such as [`getExternalStoragePublicDirectory`](https://developer.android.com/reference/kotlin/android/os/Environment#getExternalStoragePublicDirectory(kotlin.String)) that return paths to a shared location that other apps can access. An app may obtain a path to an "external" location and write sensitive data to it. This location is considered "Shared Storage Requiring No User Interaction", which means that a third-party app with proper permissions can read this sensitive data.

For example, the following Kotlin snippet stores sensitive information in clear text to a file `password.txt` residing on external storage.

```kotlin
val [CREDENTIAL_REDACTED]"
val path = context.getExternalFilesDir(null)
val file = File(path, "password.txt")
file.appendText(password)
```

## MediaStore API

The [`MediaStore` API](https://developer.android.com/training/data-storage/shared/media) provides a way for apps to interact with two types of files stored on the device:

- media files inclu