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-40179-PoC — Minimal Python PoC for CVE-2026-40179: injects a malicious metric name via unauthenticated Prometheus remote_write to trigger stored XSS in the web UI. No protobuf stubs required. | Kitploit
Tools/GitHubGitHub/bsdrip/cve-2026-40179-poc
Vulnerability AnalysisExploitationWeb Application ExploitationAPI Security
GitHubbsdrip/cve-2026-40179-poc

CVE-2026-40179-PoC

Minimal Python PoC for CVE-2026-40179: injects a malicious metric name via unauthenticated Prometheus remote_write to trigger stored XSS in the web UI. No protobuf stubs required.

View Repository
1 day 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-40179 — Prometheus stored XSS via remote_write

A minimal, dependency-light proof of concept for CVE-2026-40179 (GHSA-vffh-x6r8-xx99): stored cross-site scripting in the Prometheus web UI, delivered through an unauthenticated remote_write endpoint.

The vulnerability

Prometheus 3.x renders metric names and label values into the web UI via innerHTML without escaping. Because Prometheus v3 relaxed label validation to allow arbitrary UTF-8 — including <, >, and " — a metric name can carry an HTML payload that executes when someone browses the UI.

AffectedPrometheus 3.0.0 – 3.5.1
Fixed in3.5.2
ImpactStored XSS, executes in the browser of any user viewing the affected metric
Vulnerable surfacesGraph page tooltips, Metrics Explorer

The XSS itself needs a way to get a crafted series into the TSDB. Any of these will do:

  • an open remote_write endpoint (what this PoC uses),
  • a compromised or attacker-controlled scrape target,
  • an OTLP receiver.

An internet- or LAN-exposed Prometheus with no authentication in front of it gives all of the above for free, which is what makes this practically exploitable rather than theoretical.

What this script does

Sends a single POST /api/v1/write containing one time series whose __name__ is:

root@kitploit:~
pentest_poc_cve_2026_40179

The protobuf WriteRequest is hand-encoded in ~40 lines, so there is no protobuf, prometheus_pb2, or promtool dependency — just python-snappy for the wire compression and requests for the POST. That makes it easy to drop onto a jump host where you can't build generated protobuf stubs.

Requirements

root@kitploit:~
python3 -m pip install python-snappy requests

python-snappy needs the Snappy C library:

root@kitploit:~
# Debian/Ubuntu
sudo apt install libsnappy-dev
# macOS
brew install snappy

Usage

root@kitploit:~
python3 cve-2026-40179-poc.py <target_ip>

The script assumes HTTPS on port 9090 with certificate verification disabled (typical for an internal instance with a self-signed cert). If your target is plain HTTP or on another port, edit the url line in main().

A successful injection returns HTTP 204:

root@kitploit:~
POST https://192.0.2.10:9090/api/v1/write -> 204

Confirming the write landed

Query the series in the Prometheus UI or API — it should return immediately:

root@kitploit:~
{__name__=~"pentest_poc.*"}

The Table view escapes it correctly and shows the payload as plain text. That is expected and is not the vulnerable surface.

Triggering the payload

Open the Metrics Explorer (the metric browser next to the query box), search for pentest_poc, and hover the listed entry.

In field testing against 3.2.1, the Metrics Explorer path fired reliably while the Graph tab tooltip did not reproduce — the injected sample (value 1.0) was not visibly rendered on the plotted chart, and hovering the legend did not trigger it either. Both surfaces are named in the advisory; if one doesn't fire on your target version, try the other before concluding it isn't vulnerable.

The default payload uses console.log() so it doesn't interrupt anyone who isn't looking for it. For a visible demo — a screenshot for a report, for example — change METRIC_NAME to use alert():

root@kitploit:~
METRIC_NAME = ('pentest_poc_cve_2026_40179'
               '')

Cleanup — read before you run this

The injected series is persistent. Once written, it stays in the TSDB until retention expires it. Removing it requires the admin API, which is disabled by default:

root@kitploit:~
# Only works if Prometheus was started with --web.enable-admin-api
curl -X POST -g 'https://<target>:9090/api/v1/admin/tsdb/delete_series?match[]={__name__=~"pentest_poc.*"}'
curl -X POST 'https://<target>:9090/api/v1/admin/tsdb/clean_tombstones'

If the admin API is off, there is no remote cleanup path. The only alternative is promtool tsdb run locally on the host, which you probably don't have access to.

Practical consequences:

  • Confirm cleanup is possible before injecting into anything you care about, or accept that the artifact persists.
  • The metric name is deliberately long, unmistakable, and self-labelling (job="pentest_poc") so it is easy to find and obviously a test artifact.
  • On an authorized engagement, tell the client about any residual series directly, so it isn't later mistaken for a real compromise.

Testing safely

To reproduce against a disposable instance rather than anything live:

root@kitploit:~
docker run --rm -p 9090:9090 prom/prometheus:v3.2.1 \
  --config.file=/etc/prometheus/prometheus.yml \
  --web.enable-remote-write-receiver \
  --web.enable-admin-api

Then point the script at 127.0.0.1 (change the URL scheme to http:// in main()). Starting with --web.enable-admin-api means you can actually delete the series afterwards.

Remediation

  1. Upgrade to Prometheus 3.5.2 or later. This is the fix.
  2. Put authentication and TLS in front of the Prometheus UI and API — a reverse proxy with auth, or --web.config.file with basic_auth_users.
  3. Don't enable --web.enable-remote-write-receiver unless you need it, and never expose it unauthenticated.
  4. Restrict network access to port 9090 to the hosts that legitimately need it.

Note that (1) alone fixes the XSS, but an unauthenticated Prometheus remains a substantial information-disclosure surface on its own: the full metric name list, scrape target inventory, and internal hostnames are all readable without credentials.

Authorized use only

This is published for defenders, researchers, and testers working under authorization. The vulnerability is publicly disclosed and patched upstream.

Running this against a system writes persistent data to it. Do not point it at infrastructure you do not own or have explicit written permission to test.

License

MIT — see LICENSE.

Download Tool