VYPR
Moderate severityNVD Advisory· Published Feb 27, 2026· Updated Mar 3, 2026

PMD Designer has Stored XSS in VBHTMLRenderer and YAHTMLRenderer via unescaped violation messages

CVE-2026-28338

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.

PackageAffected versionsPatched versions
net.sourceforge.pmd:pmd-coreMaven
< 7.22.07.22.0

Affected products

2
  • Pmd/PMDllm-create
    Range: <7.22.0
  • pmd/pmdv5
    Range: < 7.22.0

Patches

1
c140c0e1de58

[core] Fix stored XSS in VBHTMLRenderer and YAHTMLRenderer (#6475)

https://github.com/pmd/pmdAndreas DangelFeb 27, 2026via ghsa
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>&nbsp;").append(filename)
    +                sb.append("<tr id=TableHeader><td colspan=\"2\"><font class=title>&nbsp;").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("&nbsp;&nbsp;&nbsp;</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&nbsp;thatNeedsEscaping.ext";
         }
     
    +    private String getEscapedRuleMessage() {
    +        return "This should be escaped: &quot;&lt;script&gt;alert('test')&lt;/script&gt;&quot;.";
    +    }
    +
    +    @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&nbsp;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 &lt;script&gt;alert('escaped')&lt;/script&gt;</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: &quot;&lt;script&gt;alert('test')&lt;/script&gt;&quot;.";
    +    }
    +
    +    @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>&nbsp;" + getSourceCodeFilename() + "</font></tr>"
                     + EOL
    -                + "<tr id=RowColor2><td width=\"50\" align=\"right\"><font class=body>1&nbsp;&nbsp;&nbsp;</font></td><td><font class=body>blah</font></td></tr>"
    +                + "<tr id=RowColor2><td width=\"50\" align=\"right\"><font class=body>1&nbsp;&nbsp;&nbsp;</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>&nbsp;" + getSourceCodeFilename() + "</font></tr>"
                     + EOL
    -                + "<tr id=RowColor2><td width=\"50\" align=\"right\"><font class=body>1&nbsp;&nbsp;&nbsp;</font></td><td><font class=body>blah</font></td></tr>"
    +                + "<tr id=RowColor2><td width=\"50\" align=\"right\"><font class=body>1&nbsp;&nbsp;&nbsp;</font></td><td><font class=body>" + ruleDescription + "</font></td></tr>"
                     + EOL
    -                + "<tr id=RowColor1><td width=\"50\" align=\"right\"><font class=body>1&nbsp;&nbsp;&nbsp;</font></td><td><font class=body>blah</font></td></tr>"
    +                + "<tr id=RowColor1><td width=\"50\" align=\"right\"><font class=body>1&nbsp;&nbsp;&nbsp;</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: &quot;&lt;script&gt;alert('test')&lt;/script&gt;&quot;.</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: &quot;&lt;script&gt;alert('test')&lt;/script&gt;&quot;.</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: &quot;&lt;script&gt;alert('test')&lt;/script&gt;&quot;.</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

News mentions

0

No linked articles in our index yet.