javascript.express.security.express-puppeteer-injection.express-puppeteer-injection

Author
3,077
Download Count*
License
If unverified user data can reach the puppeteer
methods it can result in Server-Side Request Forgery vulnerabilities
Run Locally
Run in CI
Defintion
rules:
- id: express-puppeteer-injection
message: If unverified user data can reach the `puppeteer` methods it can result
in Server-Side Request Forgery vulnerabilities
metadata:
owasp:
- A10:2021 - Server-Side Request Forgery (SSRF)
cwe:
- "CWE-918: Server-Side Request Forgery (SSRF)"
category: security
technology:
- express
references:
- https://pptr.dev/api/puppeteer.page
cwe2022-top25: true
cwe2021-top25: true
subcategory:
- vuln
likelihood: MEDIUM
impact: MEDIUM
confidence: MEDIUM
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
languages:
- javascript
- typescript
severity: ERROR
mode: taint
pattern-sources:
- patterns:
- pattern-either:
- pattern-inside: function ... ($REQ, $RES) {...}
- pattern-inside: function ... ($REQ, $RES, $NEXT) {...}
- patterns:
- pattern-either:
- pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES) {...})
- pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES, $NEXT) {...})
- metavariable-regex:
metavariable: $METHOD
regex: ^(get|post|put|head|delete|options)$
- pattern-either:
- pattern: $REQ.query
- pattern: $REQ.body
- pattern: $REQ.params
- pattern: $REQ.cookies
- pattern: $REQ.headers
- patterns:
- pattern-either:
- pattern-inside: |
({ $REQ }: Request,$RES: Response, $NEXT: NextFunction) =>
{...}
- pattern-inside: |
({ $REQ }: Request,$RES: Response) => {...}
- focus-metavariable: $REQ
- pattern-either:
- pattern: params
- pattern: query
- pattern: cookies
- pattern: headers
- pattern: body
pattern-sinks:
- patterns:
- pattern-either:
- pattern-inside: |
require('puppeteer');
...
- pattern-inside: |
import 'puppeteer';
...
- pattern-either:
- pattern: $PAGE.goto($SINK,...)
- pattern: $PAGE.setContent($SINK,...)
- pattern: $PAGE.evaluate($SINK,...)
- pattern: $PAGE.evaluate($CODE,$SINK,...)
- pattern: $PAGE.evaluateHandle($SINK,...)
- pattern: $PAGE.evaluateHandle($CODE,$SINK,...)
- pattern: $PAGE.evaluateOnNewDocument($SINK,...)
- pattern: $PAGE.evaluateOnNewDocument($CODE,$SINK,...)
- focus-metavariable: $SINK
Examples
express-puppeteer-injection.js
const express = require('express')
const app = express()
const port = 3000
const puppeteer = require('puppeteer')
app.get('/', async (req, res) => {
const browser = await puppeteer.launch()
const page = await browser.newPage()
const url = `https://${req.query.name}`
// ruleid: express-puppeteer-injection
await page.goto(url)
await page.screenshot({path: 'example.png'})
await browser.close()
res.send('Hello World!')
})
app.post('/test', async (req, res) => {
const browser = await puppeteer.launch()
const page = await browser.newPage()
// ruleid: express-puppeteer-injection
await page.setContent(`${req.body.foo}`)
await page.screenshot({path: 'example.png'})
await browser.close()
res.send('Hello World!')
})
const controller = async (req, res) => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
const body = req.body.foo;
// ruleid: express-puppeteer-injection
await page.setContent('<html>' + body + '</html>');
await page.screenshot({path: 'example.png'});
await browser.close();
res.send('Hello World!');
}
app.post('/test2', async (req, res) => {
const browser = await puppeteer.launch()
const page = await browser.newPage()
// ruleid: express-puppeteer-injection
await page.evaluateOnNewDocument(`${req.body.foo}`)
await page.screenshot({path: 'example.png'})
await browser.close()
res.send('Hello World!')
})
const controller2 = async (req, res) => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
const body = req.body.foo;
// ruleid: express-puppeteer-injection
await page.evaluate('alert(' + body + ')');
await page.screenshot({path: 'example.png'});
await browser.close();
res.send('Hello World!');
}
app.post('/test2', controller)
app.post('/ok-test', async (req, res) => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// ok: express-puppeteer-injection
await page.goto('https://example.com');
await page.screenshot({path: 'example.png'});
await browser.close();
res.send('Hello World!');
})
const controller = async (req, res) => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// ok: express-puppeteer-injection
const body = '<div>123</div>';
await page.setContent('<html>' + body + '</html>');
await page.screenshot({path: 'example.png'});
await browser.close();
res.send('Hello World!');
}
app.post('/ok-test2', controller)
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
Short Link: https://sg.run/0QJB