Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-32722 — Bloomberg Memray’s Stored XSS via Unescaped Command-Line Metadata | Kitploit
Tools/GitHubGitHub/0xmrma/cve-2026-32722
Static Code Analysis (SAST)Vulnerability AnalysisWeb Application ExploitationPenetration TestingPapers & ResearchLearning & Education
GitHub0xmrma/cve-2026-32722

CVE-2026-32722

Bloomberg Memray’s Stored XSS via Unescaped Command-Line Metadata

View Repository
175 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

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
Advisory: GHSA-r5pr-887v-m2w9 /CVE-2026-32722

photo0

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:

root@kitploit:~
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:

root@kitploit:~
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:

root@kitploit:~
cat > victim.py <<'PY'
x = [b"A" * 1024 for _ in range(1000)]
print("done")
PY

python -m memray run -o poc.bin victim.py ''
python -m memray flamegraph -o poc.html poc.bin

The generated HTML contained raw attacker-controlled markup:

root@kitploit:~
Command line: <code>~/memray/src/memray/__main__.py run -o poc.bin victim.py </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:

root@kitploit:~
python -m memray run -o poc.bin -c '# '

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:

root@kitploit:~

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:

root@kitploit:~
{{ metadata.command_line }}

to:

root@kitploit:~
{{ metadata.command_line|e }}

That is the right fix because it addresses the vulnerable sink directly.

Instead of emitting raw markup like:

root@kitploit:~

the template now emits escaped text:

root@kitploit:~
&lt;img src=x onerror=alert(1)&gt;

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.

photo0
Download Tool