Lucene search
K

📄 Bloomberg Memray Cross Site Scripting

🗓️ 02 Apr 2026 00:00:00Reported by Mohamed AbdelaalType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 96 Views

Bloomberg Memray stored XSS CVE-2026-32722 via unescaped command-line metadata in HTML reports.

Related
Code
# CVE-2026-32722
    
    Bloomberg Memray’s Stored XSS via Unescaped Command-Line Metadata
    
    ## Intro
    
    I found this issue while reviewing **Memray**, Bloomberg’s Python memory profiler, with a simple question in mind:
    
    **Can attacker-controlled runtime metadata cross into browser-rendered report output unsafely?**
    
    In this case, the answer was yes.
    
    The bug was in Memray’s HTML report generation path, where command-line metadata was rendered into a browser-opened report without escaping. That turned an operational field into an executable HTML sink and ultimately became **CVE-2026-32722**.
    
    **Project:** [Memray on GitHub](https://github.com/bloomberg/memray)  
    **Advisory:** [GHSA-r5pr-887v-m2w9 /CVE-2026-32722](https://github.com/bloomberg/memray/security/advisories/GHSA-r5pr-887v-m2w9)
    
    <img width="840" height="760" alt="photo0" src="https://github.com/user-attachments/assets/2c043ef1-8ea7-4991-b577-6e857487d7e0" />
    
    ---
    
    ## Attack Chain
    
    `attacker-controlled argv → metadata.command_line → HTML template sink without escaping → raw markup in generated report → browser-side JavaScript execution`
    
    ---
    
    ## What Memray Does
    
    **Memray** is a Python memory profiler.
    
    It instruments a Python process, records allocation behavior, and produces reports that help developers understand:
    - where memory is allocated
    - which call paths are responsible
    - what peak memory usage looks like
    - how memory changes over time
    
    Some of those reports are emitted as **HTML** and opened in a browser.
    
    That makes report generation a real security boundary.
    
    The relevant question is not whether Memray is a “local tool.”  
    The relevant question is whether **attacker-controlled data can cross into browser-rendered output unsafely**.
    
    In this case, it could.
    
    ---
    
    ## Why This Bug Was Worth Looking At
    
    A lot of people underestimate developer tooling.
    
    That is a mistake.
    
    Once a tool:
    - records runtime metadata,
    - stores attacker-influenced values,
    - and later renders them into HTML,
    
    it inherits the same output-encoding risks as a web application.
    
    That was the core issue here.
    
    This bug was not in profiling logic.
    It was not in allocation tracking.
    It was not in native memory handling.
    
    It was a classic **trust-boundary failure**:
    - untrusted metadata entered the system,
    - crossed into an HTML sink,
    - and was rendered without escaping.
    
    That is enough to create a real vulnerability.
    
    ---
    
    ## The Boundary I Focused On
    
    I did not approach Memray by fuzzing random CLI options or chasing crashes.
    
    The stronger approach was to identify the highest-probability security surface first.
    
    For Memray, that was **HTML report generation**.
    
    Why?
    
    Because HTML output introduces a browser sink, and browser sinks turn ordinary metadata bugs into security issues if:
    - the input is attacker-influenced,
    - the output is unescaped,
    - and the browser interprets the result as markup instead of text.
    
    That is exactly what happened here.
    
    ---
    
    ## Root Cause
    
    The bug reduces to two lines.
    
    In:
    
    ```python title="src/memray/reporters/templates/__init__.py"
    def get_render_environment() -> jinja2.Environment:
        loader = jinja2.PackageLoader("memray.reporters")
        env = jinja2.Environment(loader=loader)
    ```
    the Jinja environment is created without autoescape.
    
    Then in:
    ```html
    Command line: <code>{{ metadata.command_line }}</code><br>
    ```
    `metadata.command_line` is rendered directly into HTML.
    
    That is the whole vulnerability.
    
    ### Why this is exploitable
    
    Because `metadata.command_line` is attacker-influenced.
    
    Memray records the command line used to run the profiled program.
    That means user-controlled values from `argv` are preserved as metadata and later inserted into the report.
    
    So the exploit chain is straightforward:
    
    - attacker controls command-line content
    - Memray stores it in `metadata.command_line`
    - the template emits it into HTML
    - the environment does not autoescape it
    - the browser parses it as live markup
    
    That turns metadata into executable browser content.
    
    ---
    
    ## What Makes This a Security Issue, Not Just Bad Rendering
    
    The important distinction is execution.
    
    Plenty of bugs produce malformed HTML.
    That alone is not enough.
    
    Here, attacker-controlled content was not merely visible in the page source.
    It was interpreted by the browser as active HTML and executed as JavaScript.
    
    That is the difference between:
    
    - formatting corruption
    - and a real XSS sink
    
    So the question was not:
    
    > “Can HTML appear in the report?”
    
    The real question was:
    
    > “Can attacker-controlled HTML become executable when the report is opened?”
    
    The answer was yes.
    
    ---
    
    ## PoC
    
    My initial reproducer used an explicit script plus an attacker-controlled argument:
    ```bash
    cat > victim.py <<'PY'
    x = [b"A" * 1024 for _ in range(1000)]
    print("done")
    PY
    
    python -m memray run -o poc.bin victim.py '<img src=x onerror=alert(1)>'
    python -m memray flamegraph -o poc.html poc.bin
    ```
    The generated HTML contained raw attacker-controlled markup:
    ```html
    Command line: <code>~/memray/src/memray/__main__.py run -o poc.bin victim.py <img src=x onerror=alert(1)></code><br>
    ```
    Opening or refreshing the generated report triggered JavaScript execution.
    
    That established the core claim:
    - the value was unescaped,
    - the browser parsed it as markup,
    - and the sink was executable.
    
    Later, during coordinated disclosure, the maintainer simplified the reproducer further:
    ```bash
    python -m memray run -o poc.bin -c '# <img src=x onerror=alert(1)>'
    ```
    That version is better because it isolates the vulnerable boundary more directly:
    - no extra file
    - no extra application logic
    - just attacker-controlled command-line content entering the report pipeline
    
    ---
    
    ## Why the Payload Was Chosen
    
    The payload was intentionally simple:
    ```html
    <img src=x onerror=alert(1)>
    ```
    This is not about flashy payloads.
    
    It is a clean execution probe because:
    - it requires no external infrastructure
    - it is obvious in rendered HTML
    - it proves HTML interpretation immediately
    - it proves browser-side execution without relying on remote content
    
    For this class of bug, that is enough.
    
    ---
    
    ## Scope Validation
    
    One report type would already have been enough to justify the issue.
    
    But I wanted to know whether this was isolated or structural.
    
    I confirmed the same behavior in:
    - flamegraph reports
    - table reports
    - flamegraph reports generated with `--no-web`
    
    That mattered for two reasons.
    
    ### First
    
    It showed the vulnerable sink was reused across multiple HTML outputs.
    
    ### Second
    
    It proved the bug was not dependent on external CDN-hosted assets.
    
    `--no-web` still reproduced the issue, which means the problem was in Memray’s own generated HTML and template handling, not in remote JS behavior.
    That made the case much stronger.
    
    ---
    
    ## Why This Was Classified as Low Severity
    
    The maintainer’s main concern was practical attacker control.
    
    That is fair.
    
    This is not the kind of issue where an unauthenticated remote attacker hits an exposed HTTP endpoint and gets instant impact.
    
    The exploit condition is narrower:
    - attacker influences command-line input
    - a victim later opens the generated report in a browser
    
    So the realistic classification was low severity.
    
    That does not make it a weak bug.
    
    Severity is about exploit conditions and likely impact.
    Validity is about whether the issue is real.
    
    This issue was clearly real:
    - attacker-controlled source
    - HTML sink
    - missing escaping
    - actual JavaScript execution
    - deterministic fix
    
    That is why it still became a CVE.
    
    ---
    
    ## Fix Analysis
    
    The fix was minimal and correct.
    
    The maintainer changed:
    ```html
    {{ metadata.command_line }}
    ```
    to:
    ```html
    {{ metadata.command_line|e }}
    ```
    That is the right fix because it addresses the vulnerable sink directly.
    
    Instead of emitting raw markup like:
    ```html
    <img src=x onerror=alert(1)>
    ```
    the template now emits escaped text:
    ```html
    <img src=x onerror=alert(1)>
    ```
    That preserves the informational value of the command-line field while removing the browser execution path.
    
    The maintainer also reviewed the rest of the template context and concluded that:
    - several fields were numeric
    - some strings were fully controlled by Memray
    - script-bound values were rendered with `|tojson`
    So the issue was correctly narrowed to `metadata.command_line`.
    
    That is exactly the kind of fix review you want in a real disclosure.
    
    ---
    
    ## Disclosure
    
    This was reported privately through GitHub Security Advisories.
    
    The maintainers:
    - validated the issue
    - agreed it was their bug to fix
    - simplified the reproducer
    - patched the vulnerable sink
    - released the fix in 1.19.2
    - requested a CVE
    - published the advisory
    
    The issue was assigned:
    **CVE-2026-32722**
    
    ---
    
    ## What This Bug Actually Teaches
    
    The key lesson here is simple:
    
    > metadata is not automatically trusted just because it looks operational.
    
    - A command line feels harmless.
    - A report modal feels harmless.
    - A local HTML file feels harmless.
    
    None of that matters once attacker-controlled content crosses into browser-rendered output without escaping.
    
    The moment a tool emits HTML, it needs to be treated like an HTML-producing application.
    
    That is the real takeaway.
    
    ---
    
    ## Key Points
    
    - HTML report generators are security surfaces
    - developer tooling still needs output encoding discipline
    - local report artifacts can contain real XSS sinks
    - missing escaping in templates is enough when attacker-controlled metadata reaches the sink
    - low severity does not mean low quality
    - the right mindset here was trust boundary analysis, not blind fuzzing
    
    ---
    
    ## Final Words
    
    This vulnerability was not about a clever payload.
    
    It was about identifying the right boundary.
    
    Memray took attacker-influenced command-line metadata and rendered it into generated HTML without escaping it.
    The browser did the rest.
    
    That is why this became **CVE-2026-32722**.
    
    Fixed in **Memray 1.19.2**.
    
    <img width="840" height="560" alt="photo0" src="https://github.com/user-attachments/assets/a9751b5f-a614-4501-b257-56b00f0693d0" />

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

02 Apr 2026 00:00Current
5.4Medium risk
Vulners AI Score5.4
CVSS 3.13.6 - 6.1
EPSS0.00022
SSVC
96