Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
Maven
Not in CISA KEV
MEDIUM severity

GHSA-gx93-m64w-5m6h

MEDIUM

GHSA-gx93-m64w-5m6h is a medium-severity (CVSS 6.1) Cross-site Scripting (XSS) vulnerability in io.qameta.allure:allure-generator. O3 Security confirms whether GHSA-gx93-m64w-5m6h is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.

Allure Report: Stored XSS via unescaped ANSI helper in status message/trace rendering

Also known asCVE-2026-55847
Published
Jun 19, 2026
Updated
Jun 19, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Jun 19, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

No confirmed exploitation observed yet

  • CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.

Exploitation and automatability from CISA’s SSVC triage for GHSA-gx93-m64w-5m6h.

Real-World Exposure

1 pkg affected
io.qameta.allure:allure-generator

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Maven packages — download data is not available via public APIs for these ecosystems.

Description

Summary

The ansi.js Handlebars helper in allure-generator passes user-controlled statusMessage and statusTrace values from test result files through the ansi-to-html library and wraps the output in Handlebars SafeString without HTML escaping. Since ansi-to-html does not escape HTML entities by default, an attacker who can influence test result content (e.g., via crafted JUnit XML failure messages) can inject arbitrary JavaScript that executes when anyone views the generated Allure report.

Details

The vulnerability is an incomplete fix — commit 4c64b19 (PR #3271) fixed XSS in linky.js and text-with-links.js by adding escapeExpression(), but the same pattern in ansi.js was not addressed.

Vulnerable sinkallure-generator/src/main/javascript/helpers/ansi.js:10-11:

export default function (input) {
    return new SafeString(ansiConverter.toHtml(input));
};

The AnsiToHtml constructor at line 4 does not set escapeForHtml: true:

const ansiConverter = new AnsiToHtml({
    fg: "black",
    bg: "black",
    newline: true,
});

The ansi-to-html library (v0.7.2) defaults escapeForHtml to false, meaning HTML entities in the input pass through unchanged. Wrapping the result in SafeString tells Handlebars to skip its auto-escaping, so the raw HTML reaches the browser.

Template usageallure-generator/src/main/javascript/blocks/status-details/status-details.hbs:7,10:

<pre class="status-details__message"><code>{{ansi statusMessage}}</code></pre>
...
<pre class="{{b 'status-details' 'trace'}}"><code>{{ansi statusTrace}}</code></pre>

Sourceplugins/junit-xml-plugin/src/main/java/io/qameta/allure/junitxml/JunitXmlPlugin.java:307-308:

result.setStatusMessage(element.getAttribute(MESSAGE_ATTRIBUTE_NAME));
result.setStatusTrace(element.getValue());

These values are read directly from XML attributes with no sanitization. The same pattern exists in TRX, xUnit XML, xctest, and Allure1/2 plugins.

Contrast with the fixed helperlinky.js (post-fix) correctly escapes before wrapping in SafeString:

const safeText = escapeExpression(text);
return new SafeString(`<a href="${safeText}" ...>${safeText}</a>`);

PoC

  1. Create a malicious JUnit XML test result file:
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="XSSTest" tests="1" failures="1">
  <testcase name="xssPayload" classname="com.example.Test">
    <failure message="&lt;img src=x onerror=alert(document.cookie)&gt;">
      Stack trace: &lt;img src=x onerror=alert('statusTrace_XSS')&gt;
    </failure>
  </testcase>
</testsuite>
  1. Generate an Allure report:
allure generate /path/to/results-with-malicious-xml -o /tmp/allure-report
  1. Open the report and navigate to the failed test case:
allure open /tmp/allure-report
  1. When viewing the test's status details, the <img onerror> payloads execute JavaScript in the viewer's browser.

Impact

  • Arbitrary JavaScript execution in the browser of anyone viewing the generated Allure report
  • Cookie theft, session hijacking if the report is served from a domain with active sessions (e.g., CI dashboards)
  • Data exfiltration — the injected script can read the full report content and send it to an attacker-controlled server
  • Attack vectors: A malicious dependency that throws crafted exception messages, a CI pipeline processing test results from untrusted pull requests, or a contributor submitting test files containing XSS payloads
  • Allure reports are commonly hosted on CI/CD platforms (Jenkins, GitLab, GitHub Actions artifacts) where session cookies may be present

Recommended Fix

Configure AnsiToHtml with escapeForHtml: true to escape HTML entities while preserving ANSI-to-HTML conversion:

import AnsiToHtml from "ansi-to-html";
import {SafeString} from "handlebars/runtime";

const ansiConverter = new AnsiToHtml({
    fg: "black",
    bg: "black",
    newline: true,
    escapeForHtml: true,  // Escape HTML entities in non-ANSI input
});

export default function (input) {
    return new SafeString(ansiConverter.toHtml(input));
};

This is the correct approach because it preserves the ANSI escape sequence → HTML conversion (colored output) while ensuring that any non-ANSI HTML in the input is safely escaped. The alternative of using escapeExpression() on the input would destroy ANSI sequences before they could be converted.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
Mavenio.qameta.allure:allure-generatorall versions2.39.0

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for io.qameta.allure:allure-generator. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.

  2. Fix

    Update io.qameta.allure:allure-generator to 2.39.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-gx93-m64w-5m6h is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 pinpoints whether GHSA-gx93-m64w-5m6h is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.

Tailored to GHSA-gx93-m64w-5m6h. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

## Summary The `ansi.js` Handlebars helper in allure-generator passes user-controlled `statusMessage` and `statusTrace` values from test result files through the `ansi-to-html` library and wraps the output in Handlebars `SafeString` without HTML escaping. Since `ansi-to-html` does not escape HTML entities by default, an attacker who can influence test result content (e.g., via crafted JUnit XML failure messages) can inject arbitrary JavaScript that executes when anyone views the generated Allure report. ## Details The vulnerability is an incomplete fix — commit `4c64b19` (PR #3271) fixed XS
O3 Security · Impact-Aware SCA

Is GHSA-gx93-m64w-5m6h in your dependencies?

O3 detects GHSA-gx93-m64w-5m6h across Maven dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.

GHSA-gx93-m64w-5m6h: allure (Medium 6.1) | O3 Security