Allure Report CVE-2026-55847
MEDIUMSeverity by source
AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Attacker needs no Allure system privileges (PR:N), only test file influence; victim must open report (UI:R); scope change applies as browser context is affected; no availability impact.
Primary rating from GitHub Advisory.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Lifecycle Timeline
2DescriptionGitHub Advisory
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 sink - allure-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 usage - allure-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>Source - plugins/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 helper - linky.js (post-fix) correctly escapes before wrapping in SafeString:
const safeText = escapeExpression(text);
return new SafeString(`<a href="${safeText}" ...>${safeText}</a>`);PoC
- 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="<img src=x onerror=alert(document.cookie)>">
Stack trace: <img src=x onerror=alert('statusTrace_XSS')>
</failure>
</testcase>
</testsuite>- Generate an Allure report:
allure generate /path/to/results-with-malicious-xml -o /tmp/allure-report- Open the report and navigate to the failed test case:
allure open /tmp/allure-report- 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.
AnalysisAI
Stored XSS in allure-generator (versions <= 2.38.1) allows arbitrary JavaScript execution in the browser of anyone who views a generated Allure report containing crafted test result data. The vulnerable ansi.js Handlebars helper passes unsanitized statusMessage and statusTrace values - sourced from JUnit XML failure messages and equivalent fields in TRX, xUnit XML, xctest, and Allure 1/2 plugins - through ansi-to-html without HTML escaping, then wraps the output in SafeString to bypass Handlebars' auto-escape protection. …
Unlock full vulnerability intelligence
- Risk assessment & exploitation conditions
- Attack chain visualization
- Remediation with exact patch versions
- Threat intelligence from 22 sources
- Personal watchlist & email alerts
Free forever · No credit card required
Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata
Vulnerability AssessmentAI
| Exploitation | The attacker must be able to influence the content of test result files consumed by Allure's report generator - specifically the `message` XML attribute of `<failure>` or `<error>` elements in JUnit XML (read by `JunitXmlPlugin.java` lines 307-308 without sanitization), or equivalent fields in TRX, xUnit XML, xctest, or Allure 1/2 result formats. … Additional conditions and limiting factors are described in the full assessment. |
| Risk Assessment | The CVSS 3.1 base score of 6.1 (Medium) is grounded in a vector of AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in. |
| Exploit Scenario | A threat actor submits a pull request to an open-source project with a JUnit XML test result file containing `<img src=x onerror=alert(document.cookie)>` embedded in the `message` attribute of a `<failure>` element. The project's CI pipeline runs `allure generate` on the results and publishes the report to a shared Jenkins or GitLab dashboard. … |
| Remediation | Upgrade `io.qameta.allure:allure-generator` to version 2.39.0, which resolves the vulnerability by initializing `AnsiToHtml` with `escapeForHtml: true` in `ansi.js`. … Detailed patch versions, workarounds, and compensating controls in full report. |
Threat intelligence, references, and detailed analysis are available after sign-in.
More from same product – last 7 days
Local denial of service in Android's PackageInstaller subsystem stems from a logic error in PackageInstallerSession.tran
Cedar policy injection in CedarJava (com.cedarpolicy:cedar-java) versions below 2.3.6, 3.4.1, and 4.9.0 allows attackers
Type confusion in CedarJava versions prior to 2.3.6, 3.4.1, and 4.9 allows authenticated remote attackers to manipulate
Remote code execution in Spinnaker's Orca and Rosco services allows authenticated users to achieve arbitrary Java class
Denial of service in Steeltoe.Discovery.Eureka client (.NET) versions prior to 4.2.0 and 3.4.0 allows a remote Eureka re
Share
External POC / Exploit Code
Leaving vuln.today
GHSA-gx93-m64w-5m6h