
Content Providers and the potential weak spots they can have | Oversecured Blog
Oversecured's Android security checklist for Content Providers covers insecure FileProvider path configs, path traversal via decoded Uri.getLastPathSegment(), mismatched readPermission/writePermission, proxying requests to more privileged providers, SQL injection across a shared database, and sensitive actions in providers. Each case has vulnerable manifest and Java code, an attacker PoC and remediation. Real cases from Google and Samsung devices are cited. The page text was truncated near the end.
What it is
Oversecured's Android checklist for ContentProvider flaws. It gives six patterns, each with vulnerable manifest and Java code, an attacker PoC and a fix. The page says the flaws apply to exported providers and to providers with android:grantUriPermissions="true". The page text was truncated near the end.
How it works
Over-broad FileProvider. FileProviders are never exported but always set grantUriPermissions="true". The XML paths file can declare root-path (/), files-path, cache-path or external-path (the whole SD card). A broad entry becomes the last link in a chain: intent redirection, then a grant on an arbitrary provider, then reads or writes of any file under the broad path. The page cites a Samsung case that gave read/write access to arbitrary files with system privileges.
Decoded URI segments. Uri.getLastPathSegment() and Uri.getPathSegments() return decoded values. A provider that does new File(getFilesDir(), uri.getLastPathSegment()) can be hit with this URI:
Uri.parse("content://com.victim.path_traversal/..%2Fshared_prefs%2Fsecrets.xml");The page cites a Google case that led to arbitrary code execution (read+write on arbitrary files) and a Samsung case with read-only system-level file access.
Split read/write permissions. readPermission guards query(). writePermission guards insert(), update(), delete() and bulkInsert(). call() needs either one. If only readPermission is set, writes need no permission. File-open methods are checked against the requested mode. A provider whose openFile() ignores mode and always opens read-only can be called with mode "w". That passes the unprotected write check and returns a readable descriptor for any path, such as content://com.victim.protected/data/user/0/com.victim/shared_prefs/secrets.xml.
Proxying to a more privileged provider. The page shows a provider guarded by a normal permission whose query() forwards to ContactsContract.CommonDataKinds.Phone.CONTENT_URI, which is dangerous. An attacker takes the normal permission and reads contacts through the app. The worst variant builds the target from uri.getQueryParameter("uri"), which exposes every provider the app can reach, including system providers. Oversecured also flags proxying from a non-exported provider with grantUriPermissions="true" to one without it.
Shared database. A signature-protected provider and an unprotected one use the same data.db. A selection injected through the unprotected provider leaks the protected table:
String whereSqli = "1=2 UNION SELECT * FROM Sensitive -- ";
getContentResolver().query(Uri.parse("content://com.victim.insensitive/"), null, whereSqli, null, null);Sensitive actions in providers. A non-exported provider had a debug path that copied internal.db to a download location. It passed review because it was not exported. The app also had dozens of places that called ContentResolver.query() on externally supplied URIs. An attacker passed content://com.victim.internal/debug and triggered it. Oversecured says this was found in a very popular app.
What to do
- FileProvider: use one provider per purpose and expose only a specific subfolder, such as
/data/user/0/com.victim/cache/my_image_cache/, not all ofcache/. - Path traversal: validate the canonical path of the resulting file, or re-encode with
Uri.encode(Uri.getLastPathSegment()). - Permissions: check the access mode in file-open methods. If unsure whether to require read or write, set
android:permissioninstead of only one of the two. - Proxying: do not forward requests to other providers.
- Database: give each provider its own database file, and do not let providers of different security levels talk to each other based on a passed URI.
- Sensitive logic: keep providers as proxies to internal files or database data. Do not put debug, encryption or file-moving logic in them beyond
insert(),delete()and similar.
Caveats
The page links to a separate article on reaching arbitrary providers, which it does not reproduce. The Google and Samsung cases are named without CVE IDs or dates here. The page ends with a vendor pitch for Oversecured's scanner.
Organisations named here
- FileProvider misconfiguration
- grantUriPermissions
- readPermission
- writePermission
Technologies named here
- Oversecured
- Android
- SQLite
- Java
- Android Content Providers (ContentProvider component)
- Android FileProvider
- AndroidManifest.xml provider attributes (android:exported, android:permission, android:readPermission, android:writePermission, android:grantUriPermissions)
- Android system providers (contacts, SMS, device settings)
- A very popular unnamed Android application (sensitive debug action in a non-exported provider, found by Oversecured)
- ContentResolver
- FileProvider
- Samsung devices (FileProvider issue giving read/write access to arbitrary files with system privileges; path traversal issue giving read-only access to arbitrary files with system privileges)
- SQLiteOpenHelper / SQLite
- UriMatcher
Techniques named here
- Path traversal
- SQL injection
- Intent Redirection
- Bypass of readPermission via file mode mismatch
- Path traversal via decoded Uri segments
- Proxying requests to more secure providers (confused deputy)
- Sensitive actions exposed in a content provider
- SQL injection in a content provider
Related in Mobile Security
thomasbuilds/Spectre
