CVE-2023-4434 — hamza417 · Inure App Manager

Improper validation of intent data in TextViewerActivity allows a malicious app to open arbitrary files from Inure's private storage.

TextViewerActivity in Inure App Manager (Build87) is an exported activity that opens text files passed to it via intent. It performs no validation on the incoming URI — accepting file:// paths that address the app’s own private /data/data/ directory. Any app on the device can trigger Inure to display its own internal files.

Background

Android’s app sandbox normally prevents one app from reading another’s private data directory at /data/data/<package>/. However, file:// URIs bypass the content provider layer entirely — they address the filesystem path directly. When an exported activity accepts file:// URIs without validating the path, it can be tricked into opening its own private files on behalf of a malicious caller. Unlike content:// URIs, a file:// URI doesn’t go through a provider with access controls; the app opens the file using its own filesystem permissions.

This is distinct from CVE-2023-4876, which achieves full programmatic exfiltration by writing files to external storage. Here, the file is displayed in Inure’s own UI — the attacker sees the contents on screen, but can’t receive them directly via intent return values.

Root Cause Analysis

TextViewerActivity is a thin wrapper that instantiates the Text fragment:

// TextViewerActivity.kt
class TextViewerActivity : BaseActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        if (savedInstanceState.isNull()) {
            supportFragmentManager.beginTransaction()
                .replace(R.id.app_container, Text.newInstance())
                .commit()
        }
    }
}

The actual file read happens in Text.kt:

// Text.kt — onViewCreated()
val string = requireActivity().contentResolver
    .openInputStream(requireActivity().intent.data!!)!!  // no scheme or path validation
    .use { inputStream ->
        inputStream.bufferedReader().use { it.readText() }
    }

requireActivity().intent.data is whatever was passed to TextViewerActivity. No scheme check, no path check, no restriction on what can be opened. A file:// URI like file:///data/data/app.simple.inure/shared_prefs/Preferences.xml is resolved using Inure’s own filesystem access — bypassing the Android sandbox because Inure is the one opening it.

TextViewerActivity is exported via an intent filter for VIEW on text/* MIME types, making it reachable from any installed application.

Proof of Concept

adb shell am start \
  -n app.simple.inure/.activities.association.TextViewerActivity \
  -d "file:///data/data/app.simple.inure/shared_prefs/Preferences.xml"

This launches TextViewerActivity and the Text fragment reads and renders Preferences.xml on screen — a file from inside Inure’s private /data/data/ directory, inaccessible to other apps under normal circumstances.

Constraint: In Build87, attempting to use the in-app Export function on the opened file causes a crash, which limits direct programmatic exfiltration. The file contents are visually exposed on screen rather than programmatically returned to the attacker. This limitation was not present in CVE-2023-4876, which achieved full exfiltration through a different path.

Impact

A malicious app can silently trigger Inure to display any file from its private directory. Sensitive data — preferences, database content, internal tokens — becomes readable on screen. While the crash on Export reduces direct exfiltration risk in this version, this class of bug serves as a reconnaissance primitive and can be escalated when combined with other vulnerabilities or social engineering.

Patch Analysis

Fix commit 2176af7. The correct fix is to validate intent.data before passing it to openInputStream() — rejecting file:// URIs entirely, or restricting accepted URIs to trusted schemes and paths outside the app’s private directory.

Timeline

DateEvent
2023-08-13Discovered and reported on huntr
2023-08-15Validated by maintainer
2023-08-20Scheduled public disclosure

References