Skip to content

Commit de9370a

Browse files
authored
Merge pull request github#16540 from aegilops/aegilops/js/insecure-helmet-middleware
JS/TS: insecure Helmet middleware (new query)
2 parents 5bdef38 + 412ad17 commit de9370a

File tree

12 files changed

+216
-0
lines changed

12 files changed

+216
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/javascript-queries
4+
extensible: requiredHelmetSecuritySetting
5+
data:
6+
- ["frameguard"]
7+
- ["contentSecurityPolicy"]
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Insecure Helmet Configuration - customizations
2+
3+
You can extend the required [Helmet security settings](https://helmetjs.github.io/) using [data extensions](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-javascript/) in a [CodeQL model pack](https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/creating-and-working-with-codeql-packs#creating-a-codeql-model-pack).
4+
5+
They are defaulted to just `frameguard` and `contentSecurityPolicy`, but you can add more using this method, to require them not to be set to `false` (which explicitly disables them) in the Helmet configuration.
6+
7+
For example, this YAML model can be used inside a CodeQL model pack to require `frameguard` and `contentSecurityPolicy`:
8+
9+
```yaml
10+
extensions:
11+
- addsTo:
12+
pack: codeql/javascript-all
13+
extensible: requiredHelmetSecuritySetting
14+
data:
15+
- ["frameguard"]
16+
- ["contentSecurityPolicy"]
17+
```
18+
19+
Note: Using `frameguard` and `contentSecurityPolicy` is an example: the query already enforces these, so it is not necessary to add it with your own data extension.
20+
21+
A suitable [model pack](https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/creating-and-working-with-codeql-packs#creating-a-codeql-model-pack) might be:
22+
23+
```yaml
24+
name: my-org/javascript-helmet-insecure-config-model-pack
25+
version: 1.0.0
26+
extensionTargets:
27+
codeql/java-all: '*'
28+
dataExtensions:
29+
- models/**/*.yml
30+
```
31+
32+
## References
33+
34+
- [Helmet security settings](https://helmetjs.github.io/)
35+
- [Customizing library models for javascript](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-javascript/)
36+
- [Creating and working with CodeQL packs](https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/creating-and-working-with-codeql-packs#creating-a-codeql-model-pack)
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
2+
<qhelp>
3+
<overview>
4+
<p>
5+
<a href="https://helmetjs.github.io/">Helmet</a> is a collection of middleware functions for securing Express apps. It sets various HTTP headers to guard against common web vulnerabilities.
6+
7+
This query detects Helmet misconfigurations that can lead to security vulnerabilities, specifically:
8+
</p>
9+
10+
<ul>
11+
<li>Disabling frame protection</li>
12+
<li>Disabling Content Security Policy</li>
13+
</ul>
14+
15+
<p>
16+
Content Security Policy (CSP) helps spot and prevent injection attacks such as Cross-Site Scripting (XSS).
17+
18+
Removing frame protections exposes an application to attacks such as clickjacking, where an attacker can trick a user into clicking on a button or link on a targeted page when they intended to click on the page carrying out the attack.
19+
</p>
20+
21+
<p>
22+
Users of the query can extend the set of required Helmet features by adding additional checks for them, using CodeQL <a href="https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-javascript/">data extensions</a> in a <a href="https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/creating-and-working-with-codeql-packs#creating-a-codeql-model-pack">CodeQL model pack</a>. See <code>CUSTOMIZING.md</code> in the query source for more information.
23+
</p>
24+
25+
</overview>
26+
<recommendation>
27+
<p>
28+
To help mitigate these vulnerabilities, ensure that the following Helmet functions are not disabled, and are configured appropriately to your application:
29+
</p>
30+
31+
<ul>
32+
<li><code>frameguard</code></li>
33+
<li><code>contentSecurityPolicy</code></li>
34+
</ul>
35+
</recommendation>
36+
<example>
37+
<p>
38+
The following code snippet demonstrates Helmet configured in an insecure manner:
39+
</p>
40+
41+
<sample src="examples/helmet_insecure.js" />
42+
43+
<p>
44+
In this example, the defaults are used, which enables frame protection and a default Content Security Policy.
45+
</p>
46+
47+
<sample src="examples/helmet_default.js" />
48+
49+
<p>
50+
You can also enable a custom Content Security Policy by passing an object to the <code>contentSecurityPolicy</code> key. For example, taken from the <a href="https://helmetjs.github.io/#content-security-policy">Helmet docs</a>:
51+
</p>
52+
53+
<sample src="examples/helmet_custom.js" />
54+
55+
</example>
56+
<references>
57+
<li>
58+
<a href="https://helmetjs.github.io/">helmet.js website</a>
59+
</li>
60+
<li>
61+
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy">Content Security Policy (CSP) | MDN</a>
62+
</li>
63+
<li>
64+
<a href="https://infosec.mozilla.org/guidelines/web_security">Mozilla Web Security Guidelines</a>
65+
</li>
66+
<li>
67+
<a href="https://developer.mozilla.org/en-US/docs/Web/Security#protect_against_clickjacking">Protect against clickjacking | MDN</a>
68+
</li>
69+
70+
</references>
71+
</qhelp>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @name Insecure configuration of Helmet security middleware
3+
* @description The Helmet middleware is used to set security-related HTTP headers in Express applications. This query finds instances where the middleware is configured with important security features disabled.
4+
* @kind problem
5+
* @problem.severity error
6+
* @security-severity 7.0
7+
* @precision high
8+
* @id js/insecure-helmet-configuration
9+
* @tags security
10+
* external/cwe/cwe-693
11+
* external/cwe/cwe-1021
12+
*/
13+
14+
import javascript
15+
import DataFlow
16+
import semmle.javascript.frameworks.ExpressModules
17+
18+
class HelmetProperty extends DataFlow::Node instanceof DataFlow::PropWrite {
19+
ExpressLibraries::HelmetRouteHandler helmet;
20+
21+
HelmetProperty() {
22+
this = helmet.(DataFlow::CallNode).getAnArgument().getALocalSource().getAPropertyWrite()
23+
}
24+
25+
ExpressLibraries::HelmetRouteHandler getHelmet() { result = helmet }
26+
27+
predicate isFalse() { DataFlow::PropWrite.super.getRhs().mayHaveBooleanValue(false) }
28+
29+
string getName() { result = DataFlow::PropWrite.super.getPropertyName() }
30+
31+
predicate isImportantSecuritySetting() {
32+
// read from data extensions to allow enforcing custom settings
33+
// defaults are located in javascript/ql/lib/semmle/frameworks/helmet/Helmet.Required.Setting.model.yml
34+
requiredHelmetSecuritySetting(this.getName())
35+
}
36+
}
37+
38+
extensible predicate requiredHelmetSecuritySetting(string name);
39+
40+
from HelmetProperty helmetProperty, ExpressLibraries::HelmetRouteHandler helmet
41+
where
42+
helmetProperty.isFalse() and
43+
helmetProperty.isImportantSecuritySetting() and
44+
helmetProperty.getHelmet() = helmet
45+
select helmet,
46+
"Helmet security middleware, configured with security setting $@ set to 'false', which disables enforcing that feature.",
47+
helmetProperty, helmetProperty.getName()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
app.use(
2+
helmet({
3+
contentSecurityPolicy: {
4+
directives: {
5+
"script-src": ["'self'", "example.com"],
6+
"style-src": null,
7+
},
8+
},
9+
})
10+
);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
app.use(helmet());
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const helmet = require('helmet');
2+
3+
app.use(helmet({
4+
frameguard: false,
5+
contentSecurityPolicy: false
6+
}));
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: newQuery
3+
---
4+
* Added a new query, `js/insecure-helmet-configuration`, to detect instances where Helmet middleware is configured with important security features disabled.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| InsecureHelmetBad.js:6:9:9:2 | helmet( ... uard\\n}) | Helmet security middleware, configured with security setting $@ set to 'false', which disables enforcing that feature. | InsecureHelmetBad.js:7:5:7:32 | content ... : false | contentSecurityPolicy |
2+
| InsecureHelmetBad.js:6:9:9:2 | helmet( ... uard\\n}) | Helmet security middleware, configured with security setting $@ set to 'false', which disables enforcing that feature. | InsecureHelmetBad.js:8:5:8:21 | frameguard: false | frameguard |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE-693/InsecureHelmet.ql

0 commit comments

Comments
 (0)