Skip to content

Judge server templates: inline scripts, template code and Node views - #27

Merged
tauanbinato merged 8 commits into
audit-0.21from
server-templates
Sep 26, 2026
Merged

tauanbinato merged 8 commits into
audit-0.21from
server-templates

Conversation

@tauanbinato

@tauanbinato tauanbinato commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #26. JevGate never read server templates, and they held most of the vulnerabilities the audit's vulnerable apps document that it missed. This teaches it three things about them.

What changes

  • Inline scripts: an ERB, EJS, JSP, Handlebars, Mustache, Nunjucks, Twig, Jinja or Go template, or HTML under templates/, views/, layouts/, partials/ or includes/, is parsed as its <script> code, with its template tags blanked so lines stay the file's. Its top-level script is judged like a PHP page script by every security rule, and its requests say the code runs in the visitor's browser.
  • Template code: the server code a template runs that reads the request, a cookie, the session or the signed-in user is one unit, template code. For ERB, EJS, Handlebars, Jinja and Twig that is the tags writing such a value unescaped; injection judges them. For JSP it is every scriptlet and declaration once one reads the request; every security rule judges them.
  • Node views: a handler that renders a view by name (res.render('app/products', …)) is sent the view's lines that write values unescaped, as Django views already were. Its presence question, markup check and markup Choice name such templates.

A template holding neither inline scripts nor template code is not selected; 900 of the corpus's 1,003 templates stay out of reports.

Results

Labeled findings, tuned projects Reviews right Considers right
Template code (unescaped client data, JSP scriptlets and declarations) 34 of 38 6 of 9
Inline scripts 8 of 11 10 of 16
Node views (dvna's handlers) 1 of 1 1 of 1

Documented vulnerabilities in the intentionally vulnerable apps that no rule read, now found (24):

Held-out projects: 1 review right (dvja), 1 consider wrong (mdbook's page script). Corpus cost of the whole branch: about $0.1.

Sanity check on four real apps outside the corpus, template paths only (about $0.07):

  • jpetstore-6 (JSP with Stripes tags and EL): nothing selected.
  • healthchecks (Django): no template findings.
  • human-essentials (Rails): four considers on raw fullstory_script(current_user: …), whose helper writes the user's email unescaped into a <script> string. That is a real, if self-only, injection. It also got a hard-coded production sign-in URL in a page script.
  • hackathon-starter (Express + Pug): this showed that Pug's != rule also matched !== comparisons, now fixed. What remains are td!= link (scraped HTML) and !{ publicKey } JSON in a script tag.

Review notes

  • Considers on inline scripts are the weak part (10 right, 6 wrong; injection alone 5 right, 3 wrong): parameterless click and ready callbacks get "its parameters … a caller passing outside input" wording for data fetched from the app's own server. The origin question has no option for that; fixing it means rewording browser code's origin question everywhere, so I left it.
  • Nothing outside templates, Node handlers that render views, and dvna/express changed: the other 101 corpus projects send byte-identical requests.
  • The branch's self-check leaves only the baselined visit. CI's review runs the released 0.20.0, which also flags settle.rs (fixed by Audit 0.20.0 on 103 projects: crash and hang fixes, security checks, precision caps #26's file-organization change).
  • check --help now names component and server template files.

JevGate never read server templates, and they held most of the documented
vulnerabilities it missed in the intentionally vulnerable apps.

- An ERB, EJS, JSP, Handlebars, Mustache, Nunjucks, Twig, Jinja or Go
  template, or HTML under templates/, views/, layouts/, partials/ or
  includes/, is parsed as its inline scripts with its tags blanked, and its
  top-level script is judged like a PHP page script. Its requests say the
  code runs in the visitor's browser.
- Its `template code` is one more unit: tags that write request, cookie,
  session or signed-in-user data unescaped (judged by injection), and every
  scriptlet and declaration of a JSP page once one reads the request
  (judged by every security rule).
- A Node handler that renders a view by name is sent the view's unescaped
  lines, as Django views are, and its questions name such templates.

A template holding neither inline scripts nor template code is not
selected. On the corpus, 24 documented vulnerabilities are found that no
rule read (RailsGoat's and DVNA's XSS, DVGA's paste-page XSS, DVJA's JSP
XSS, JavaVulnerableLab's JSP-only injections, traversal, SSRF and leaked
stack traces); 42 of 49 labeled reviews and 16 of 25 considers in templates
were right. Requests outside templates and render calls are unchanged on
the other 101 projects.
…check's help

Pug writes a value unescaped with `!=` right after a tag or at the start of
a line, and with `!{…}`; `err.name !== 'AbortError'` in a view's script
is a comparison. hackathon-starter's handlers were sent such comparisons as
unescaped output. `check --help` names the component and server template
files JevGate selects.
@tauanbinato
tauanbinato merged commit 714e7a2 into audit-0.21 Sep 26, 2026
9 checks passed
@tauanbinato
tauanbinato deleted the server-templates branch September 26, 2026 21:16
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