PMD Designer has Stored XSS in VBHTMLRenderer and YAHTMLRenderer via unescaped violation messages
Description
PMD is an extensible multilanguage static code analyzer. Prior to version 7.22.0, PMD's vbhtml and yahtml report formats insert rule violation messages into HTML output without escaping. When PMD analyzes untrusted source code containing crafted string literals, the generated HTML report contains executable JavaScript that runs when opened in a browser. Practical impact is limited because vbhtml and yahtml are legacy formats rarely used in practice. The default html format is properly escaped and not affected. Version 7.22.0 contains a fix for the issue.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
PMD's legacy vbhtml and yahtml report formats are vulnerable to stored XSS because rule violation messages are not HTML-escaped, allowing execution of crafted JavaScript in generated reports.
PMD's vbhtml and yahtml report formats are affected by a stored cross-site scripting vulnerability. The root cause is that these renderers insert rule violation messages directly into the HTML output without any sanitization. When PMD analyzes untrusted source code containing crafted string literals (e.g., with <script> tags), the generated HTML report will contain executable JavaScript. This occurs because the violation message, derived from the source code, is not HTML-escaped before being written to the report [1][4].
To exploit this vulnerability, an attacker must submit untrusted source code to PMD and have the analysis results rendered in the vbhtml or yahtml format. When a user opens the generated HTML report in a browser, the embedded JavaScript executes. No special network position or authentication is required beyond the ability to trigger PMD analysis on the malicious source and access the resulting report. The default html format is properly escaped for rule violations, but it was found to have a similar issue with suppressed violation messages, which was also fixed [4].
Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of the user's browser. This could lead to session hijacking, data theft, or other client-side attacks, depending on the user's privileges and the sensitivity of the data within the report. The practical impact is somewhat limited because the vbhtml and yahtml formats are legacy and rarely used in practice [1][4].
PMD version 7.22.0 contains a fix for both issues. The fix introduces an escape() method that uses StringEscapeUtils.escapeHtml4() on violation descriptions and applies URLEncoder.encode() on external info URLs to prevent injection [2][3]. Users are strongly advised to upgrade to PMD 7.22.0 or later. If upgrading is not immediately possible, avoiding the use of vbhtml and yahtml report formats is a recommended workaround [1][4].
AI Insight generated on May 18, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
net.sourceforge.pmd:pmd-coreMaven | < 7.22.0 | 7.22.0 |
Affected products
2- pmd/pmdv5Range: < 7.22.0
Patches
1c140c0e1de58[core] Fix stored XSS in VBHTMLRenderer and YAHTMLRenderer (#6475)
9 files changed · +134 −50
docs/pages/release_notes.md+11 −0 modified@@ -24,6 +24,16 @@ This is a {{ site.pmd.release_type }} release. ### 🚀️ New and noteworthy +#### Security fixes +* This release fixes a stored XSS vulnerability in VBHTMLRenderer and YAHTMLRenderer via unescaped violation messages. + Affects CI/CD pipelines that run PMD with `--format vbhtml` or `--format yahtml` on untrusted source code + (e.g. pull requests from external contributors) and expose the HTML report as a build artifact. + JavaScript executes in the browser context of anyone who opens the report. + Note: The default `html` format is **not affected** by unescaped violation messages, but a similar problem + existed with suppressed violation markers. + If you use these reports, it is recommended to upgrade PMD. + Reported by [Smaran Chand](https://github.com/smaranchand) (@smaranchand). + ### 🌟️ New and Changed Rules #### New Rules * The new Java rule {% rule java/codestyle/UnnecessaryInterfaceDeclaration %} detects classes that @@ -43,6 +53,7 @@ This is a {{ site.pmd.release_type }} release. ### 🐛️ Fixed Issues * core * [#6471](https://github.com/pmd/pmd/issues/6471): \[core] BaseAntlrTerminalNode should return type instead of index for getTokenKind() + * [#6475](https://github.com/pmd/pmd/issues/6475): \[core] Fix stored XSS in VBHTMLRenderer and YAHTMLRenderer * doc * [#6396](https://github.com/pmd/pmd/pull/6396): \[doc] Mention test-pmd-tool as alternative for testing * java-bestpractices
pmd-core/src/main/java/net/sourceforge/pmd/renderers/HTMLRenderer.java+26 −20 modified@@ -7,6 +7,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.Writer; +import java.net.URLEncoder; import java.util.Iterator; import java.util.List; import java.util.Optional; @@ -68,6 +69,10 @@ public String defaultFileExtension() { return "html"; } + private static String escape(String s) { + return StringEscapeUtils.escapeHtml4(s); + } + /** * Write the body of the main body of the HTML content. */ @@ -135,16 +140,16 @@ private void glomRuleViolations(Writer writer, Iterator<RuleViolation> violation buf.append("> ").append(System.lineSeparator()); buf.append("<td align=\"center\">").append(violationCount).append("</td>").append(System.lineSeparator()); buf.append("<td width=\"*%\">") - .append(renderFileName(rv.getFileId(), rv.getBeginLine())) + .append(renderFileNameEscaped(rv.getFileId(), rv.getBeginLine())) .append("</td>") .append(System.lineSeparator()); buf.append("<td align=\"center\" width=\"5%\">").append(rv.getBeginLine()).append("</td>").append(System.lineSeparator()); - String d = StringEscapeUtils.escapeHtml4(rv.getDescription()); + String d = escape(rv.getDescription()); String infoUrl = rv.getRule().getExternalInfoUrl(); if (StringUtils.isNotBlank(infoUrl)) { - d = "<a href=\"" + infoUrl + "\">" + d + "</a>"; + d = "<a href=\"" + URLEncoder.encode(infoUrl, "UTF-8") + "\">" + d + "</a>"; } buf.append("<td width=\"*\">") .append(d) @@ -157,13 +162,13 @@ private void glomRuleViolations(Writer writer, Iterator<RuleViolation> violation } } - private String renderFileName(FileId fileId, int beginLine) { - return maybeWrap(StringEscapeUtils.escapeHtml4(determineFileName(fileId)), + private String renderFileNameEscaped(FileId fileId, int beginLine) { + return maybeWrap(escape(determineFileName(fileId)), linePrefix == null || beginLine < 0 ? "" : linePrefix + beginLine); } - private String renderRuleName(Rule rule) { - String name = rule.getName(); + private String renderRuleNameEscaped(Rule rule) { + String name = escape(rule.getName()); String infoUrl = rule.getExternalInfoUrl(); if (StringUtils.isNotBlank(infoUrl)) { return "<a href=\"" + infoUrl + "\">" + name + "</a>"; @@ -192,8 +197,8 @@ private void glomProcessingErrors(PrintWriter writer, List<Report.ProcessingErro } colorize = !colorize; buf.append("> ").append(System.lineSeparator()); - buf.append("<td>").append(renderFileName(pe.getFileId(), -1)).append("</td>").append(System.lineSeparator()); - buf.append("<td><pre>").append(pe.getDetail()).append("</pre></td>").append(System.lineSeparator()); + buf.append("<td>").append(renderFileNameEscaped(pe.getFileId(), -1)).append("</td>").append(System.lineSeparator()); + buf.append("<td><pre>").append(escape(pe.getDetail())).append("</pre></td>").append(System.lineSeparator()); buf.append("</tr>").append(System.lineSeparator()); writer.write(buf.toString()); } @@ -221,11 +226,12 @@ private void glomSuppressions(PrintWriter writer, List<Report.SuppressedViolatio colorize = !colorize; buf.append("> ").append(System.lineSeparator()); RuleViolation rv = sv.getRuleViolation(); - buf.append("<td align=\"left\">").append(renderFileName(rv.getFileId(), rv.getBeginLine())).append("</td>").append(System.lineSeparator()); + String userMessage = Optional.ofNullable(sv.getUserMessage()).orElse(""); + buf.append("<td align=\"left\">").append(renderFileNameEscaped(rv.getFileId(), rv.getBeginLine())).append("</td>").append(System.lineSeparator()); buf.append("<td align=\"center\">").append(rv.getBeginLine()).append("</td>").append(System.lineSeparator()); - buf.append("<td align=\"center\">").append(renderRuleName(rv.getRule())).append("</td>").append(System.lineSeparator()); - buf.append("<td align=\"center\">").append(sv.getSuppressor().getId()).append("</td>").append(System.lineSeparator()); - buf.append("<td align=\"center\">").append(sv.getUserMessage() == null ? "" : sv.getUserMessage()).append("</td>").append(System.lineSeparator()); + buf.append("<td align=\"center\">").append(renderRuleNameEscaped(rv.getRule())).append("</td>").append(System.lineSeparator()); + buf.append("<td align=\"center\">").append(escape(sv.getSuppressor().getId())).append("</td>").append(System.lineSeparator()); + buf.append("<td align=\"center\">").append(escape(userMessage)).append("</td>").append(System.lineSeparator()); buf.append("</tr>").append(System.lineSeparator()); writer.write(buf.toString()); } @@ -252,24 +258,24 @@ private void glomConfigurationErrors(final PrintWriter writer, final List<Config } colorize = !colorize; buf.append("> ").append(System.lineSeparator()); - buf.append("<td>").append(renderRuleName(ce.rule())).append("</td>").append(System.lineSeparator()); - buf.append("<td>").append(ce.issue()).append("</td>").append(System.lineSeparator()); + buf.append("<td>").append(renderRuleNameEscaped(ce.rule())).append("</td>").append(System.lineSeparator()); + buf.append("<td>").append(escape(ce.issue())).append("</td>").append(System.lineSeparator()); buf.append("</tr>").append(System.lineSeparator()); writer.write(buf.toString()); } writer.write("</table>"); } - private String maybeWrap(String filename, String line) { + private String maybeWrap(String filenameEscaped, String line) { if (StringUtils.isBlank(linkPrefix)) { - return filename; + return filenameEscaped; } - String newFileName = filename.replace('\\', '/'); + String newFileName = filenameEscaped.replace('\\', '/'); if (replaceHtmlExtension) { - int index = filename.lastIndexOf('.'); + int index = filenameEscaped.lastIndexOf('.'); if (index >= 0) { - newFileName = filename.substring(0, index); + newFileName = filenameEscaped.substring(0, index); } }
pmd-core/src/main/java/net/sourceforge/pmd/renderers/VBHTMLRenderer.java+12 −6 modified@@ -7,6 +7,8 @@ import java.io.IOException; import java.util.Iterator; +import org.apache.commons.lang3.StringEscapeUtils; + import net.sourceforge.pmd.reporting.Report; import net.sourceforge.pmd.reporting.RuleViolation; @@ -28,6 +30,10 @@ public String defaultFileExtension() { return "vb.html"; } + private static String escape(String s) { + return StringEscapeUtils.escapeHtml4(s); + } + @Override public void start() throws IOException { getWriter().write(header()); @@ -55,7 +61,7 @@ public void renderFileViolations(Iterator<RuleViolation> violations) throws IOEx } filename = nextFilename; sb.append("<table border=\"0\" width=\"80%\">"); - sb.append("<tr id=TableHeader><td colspan=\"2\"><font class=title> ").append(filename) + sb.append("<tr id=TableHeader><td colspan=\"2\"><font class=title> ").append(escape(filename)) .append("</font></tr>"); sb.append(lineSep); } @@ -68,7 +74,7 @@ public void renderFileViolations(Iterator<RuleViolation> violations) throws IOEx colorize = !colorize; sb.append("<td width=\"50\" align=\"right\"><font class=body>").append(rv.getBeginLine()).append(" </font></td>"); - sb.append("<td><font class=body>").append(rv.getDescription()).append("</font></td>"); + sb.append("<td><font class=body>").append(escape(rv.getDescription())).append("</font></td>"); sb.append("</tr>"); sb.append(lineSep); writer.write(sb.toString()); @@ -97,8 +103,8 @@ public void end() throws IOException { sb.append("<tr id=RowColor2>"); } colorize = !colorize; - sb.append("<td><font class=body>").append(determineFileName(error.getFileId())).append("</font></td>"); - sb.append("<td><font class=body><pre>").append(error.getDetail()).append("</pre></font></td></tr>"); + sb.append("<td><font class=body>").append(escape(determineFileName(error.getFileId()))).append("</font></td>"); + sb.append("<td><font class=body><pre>").append(escape(error.getDetail())).append("</pre></font></td></tr>"); } sb.append("</table>"); writer.write(sb.toString()); @@ -116,8 +122,8 @@ public void end() throws IOException { sb.append("<tr id=RowColor2>"); } colorize = !colorize; - sb.append("<td><font class=body>").append(error.rule().getName()).append("</font></td>"); - sb.append("<td><font class=body>").append(error.issue()).append("</font></td></tr>"); + sb.append("<td><font class=body>").append(escape(error.rule().getName())).append("</font></td>"); + sb.append("<td><font class=body>").append(escape(error.issue())).append("</font></td></tr>"); } sb.append("</table>"); writer.write(sb.toString());
pmd-core/src/main/java/net/sourceforge/pmd/renderers/YAHTMLRenderer.java+20 −14 modified@@ -7,13 +7,15 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; +import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.LinkedList; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; +import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import net.sourceforge.pmd.properties.PropertyDescriptor; @@ -47,6 +49,10 @@ public String defaultFileExtension() { return "html"; } + private static String escape(String s) { + return StringEscapeUtils.escapeHtml4(s); + } + private void addViolation(RuleViolation violation) { String packageName = violation.getAdditionalInfo().getOrDefault(RuleViolation.PACKAGE_NAME, ""); String className = violation.getAdditionalInfo().getOrDefault(RuleViolation.CLASS_NAME, ""); @@ -118,17 +124,17 @@ private void renderIndex(String outputDir) throws IOException { for (ReportNode node : reportNodesByPackage.values()) { out.print(" <tr><td><b>"); - out.print(node.getPackageName()); + out.print(escape(node.getPackageName())); out.print("</b></td> <td>"); if (node.hasViolations()) { out.print("<a href=\""); - out.print(node.getClassName()); + out.print(URLEncoder.encode(node.getClassName(), "UTF-8")); out.print(".html"); out.print("\">"); - out.print(node.getClassName()); + out.print(escape(node.getClassName())); out.print("</a>"); } else { - out.print(node.getClassName()); + out.print(escape(node.getClassName())); } out.print("</td> <td>"); out.print(node.getViolationCount()); @@ -151,32 +157,32 @@ private void renderClasses(String outputDir) throws IOException { out.println(" <head>"); out.println(" <meta charset=\"UTF-8\">"); out.print(" <title>PMD - "); - out.print(node.getClassName()); + out.print(escape(node.getClassName())); out.println("</title>"); out.println(" </head>"); out.println(" <body>"); out.println(" <h2>Class View</h2>"); out.print(" <h3 align=\"center\">Class: "); - out.print(node.getClassName()); + out.print(escape(node.getClassName())); out.println("</h3>"); out.println(" <table border=\"\" align=\"center\" cellspacing=\"0\" cellpadding=\"3\">"); out.println(" <tr><th>Method</th><th>Violation</th></tr>"); for (RuleViolation violation : node.getViolations()) { out.print(" <tr><td>"); String methodName = violation.getAdditionalInfo().get(RuleViolation.METHOD_NAME); - out.print(StringUtil.nullToEmpty(methodName)); + out.print(escape(StringUtil.nullToEmpty(methodName))); out.print("</td><td>"); out.print("<table border=\"0\">"); - out.print(renderViolationRow("Rule:", violation.getRule().getName())); - out.print(renderViolationRow("Description:", violation.getDescription())); + out.print(renderViolationRowEscaped("Rule:", violation.getRule().getName())); + out.print(renderViolationRowEscaped("Description:", violation.getDescription())); String variableName = violation.getAdditionalInfo().get(RuleViolation.VARIABLE_NAME); if (StringUtils.isNotBlank(variableName)) { - out.print(renderViolationRow("Variable:", variableName)); + out.print(renderViolationRowEscaped("Variable:", variableName)); } - out.print(renderViolationRow("Line:", violation.getEndLine() > 0 + out.print(renderViolationRowEscaped("Line:", violation.getEndLine() > 0 ? violation.getBeginLine() + " and " + violation.getEndLine() : String.valueOf(violation.getBeginLine()))); @@ -193,12 +199,12 @@ private void renderClasses(String outputDir) throws IOException { } } - private String renderViolationRow(String name, String value) { + private String renderViolationRowEscaped(String name, String value) { return "<tr><td><b>" - + name + + escape(name) + "</b></td>" + "<td>" - + value + + escape(value) + "</td></tr>"; }
pmd-core/src/test/java/net/sourceforge/pmd/renderers/HTMLRendererTest.java+44 −3 modified@@ -11,8 +11,13 @@ import org.junit.jupiter.api.Test; +import net.sourceforge.pmd.lang.document.FileLocation; +import net.sourceforge.pmd.lang.rule.Rule; +import net.sourceforge.pmd.reporting.Report; import net.sourceforge.pmd.reporting.Report.ConfigurationError; import net.sourceforge.pmd.reporting.Report.ProcessingError; +import net.sourceforge.pmd.reporting.RuleViolation; +import net.sourceforge.pmd.reporting.ViolationSuppressor; class HTMLRendererTest extends AbstractRendererTest { @@ -27,6 +32,16 @@ private String getEscapedFilename() { return "someFilename thatNeedsEscaping.ext"; } + private String getEscapedRuleMessage() { + return "This should be escaped: "<script>alert('test')</script>"."; + } + + @Override + protected RuleViolation newRuleViolation(int beginLine, int beginColumn, int endLine, int endColumn, Rule rule) { + FileLocation loc = createLocation(beginLine, beginColumn, endLine, endColumn); + return newRuleViolation(rule, loc, "This should be escaped: \"<script>alert('test')</script>\"."); + } + @Override Renderer getRenderer() { return new HTMLRenderer(); @@ -46,7 +61,7 @@ private String getExpected(String linkPrefix, String lineAnchor) { return getHeader() + "<tr bgcolor=\"lightgrey\"> " + EOL + "<td align=\"center\">1</td>" + EOL + "<td width=\"*%\">" + filename + "</td>" + EOL + "<td align=\"center\" width=\"5%\">1</td>" + EOL - + "<td width=\"*\">blah</td>" + EOL + "</tr>" + EOL + "</table></body></html>" + EOL; + + "<td width=\"*\">" + getEscapedRuleMessage() + "</td>" + EOL + "</tr>" + EOL + "</table></body></html>" + EOL; } @Override @@ -57,15 +72,41 @@ String getExpectedEmpty() { @Override String getExpectedMultiple() { + String ruleDescription = getEscapedRuleMessage(); return getHeader() + "<tr bgcolor=\"lightgrey\"> " + EOL + "<td align=\"center\">1</td>" + EOL + "<td width=\"*%\">" + getEscapedFilename() + "</td>" + EOL + "<td align=\"center\" width=\"5%\">1</td>" + EOL - + "<td width=\"*\">blah</td>" + EOL + "</tr>" + EOL + "<tr> " + EOL + + "<td width=\"*\">" + ruleDescription + "</td>" + EOL + "</tr>" + EOL + "<tr> " + EOL + "<td align=\"center\">2</td>" + EOL + "<td width=\"*%\">" + getEscapedFilename() + "</td>" + EOL - + "<td align=\"center\" width=\"5%\">1</td>" + EOL + "<td width=\"*\">blah</td>" + EOL + "</tr>" + + "<td align=\"center\" width=\"5%\">1</td>" + EOL + "<td width=\"*\">" + ruleDescription + "</td>" + EOL + "</tr>" + EOL + "</table></body></html>" + EOL; } + private String getExpectedSuppressed() { + return getHeader() + + "</table><hr/><center><h3>Suppressed warnings</h3></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + EOL + + "<th>File</th><th>Line</th><th>Rule</th><th>NOPMD or Annotation</th><th>Reason</th></tr>" + EOL + + "<tr bgcolor=\"lightgrey\"> " + EOL + + "<td align=\"left\">someFilename thatNeedsEscaping.ext</td>" + EOL + + "<td align=\"center\">1</td>" + EOL + + "<td align=\"center\">Foo</td>" + EOL + + "<td align=\"center\">//NOPMD</td>" + EOL + + "<td align=\"center\">userMessage should be <script>alert('escaped')</script></td>" + EOL + + "</tr>" + EOL + + "</table></body></html>" + EOL; + } + + @Test + void testRendererSuppressed() throws Exception { + String actual = renderReport(getRenderer(), it -> { + RuleViolation ruleViolation = newRuleViolation(1, 1, 1, 1, createFooRule()); + Report.SuppressedViolation suppressedViolation = new Report.SuppressedViolation(ruleViolation, + ViolationSuppressor.NOPMD_COMMENT_SUPPRESSOR, "userMessage should be <script>alert('escaped')</script>"); + it.onSuppressedRuleViolation(suppressedViolation); + }); + assertEquals(filter(getExpectedSuppressed()), filter(actual)); + } + @Override String getExpectedError(ProcessingError error) { return getHeader()
pmd-core/src/test/java/net/sourceforge/pmd/renderers/VBHTMLRendererTest.java+17 −3 modified@@ -4,8 +4,11 @@ package net.sourceforge.pmd.renderers; +import net.sourceforge.pmd.lang.document.FileLocation; +import net.sourceforge.pmd.lang.rule.Rule; import net.sourceforge.pmd.reporting.Report.ConfigurationError; import net.sourceforge.pmd.reporting.Report.ProcessingError; +import net.sourceforge.pmd.reporting.RuleViolation; class VBHTMLRendererTest extends AbstractRendererTest { @@ -14,6 +17,16 @@ Renderer getRenderer() { return new VBHTMLRenderer(); } + private String getEscapedRuleMessage() { + return "This should be escaped: "<script>alert('test')</script>"."; + } + + @Override + protected RuleViolation newRuleViolation(int beginLine, int beginColumn, int endLine, int endColumn, Rule rule) { + FileLocation loc = createLocation(beginLine, beginColumn, endLine, endColumn); + return newRuleViolation(rule, loc, "This should be escaped: \"<script>alert('test')</script>\"."); + } + @Override String getExpected() { return "<html><head><title>PMD</title></head><style type=\"text/css\"><!--" + EOL @@ -27,7 +40,7 @@ String getExpected() { + EOL + "--></style><body><center><table border=\"0\" width=\"80%\"><tr id=TableHeader><td colspan=\"2\"><font class=title> " + getSourceCodeFilename() + "</font></tr>" + EOL - + "<tr id=RowColor2><td width=\"50\" align=\"right\"><font class=body>1 </font></td><td><font class=body>blah</font></td></tr>" + + "<tr id=RowColor2><td width=\"50\" align=\"right\"><font class=body>1 </font></td><td><font class=body>" + getEscapedRuleMessage() + "</font></td></tr>" + EOL + "</table><br></center></body></html>" + EOL; } @@ -46,6 +59,7 @@ String getExpectedEmpty() { @Override String getExpectedMultiple() { + String ruleDescription = getEscapedRuleMessage(); return "<html><head><title>PMD</title></head><style type=\"text/css\"><!--" + EOL + "body { background-color: white; font-family:verdana, arial, helvetica, geneva; font-size: 16px; font-style: italic; color: black; }" + EOL @@ -57,9 +71,9 @@ String getExpectedMultiple() { + EOL + "--></style><body><center><table border=\"0\" width=\"80%\"><tr id=TableHeader><td colspan=\"2\"><font class=title> " + getSourceCodeFilename() + "</font></tr>" + EOL - + "<tr id=RowColor2><td width=\"50\" align=\"right\"><font class=body>1 </font></td><td><font class=body>blah</font></td></tr>" + + "<tr id=RowColor2><td width=\"50\" align=\"right\"><font class=body>1 </font></td><td><font class=body>" + ruleDescription + "</font></td></tr>" + EOL - + "<tr id=RowColor1><td width=\"50\" align=\"right\"><font class=body>1 </font></td><td><font class=body>blah</font></td></tr>" + + "<tr id=RowColor1><td width=\"50\" align=\"right\"><font class=body>1 </font></td><td><font class=body>" + ruleDescription + "</font></td></tr>" + EOL + "</table><br></center></body></html>" + EOL; }
pmd-core/src/test/java/net/sourceforge/pmd/renderers/YAHTMLRendererTest.java+1 −1 modified@@ -46,7 +46,7 @@ private RuleViolation newRuleViolation(int beginLine, int beginColumn, int endLi FileLocation loc = createLocation(beginLine, beginColumn, endLine, endColumn); Map<String, String> additionalInfo = CollectionUtil.mapOf(RuleViolation.PACKAGE_NAME, packageNameArg, RuleViolation.CLASS_NAME, classNameArg); - return InternalApiBridge.createRuleViolation(new FooRule(), loc, "blah", additionalInfo); + return InternalApiBridge.createRuleViolation(new FooRule(), loc, "This should be escaped: \"<script>alert('test')</script>\".", additionalInfo); } @Override
pmd-core/src/test/resources/net/sourceforge/pmd/renderers/yahtml/YAHTMLSampleClass1.html+2 −2 modified@@ -9,8 +9,8 @@ <h2>Class View</h2> <h3 align="center">Class: YAHTMLSampleClass1</h3> <table border="" align="center" cellspacing="0" cellpadding="3"> <tr><th>Method</th><th>Violation</th></tr> - <tr><td></td><td><table border="0"><tr><td><b>Rule:</b></td><td>Foo</td></tr><tr><td><b>Description:</b></td><td>blah</td></tr><tr><td><b>Line:</b></td><td>1 and 1</td></tr></table></td></tr> - <tr><td></td><td><table border="0"><tr><td><b>Rule:</b></td><td>Foo</td></tr><tr><td><b>Description:</b></td><td>blah</td></tr><tr><td><b>Line:</b></td><td>1 and 1</td></tr></table></td></tr> + <tr><td></td><td><table border="0"><tr><td><b>Rule:</b></td><td>Foo</td></tr><tr><td><b>Description:</b></td><td>This should be escaped: "<script>alert('test')</script>".</td></tr><tr><td><b>Line:</b></td><td>1 and 1</td></tr></table></td></tr> + <tr><td></td><td><table border="0"><tr><td><b>Rule:</b></td><td>Foo</td></tr><tr><td><b>Description:</b></td><td>This should be escaped: "<script>alert('test')</script>".</td></tr><tr><td><b>Line:</b></td><td>1 and 1</td></tr></table></td></tr> </table> </body> </html>
pmd-core/src/test/resources/net/sourceforge/pmd/renderers/yahtml/YAHTMLSampleClass2.html+1 −1 modified@@ -9,7 +9,7 @@ <h2>Class View</h2> <h3 align="center">Class: YAHTMLSampleClass2</h3> <table border="" align="center" cellspacing="0" cellpadding="3"> <tr><th>Method</th><th>Violation</th></tr> - <tr><td></td><td><table border="0"><tr><td><b>Rule:</b></td><td>Foo</td></tr><tr><td><b>Description:</b></td><td>blah</td></tr><tr><td><b>Line:</b></td><td>1 and 1</td></tr></table></td></tr> + <tr><td></td><td><table border="0"><tr><td><b>Rule:</b></td><td>Foo</td></tr><tr><td><b>Description:</b></td><td>This should be escaped: "<script>alert('test')</script>".</td></tr><tr><td><b>Line:</b></td><td>1 and 1</td></tr></table></td></tr> </table> </body> </html>
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-8rr6-2qw5-pc7rghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-28338ghsaADVISORY
- github.com/pmd/pmd/commit/c140c0e1de5853a08efb84c9f91dfeb015882442ghsax_refsource_MISCWEB
- github.com/pmd/pmd/pull/6475ghsax_refsource_MISCWEB
- github.com/pmd/pmd/security/advisories/GHSA-8rr6-2qw5-pc7rghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.