Skip to content

Commit

Permalink
feat(js): add handlebars XSS rule (#317)
Browse files Browse the repository at this point in the history
  • Loading branch information
elsapet authored Feb 23, 2024
1 parent ed11578 commit e12cb06
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 0 deletions.
37 changes: 37 additions & 0 deletions rules/javascript/lang/handlebars_no_escape.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
patterns:
- pattern: handlebars.compile($<...>$<NO_ESCAPE>)
filters:
- variable: NO_ESCAPE
detection: javascript_lang_handlebars_no_escape_true
scope: result
auxiliary:
- id: javascript_lang_handlebars_no_escape_true
patterns:
- |
{ noEscape: true }
languages:
- javascript
severity: warning
metadata:
description: "Missing escape of HTML entities in Handlebars template compilation"
remediation_message: |
## Description
As a templating engine, Handlebars generates HTML markup dynamically.
Setting `noEscape` to true disables escaping HTML entities within the template output itself.
This is a security risk as it could lead to Cross-Site Scripting (XSS) vulnerabilities if
the template is from an untrusted source.
## Remediations
❌ Do not set `noEscape` to true when compiling Handlebars templates
## References
- [Handlebars compile docs](https://handlebarsjs.com/api-reference/compilation.html#handlebars-compile-template-options)
- [OWASP XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
cwe_id:
- 80
id: javascript_lang_handlebars_no_escape
documentation_url: https://docs.bearer.com/reference/rules/javascript_lang_handlebars_no_escape
20 changes: 20 additions & 0 deletions tests/javascript/lang/handlebars_no_escape/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const {
createNewInvoker,
getEnvironment,
} = require("../../../helper.js")
const { ruleId, ruleFile, testBase } = getEnvironment(__dirname)

describe(ruleId, () => {
const invoke = createNewInvoker(ruleId, ruleFile, testBase)

test("handlebars_no_escape", () => {
const testCase = "app.js"

const results = invoke(testCase)

expect(results).toEqual({
Missing: [],
Extra: []
})
})
})
23 changes: 23 additions & 0 deletions tests/javascript/lang/handlebars_no_escape/testdata/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Handlebars from 'handlebars';

const handlebars = Handlebars.create();

export function bad(templateStr) {
try {
// bearer:expected javascript_lang_handlebars_no_escape
const template = handlebars.compile(templateStr, { noEscape: true });

compiledTemplate = template(vars);
} catch (err) {
// ...
}
}

export function ok(templateStr) {
try {
const template = handlebars.compile(templateStr, { noEscape: false });
compiledTemplate = template(vars);
} catch (err) {
// ...
}
}

0 comments on commit e12cb06

Please sign in to comment.