Skip to content

feat(java): detect unescaped raw() of non-literal values in Groovy/Stapler view templates (CWE-79) - #155

Open
ai-anant wants to merge 1 commit into
CodeVigilant:mainfrom
ai-anant:rule/java-jenkins-view-raw-unescaped-output
Open

feat(java): detect unescaped raw() of non-literal values in Groovy/Stapler view templates (CWE-79)#155
ai-anant wants to merge 1 commit into
CodeVigilant:mainfrom
ai-anant:rule/java-jenkins-view-raw-unescaped-output

Conversation

@ai-anant

Copy link
Copy Markdown

Adds a rule (rule id codevigilant.java.jenkins.view.raw-unescaped-output) that flags Groovy/Stapler view templates which pass a non-literal value to the raw(...) output builder.

The Jenkins raw(...) builder writes its argument to the HTTP response verbatim, skipping all HTML/XML escaping. When the argument is a model getter, changelog/SCM-derived value, or any external/request-derived string, an attacker who controls that value can inject arbitrary markup/script into the rendered page (stored/reflected XSS, CWE-79). The pattern is:

patterns:
  - pattern: raw(...)
  - pattern-not: raw("...")

Because Groovy view templates are .groovy files and there is no native semgrep groovy language, the rule is declared with languages: [generic] so it is applied to .groovy files during a normal repo sweep (a java-language rule scans 0 .groovy targets, verified). Constant string literals passed through raw("...") are excluded via pattern-not, keeping the rule focused on tainted/non-literal output.

Validation + tests:

  • semgrep --validate --config java/ : valid (118 rules total with php/).
  • POSITIVE testcases/java/jenkins/view/raw-unescaped-output-pos.groovy fires (4/4): raw(c.msgAnnotated), raw(c.getCommitId()), raw(browser.getChangeSetLink(c)), raw(entry.msg).
  • NEGATIVE testcases/java/jenkins/view/raw-unescaped-output-neg.groovy is clean (0): constant raw("...") literals, and text(...) / builder paths.

Severity HIGH, confidence MEDIUM (generic-mode matcher may also flag a raw("constant") if a comment or string contains the raw( token sequence; the primary pattern-not strips the dominant false-positive class).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant