CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Dashboard
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-28338
6.8

PMD Static Analyzer Stored XSS in HTML Reports

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 28, 2026·5 min read·6 visits

PoC Available

Executive Summary (TL;DR)

PMD versions prior to 7.22.0 fail to properly escape source code metadata in HTML reports, leading to Stored XSS. Attackers can embed payloads in code being analyzed to execute JavaScript when the report is viewed.

A Stored Cross-Site Scripting (XSS) vulnerability exists in the HTML report generation components of PMD, a popular extensible multilanguage static code analyzer. The flaw allows attackers to inject malicious JavaScript into source code comments or string literals, which are subsequently rendered unescaped in PMD's HTML reports. This affects the 'vbhtml' and 'yahtml' renderers, as well as the suppression reporting in the standard 'html' renderer. Successful exploitation executes arbitrary code in the context of the user viewing the report, potentially compromising CI/CD dashboard sessions.

Vulnerability Overview

CVE-2026-28338 constitutes a Stored Cross-Site Scripting (XSS) flaw within PMD, specifically affecting its HTML reporting modules. PMD is designed to scan source code for programming flaws, often integrating into Continuous Integration (CI) pipelines to generate static analysis reports. The vulnerability manifests when PMD processes untrusted source code containing crafted payloads in string literals or suppression comments.

The affected components are the VBHTMLRenderer, YAHTMLRenderer, and the suppression reporting logic within the standard HTMLRenderer. These components are responsible for transforming analysis results—including rule descriptions, file names, and specific code snippets—into human-readable HTML tables. By failing to sanitize this input during the transformation process, PMD allows the injected content to break out of the intended HTML structure.

While the primary impact is on the developer or auditor viewing the report, the context of this exploitation is often critical infrastructure. If these reports are hosted on a build server (e.g., Jenkins, GitLab CI), an attacker could hijack the session of an authenticated user, potentially gaining access to the build environment or other sensitive projects visible to that user.

Root Cause Analysis

The root cause of this vulnerability is the direct concatenation of untrusted data into HTML output streams without context-aware encoding. PMD's architecture involves 'Rules' that identify violations and generating 'Report' objects. These objects contain metadata extracted directly from the source code, such as the content of a duplicate string literal (detected by AvoidDuplicateLiterals) or the text of a suppression comment (e.g., // NOPMD - false positive).

In the vulnerable versions, the renderers utilized StringBuilder or string concatenation to construct the HTML output. For instance, the VBHTMLRenderer would append rv.getDescription() directly into a table cell. While PMD does employ StringUtil.escapeJava() for some inputs, this utility effectively escapes Java-specific control characters (like newlines or quotes) but does not encode HTML entities (like < or >).

Consequently, a string literal such as "><script>... remains syntactically valid Java but becomes a malicious HTML tag when rendered. The application assumed that the internal representation of violation data was safe or purely informational, neglecting the fact that this data originates from potentially hostile source code.

Code Analysis

The remediation for CVE-2026-28338 was applied in commit c140c0e1de5853a08efb84c9f91dfeb015882442. The fix involves the systematic application of StringEscapeUtils.escapeHtml4() to all data points reflected in the DOM.

Vulnerable Code (VBHTMLRenderer.java): In the pre-patch version, the renderer directly appended the filename and description to the buffer. The filename and desc variables flow directly from the source code analysis.

// Vulnerable implementation
private void renderViolations(Iterator<RuleViolation> violations) throws IOException {
    // ...
    sb.append("<tr>");
    sb.append("<td class=\"filename\">" + filename + "</td>");
    sb.append("<td class=\"rule\">" + rv.getRule().getName() + "</td>");
    sb.append("<td class=\"desc\">" + desc + "</td>");
    // ...
}

Patched Code (VBHTMLRenderer.java): The patch introduces a helper method escape() which wraps the Apache Commons StringEscapeUtils. This ensures that characters like < are converted to &lt; before rendering.

// Patched implementation
private String escape(String s) {
    return StringEscapeUtils.escapeHtml4(s);
}
 
private void renderViolations(Iterator<RuleViolation> violations) throws IOException {
    // ...
    sb.append("<tr>");
    sb.append("<td class=\"filename\">" + escape(filename) + "</td>");
    sb.append("<td class=\"rule\">" + escape(rv.getRule().getName()) + "</td>");
    sb.append("<td class=\"desc\">" + escape(desc) + "</td>");
    // ...
}

Critique of the Fix: While the HTML entity encoding effectively neutralizes the XSS vector, the patch implementation for externalInfoUrl uses URLEncoder.encode(infoUrl, "UTF-8"). This is technically incorrect for full URLs, as it percent-encodes protocol separators (e.g., https:// becomes https%3A%2F%2F). This likely breaks the hyperlinks in the generated report, rendering the documentation links dysfunctional, although it does prevent attribute injection.

Exploitation Methodology

Exploiting this vulnerability requires the attacker to introduce a malicious payload into a file that will be scanned by PMD. This is a common scenario in open-source projects accepting Pull Requests or in enterprise environments where developers commit code to shared repositories.

Step 1: Payload Construction The attacker identifies a PMD rule that reflects code content. The AvoidDuplicateLiterals rule is an ideal candidate because it reports the exact string literal content in the violation message. The attacker creates a Java class with a crafted string:

public class Poc {
    // The payload closes the previous td, opens an img tag with an event handler
    String xss = "><img src=x onerror=alert(document.domain)>";
    String xss2 = "><img src=x onerror=alert(document.domain)>"; // Duplicate to trigger rule
}

Step 2: Execution The victim (e.g., a CI server or a lead developer) runs PMD against the codebase using a vulnerable renderer: pmd check -d . -R rulesets/java/quickstart.xml -f vbhtml -r report.html

Step 3: Trigger When the victim opens report.html, the browser parses the unescaped payload. The resulting HTML structure will look like: <td>The String literal "<img src=x onerror=alert(document.domain)>" appears 2 times</td>

The script executes immediately, granting the attacker access to the context in which the report is viewed.

Impact Assessment

The impact of CVE-2026-28338 is classified as Medium (CVSS 6.8), largely due to the requirement for user interaction (UI:R) and the complexity (AC:H) involved in the attack chain. However, in specific environments, the consequences can be severe.

Confidentiality (High): If the report is viewed on a centralized CI/CD dashboard (e.g., Jenkins artifact viewer), the XSS payload executes within the origin of that dashboard. This allows the attacker to steal session cookies, potentially compromising the build system or other repositories accessible to the victim.

Integrity (High): The attacker can modify the content of the report to hide genuine security issues or mislead the auditor. Furthermore, if the session is hijacked, the attacker could manipulate build configurations or inject backdoors into the software supply chain via the compromised user's account.

Availability (None): The vulnerability does not directly cause denial of service to the PMD application itself or the host system, although the report could be rendered unusable.

Official Patches

PMDPMD 7.22.0 Release Notes

Fix Analysis (1)

Technical Appendix

CVSS Score
6.8/ 10
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N

Affected Systems

PMD Static Code Analyzer < 7.22.0

Affected Versions Detail

Product
Affected Versions
Fixed Version
PMD
PMD
< 7.22.07.22.0
AttributeDetail
CVE IDCVE-2026-28338
CWE IDCWE-79
CVSS v3.16.8 (Medium)
Attack VectorNetwork
Attack ComplexityHigh
Privileges RequiredNone

MITRE ATT&CK Mapping

T1189Drive-by Compromise
Initial Access
T1185Browser Session Hijacking
Collection
CWE-79
Cross-site Scripting (XSS)

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Known Exploits & Detection

GitHub Security AdvisoryOriginal advisory containing Proof of Concept vectors.

Vulnerability Timeline

Vulnerability Disclosed
2026-02-27
Patch Released (7.22.0)
2026-02-27
GHSA Advisory Published
2026-02-27

References & Sources

  • [1]GHSA-8rr6-2qw5-pc7r
  • [2]NVD - CVE-2026-28338

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.