Submit #886201: Reader Tools All PDF Reader (com.pdf.viewer.pdftool.reader.document) Version 98.8 (versionCode 988) Path Traversalinfo

TitleReader Tools All PDF Reader (com.pdf.viewer.pdftool.reader.document) Version 98.8 (versionCode 988) Path Traversal
DescriptionAll PDF Reader for Android (package com.pdf.viewer.pdftool.reader.document, version 98.8 / versionCode 988, minSdkVersion 24, targetSdkVersion 35) is affected by path traversal (CWE-22) through an attacker-delivered content URI, an instance of the Android "Dirty Stream" pattern. AFFECTED COMPONENT The exported entry activity com.pdf.viewer.pdftool.reader.document.ui.activity.splash.ActSplashNew declares intent filters for ACTION_SEND, ACTION_SEND_MULTIPLE, ACTION_VIEW and ACTION_EDIT over a broad MIME set including application/pdf and application/octet-stream. Any installed application can send it a content:// URI. ROOT CAUSE When the activity receives a content URI it copies the referenced stream to internal storage using the URI's _display_name column verbatim as the on-disk filename. The filename is joined to a fixed base directory with no path canonicalization and no separator handling, so a _display_name containing "../" escapes the intended directory. SOURCE TO SINK (verified at the bytecode level with androguard 4.1.4) 1. ActSplashNew.handleDeeplink() reads the URI from EXTRA_STREAM (SEND), ClipData / EXTRA_STREAM list item 0 (SEND_MULTIPLE), or getData() (VIEW), then calls DocumentViewModel.validateFileUri, which calls com.ezteam.baseproject.utils.fileUtils.GetRealPath.getPathFiles. 2. getPathFiles falls through to writeStreamToLocal when PathUtils.getPath returns null. A malicious provider returning a null cursor for the _data projection forces getPath to null. The sink is also reached directly when the storage-permission check is false. 3. writeStreamToLocal builds the destination and opens an output stream: File out = new File(getFilesDir() + "/temp/" + File.separator + getFileName(uri)); FileOutputStream fos = new FileOutputStream(out); // no append, an existing target is truncated It then copies the content stream into fos. 4. getFileName returns the raw _display_name value. The basename-normalization branch runs only when _display_name is null and is skipped when _display_name is present, so path separators survive. There is no canonicalization, no containment check, no allowlist, and no separator rejection. IMPACT (confirmed on a physical device) Private-directory write, no permissions required: a _display_name of "../../databases/document_database" resolves to /data/data/<pkg>/databases/document_database and overwrites the application's database. Verified: file owner u0_a405, size 109 bytes equal to the payload length, containing the attacker marker. Shared-storage write: with MANAGE_EXTERNAL_STORAGE (declared by the application), a _display_name of "../../../../../../../../../storage/emulated/0/Download/DIRTYSTREAM_POC.txt" resolves to /storage/emulated/0/Download/DIRTYSTREAM_POC.txt and writes an attacker-controlled file to shared storage. Verified on device. In both cases the write executes as the target application's UID with attacker-controlled file contents. PROOF OF CONCEPT A malicious application provides a ContentProvider that returns the traversal string "../../../../../../../../../storage/emulated/0/Download/DIRTYSTREAM_POC.txt" for the _display_name query, a null cursor for the _data query, and the payload bytes from openFile, and an activity that sends ACTION_SEND with the provider URI in EXTRA_STREAM to the exported component. On-device confirmation for the shared-storage case: grep -rl <marker> -> /sdcard/Download/DIRTYSTREAM_POC.txt ls -la /sdcard/Download/DIRTYSTREAM_POC.txt -> 109 DIRTYSTREAM_POC.txt realpath (files/temp/ + 9x "../" + storage/emulated/0/Download/DIRTYSTREAM_POC.txt) -> /storage/emulated/0/Download/DIRTYSTREAM_POC.txt REMEDIATION Reduce _display_name to a bare filename unconditionally (new File(name).getName()) and reject any value containing a path separator. Enforce canonical containment of the destination under the temp base directory before writing. Prefer a random, content-independent filename for the copied stream. The vulnerable code resides in the shared com.ezteam.baseproject library
Source⚠️ https://docs.google.com/document/d/1g8q6UDV2EBm0UfEz2tc1eVBSxXqX5Zk8Ei30FuKAYa8/edit?usp=sharing
User
 Actuator (UID 67941)
Submission07/11/2026 07:01 (2 months ago)
Moderation09/02/2026 15:10 (2 months later)
StatusAccepted
VulDB entry398130 [Reader Tools PDF Reader App 98.8 on Android File ActSplashNew.handleDeeplink _display_name path traversal]
Points20

Do you want to use VulDB in your project?

Use the official API to access entries easily!