Skip to content

fix(ui): escape metric names, label values, and flag fuzzy output in React UI (CVE-2026-40179, CVE-2026-44903, CVE-2026-44990)#336

Merged
vporoshok merged 2 commits into
ppfrom
fix/react-ui-xss-cve-2026-40179-44903
May 16, 2026
Merged

fix(ui): escape metric names, label values, and flag fuzzy output in React UI (CVE-2026-40179, CVE-2026-44903, CVE-2026-44990)#336
vporoshok merged 2 commits into
ppfrom
fix/react-ui-xss-cve-2026-40179-44903

Conversation

@vporoshok

@vporoshok vporoshok commented May 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

Backports three Prometheus React-UI XSS fixes to our fork, plus a defense-in-depth workaround for an unpatched sanitize-html bypass:

With Prometheus 3.x UTF-8 metric/label names, characters like <, >, \" are valid in metric and label values. An attacker who can inject metrics (compromised scrape target, remote-write, or OTLP receiver) can land stored XSS in any UI user's browser. From the XSS context, depending on enabled flags, the attacker can read /api/v1/status/config, hit /-/quit or /api/v1/admin/tsdb/delete_series, or exfiltrate metric data.

Prompp ships only the React UI (no Mantine UI), and we do not gate it behind --enable-feature=old-ui, so the React UI is always served and these vulnerabilities are reachable here.

Dependabot alerts that the same advisories map to in this repo: #177, #178, #187, #188, #192. The first four are pinned to `pp/tools/block_converter/go.mod` and `documentation/examples/remote_storage/go.mod` and don't actually use the vulnerable UI code paths — those alerts will need to be dismissed as `not used` after this PR ships the real fix. The sanitize-html alert (#192) is on the live npm tree but the only sink is now defanged by escaping upstream of the sanitizer.

Changes (each is a direct backport or a defense-in-depth tweak)

  • `web/ui/react-app/src/pages/graph/GraphHelpers.ts` — `escapeHTML` for `name` and label keys in chart tooltips.
  • `web/ui/react-app/src/pages/graph/MetricsExplorer.tsx` — `escapeHTML: true` on the `Fuzzy` instance feeding `dangerouslySetInnerHTML`.
  • `web/ui/react-app/src/vendor/flot/jquery.flot.heatmap.js` — import `escapeHTML`, apply to `le` label in the bucket tooltip.
  • `web/ui/react-app/src/pages/graph/Graph.tsx` — import `escapeHTML`, apply to `le` label in the y-axis `tickFormatter`.
  • `web/ui/react-app/src/pages/flags/Flags.tsx` — `escapeHTML: true` on the `Fuzzy` instance so the rendered string is entity-encoded before reaching `sanitize-html`, sidestepping the `xmp` bypass.
  • `CHANGELOG.md` — entry under `v0.8.0` → `Fixes`.

The pre-existing `escapeHTML()` helper in `web/ui/react-app/src/utils/index.ts` escapes `& < > " ' /`.

Test plan

  • `npx tsc --noEmit -p web/ui/react-app/tsconfig.json` — only pre-existing errors in `setupTests.ts` (verified identical on `origin/pp` without this patch).
  • `CI='' npm run build --workspace=react-app` in devcontainer — Compiled successfully (~523 kB gzip JS bundle), both before and after the Flags.tsx tweak.
  • Jest UI tests are blocked on a pre-existing infra issue in the devcontainer (`TextDecoder is not defined` from `undici` under Node 20), unrelated to these changes; the existing `GraphHelpers`/`MetricsExplorer` snapshots assert ASCII-only label values which our patched code path preserves byte-for-byte.

vporoshok and others added 2 commits May 15, 2026 16:51
…0179, CVE-2026-44903)

Backports upstream prometheus/prometheus#18506 (GHSA-vffh-x6r8-xx99 /
CVE-2026-40179) and prometheus/prometheus#18588 (GHSA-fw8g-cg8f-9j28 /
CVE-2026-44903) for the React web UI we still ship.

Affected sinks now call escapeHTML before interpolation into innerHTML:
- Graph tooltips: __name__ and label keys (GraphHelpers.ts)
- Metrics Explorer fuzzy search: escapeHTML option on Fuzzy
- Heatmap bucket tooltip: le label (jquery.flot.heatmap.js)
- Heatmap y-axis tick labels: le label (Graph.tsx)

This blocks stored XSS in the Prometheus UI from metric names/label
values ingested via scrape, remote-write or OTLP receivers when
UTF-8 metric/label names allow <, > and " characters.

Co-authored-by: Cursor <[email protected]>
…-44990)

Defense-in-depth for GHSA-rpr9-rxv7-x643 (sanitize-html xmp raw-text
passthrough), for which no upstream patch is released yet.

The Flags page renders fuzzy-search results through sanitize-html
with allowedTags=['strong']. Under the default config sanitize-html
preserves the content of disallowed <xmp> tags verbatim, so a flag
value containing <xmp>...</xmp> would survive sanitization.

Set escapeHTML: true on the Fuzzy instance (same pattern we just used
in MetricsExplorer for CVE-2026-40179) so the search output is fully
entity-encoded except for the <strong> match markers. sanitize-html
then sees only the strong tags plus harmless entity-encoded text and
the xmp bypass is unreachable.

Co-authored-by: Cursor <[email protected]>
@vporoshok vporoshok changed the title fix(ui): escape metric names and label values in React UI (CVE-2026-40179, CVE-2026-44903) fix(ui): escape metric names, label values, and flag fuzzy output in React UI (CVE-2026-40179, CVE-2026-44903, CVE-2026-44990) May 15, 2026
@vporoshok vporoshok self-assigned this May 16, 2026
@vporoshok
vporoshok merged commit d959139 into pp May 16, 2026
30 checks passed
@vporoshok
vporoshok deleted the fix/react-ui-xss-cve-2026-40179-44903 branch May 16, 2026 06:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant