Hej! 👋 This repository contains a collection of Server-Side Prototype Pollution gadgets found in Node.js, Deno standard libraries, and various third-party NPM packages. We also compile information about known exploits against popular applications to showcase the impact of these gadgets.
Prototype pollution is a vulnerability specific to JavaScript and TypeScript that allows an attacker to modify an object's prototype with attacker-controlled properties. The severity of these vulnerabilities hinges on gadgets, fragments of existing code in vulnerable applications that read undefined properties and execute security-sentitive actions. For instance, these gadgets can lead to Remote Code Execution (RCE) attacks.
If you're new to server-side Prototype Pollution, check out our DEF CON 31 talk for a quick 20-minute introduction to Prototype Pollution vulnerabilities in Node.js, gadgets, and an example of a real RCE exploit. All accompanying materials, such as CodeQL queries, benchmarks, experimental results, and links to extended talks, are available in the repo Silent Spring.
We also recommend checking out these papers and blog posts:
- The seminal paper "JavaScript prototype pollution attack in NodeJS" by Olivier Arteau provides many details on the exploitation and mitigation of Prototype Pollution on the server-side.
- The paper
"Silent Spring: Prototype Pollution Leads to Remote Code Execution in Node.js"
by Shcherbakov et al. introduces a tool for Prototype Pollution detection and
and the first gadgets in Node.js stdlib, including a gadget in
require
. This repository was developed as a result of this research project. 🤓 - The blog post "Server-side prototype pollution: Black-box detection without the DoS" by Gareth Heyes focuses on server-side gadgets and how to detect Prototype Pollution using black-box techniques.
- The paper "Undefined-oriented Programming: Detecting and Chaining Prototype Pollution Gadgets in Node.js Template Engines for Malicious Consequences" by Zhengyu Liu et al. presents a methodology for constructing chains of Prototype Pollution gadgets.
- The paper "GHunter: Universal Prototype Pollution Gadgets in JavaScript Runtimes" by Cornelissen et al. presents a semi-automated pipeline for systematically detecting prototype pollution-based gadgets in the Node.js and Deno runtimes.
- The write-up "Remote Code Execution via Prototype Pollution in Blitz.js" provides an exciting story of exploiting Prototype Pollution in Blitz.js, a fullstack toolkit for Next.js.
- Is Prototype Pollution possible on the client-side? Check out this repo
Note
If you want to add new gadgets, please create a Pull Request. Feel free to ask any questions, discuss new ideas for Prototype Pollution research, or suggest improvements for this repo. Contact: Mikhail Shcherbakov, Eric Cornelissen, and Musard Balliu
Function | Polluted Properties | Type | Notes | Found by |
---|---|---|---|---|
child_process.exec | NODE_OPTIONS |
ACI | Silent Spring | |
child_process.execFile | NODE_OPTIONS |
ACI | Silent Spring | |
child_process.execFileSync | shell ; NODE_OPTIONS |
ACI | Silent Spring | |
child_process.execFileSync | shell ; input |
ACI | Silent Spring | |
child_process.execSync | NODE_OPTIONS |
ACI | Silent Spring | |
child_process.execSync | shell ; env |
ACI | Michał Bentkowski and Silent Spring | |
child_process.execSync | shell ; input |
ACI | Silent Spring | |
child_process.fork | NODE_OPTIONS |
ACI | Silent Spring | |
child_process.spawn | shell ; env |
ACI | Silent Spring | |
child_process.spawn | shell ; input |
ACI | Silent Spring | |
child_process.spawnSync | shell ; NODE_OPTIONS |
ACI | Silent Spring | |
child_process.spawnSync | shell ; env |
ACI | Michał Bentkowski and Silent Spring | |
child_process.spawnSync | shell ; input |
ACI | Silent Spring | |
fetch | method ; body ; referrer |
Privilege Escalation | GHunter | |
fetch | socketPath |
SSRF | GHunter | |
http.get | hostname , headers , method , path , port |
SSRF | GHunter | |
http.request | hostname , headers , method , path , port |
SSRF | GHunter | |
http.Server.listen | backlog |
Segfault | GHunter | |
https.get | hostname , headers , method , path , port , NODE_TLS_REJECT_UNAUTHORIZED |
SSRF | GHunter | |
https.request | hostname , headers , method , path , port , NODE_TLS_REJECT_UNAUTHORIZED |
SSRF | GHunter | |
import | source |
ACE | GHunter | |
tls.connect | path , port , NODE_TLS_REJECT_UNAUTHORIZED |
Second order SSRF | GHunter | |
require | main ; NODE_OPTIONS |
ACI | main property in package.json of the loaded package |
Silent Spring |
require | main ; NODE_OPTIONS |
ACI | package.json in the directory from the argument |
GHunter |
Worker.constructor | argv , env , eval |
Second order ACE and env injection | GHunter |
Function | Polluted Properties | Type | Notes | Found by |
---|---|---|---|---|
fetch | body ; headers ; method ; 0 |
Server Side Request Forgery | Limited by network permissions | GHunter |
Worker | env |
Privilege Escalation | Limited by parent process permissions | GHunter |
Worker | ffi |
Privilege Escalation | Limited by parent process permissions | GHunter |
Worker | hrtime |
Privilege Escalation | Limited by parent process permissions | GHunter |
Worker | net |
Privilege Escalation | Limited by parent process permissions | GHunter |
Worker | read |
Privilege Escalation | Limited by parent process permissions | GHunter |
Worker | run |
Privilege Escalation | Limited by parent process permissions | GHunter |
Worker | sys |
Privilege Escalation | Limited by parent process permissions | GHunter |
Worker | write |
Privilege Escalation | Limited by parent process permissions | GHunter |
Deno.makeTempDir | dir |
Path Traversal | Limited by file system permissions | GHunter |
Deno.makeTempDir | prefix |
Path Traversal | Limited by file system permissions* |
GHunter |
Deno.makeTempDirSync | dir |
Path Traversal | Limited by file system permissions | GHunter |
Deno.makeTempDirSync | prefix |
Path Traversal | Limited by file system permissions* |
GHunter |
Deno.makeTempFile | dir |
Path Traversal | Limited by file system permissions | GHunter |
Deno.makeTempFile | prefix |
Path Traversal | Limited by file system permissions* |
GHunter |
Deno.makeTempFileSync | dir |
Path Traversal | Limited by file system permissions | GHunter |
Deno.makeTempFileSync | prefix |
Path Traversal | Limited by file system permissions* |
GHunter |
Deno.mkdir | mode |
Privilege Escalation | options must not be undefined |
GHunter |
Deno.mkdirSync | mode |
Privilege Escalation | options must not be undefined |
GHunter |
Deno.open | append |
Unauthorized Modifications | GHunter | |
Deno.open | mode |
Privilege Escalation | GHunter | |
Deno.open | truncate |
Unauthorized Modifications | GHunter | |
Deno.openSync | append |
Unauthorized Modifications | GHunter | |
Deno.openSync | mode |
Privilege Escalation | GHunter | |
Deno.openSync | truncate |
Unauthorized Modifications | GHunter | |
Deno.writeFile | append |
Unauthorized Modifications | GHunter | |
Deno.writeFile | mode |
Privilege Escalation | Affects new and existing files | GHunter |
Deno.writeFileSync | append |
Unauthorized Modifications | GHunter | |
Deno.writeFileSync | mode |
Privilege Escalation | Affects new and existing files | GHunter |
Deno.writeTextFile | append |
Unauthorized Modifications | GHunter | |
Deno.writeTextFile | mode |
Privilege Escalation | Affects new and existing files | GHunter |
Deno.writeTextFileSync | append |
Unauthorized Modifications | GHunter | |
Deno.writeTextFileSync | mode |
Privilege Escalation | Affects new and existing files | GHunter |
Deno.run | cwd |
Path Traversal | GHunter | |
Deno.run | uid |
Privilege Escalation | unstable option | GHunter |
Deno.run | gid |
Privilege Escalation | unstable option | GHunter |
Deno.Command | cwd |
Path Traversal | GHunter | |
Deno.Command | uid |
Privilege Escalation | GHunter | |
Deno.Command | gid |
Privilege Escalation | GHunter | |
node:child_process.spawn | uid |
Privilege Escalation | GHunter | |
node:child_process.spawn | gid |
Privilege Escalation | GHunter | |
node:child_process.spawn | shell ; env |
Arbitrary Code Execution | Limited by run permissions | GHunter |
node:child_process.spawnSync | shell ; env |
Arbitrary Code Execution | Limited by run permissions | GHunter |
node:child_process.exec | shell ; env |
Arbitrary Code Execution | Limited by run permissions | GHunter |
node:child_process.execSync | shell ; env |
Arbitrary Code Execution | Limited by run permissions | GHunter |
node:child_process.execFileSync | shell ; env |
Arbitrary Code Execution | Limited by run permissions | GHunter |
node:fs.appendFile | length |
Hanging | Can't be prevented (not an option) | GHunter |
node:fs.appendFile | offset |
Out of Memory | Can't be prevented (not an option) | GHunter |
node:fs.writeFile | length |
Hanging | Can't be prevented (not an option) | GHunter |
node:fs.writeFile | offset |
Out of Memory | Can't be prevented (not an option) | GHunter |
node:http.request | hostname ; method ; path ; port |
Server Side Request Forgery | Limited by network permissions | GHunter |
node:https.request | hostname ; method ; path ; port |
Server Side Request Forgery | Limited by network permissions | GHunter |
node:zlib.createBrotliCompress | params |
Panic | GHunter | |
json.JsonStringifyStream | prefix |
Unauthorized Modifications | GHunter | |
json.JsonStringifyStream | suffix |
Unauthorized Modifications | GHunter | |
log.FileHandler | formatter |
Log Pollution | GHunter | |
dotenv.load | any | Env injection | GHunter | |
dotenv.load | defaultsPath |
Env injection | GHunter | |
dotenv.load | envPath |
Env injection | GHunter | |
dotenv.load | export |
Env injection | GHunter | |
dotenv.loadSync | any | Env injection | GHunter | |
dotenv.loadSync | defaultsPath |
Env injection | GHunter | |
dotenv.loadSync | envPath |
Env injection | GHunter | |
dotenv.loadSync | export |
Env injection | GHunter | |
tar.Tar.append | uid |
Privilege Escalation | GHunter | |
tar.Tar.append | gid |
Privilege Escalation | GHunter | |
yaml.stringify | indent |
Out of Memory | GHunter |
*
: This was not the case prior to Deno v1.41.1, see CVE-2024-27931
.
Package | Version | Function | Polluted Properties | Type | Found by |
---|---|---|---|---|---|
asyncawait | 3.0.0 | require | shell ; NODE_OPTIONS |
ACI | Dasty |
better-queue | 3.8.12 | push | store |
LFI* | Dasty |
binary-parser | 2.2.1 | parse | alias |
ACE | Dasty |
bson | 4.7.2 | deserialize | evalFunctions |
ACE | Silent Spring |
chrome-launcher | 0.15.2 | launch | shell ; NODE_OPTIONS |
ACI | Dasty |
coffee | 5.5.0 | fork | env |
ACI | Dasty |
coffee | 5.5.0 | spawn | shell ; env |
ACI | Dasty |
crawler | 1.4.0 | queue | repo |
LFI* | Dasty |
cross-port-killer | 1.4.0 | kill | shell ; env |
ACI | Dasty |
cross-spawn | 7.0.3 | spawn | shell ; NODE_OPTIONS |
ACI | Dasty |
cross-spawn | 7.0.3 | spawn.sync | shell ; NODE_OPTIONS |
ACI | Dasty |
csv-write-stream | 2.0.0 | end | separator |
ACE | Dasty |
dockerfile_lint | 0.3.4 | DockerFileValidator | arrays.regex |
ACE | Dasty |
download-git-repo | 3.0.2 | download-git-repo | clone ; GIT_SSH_COMMAND |
ACI | Dasty |
dtrace-provider | 0.8.5 | require | any | LFI* | Dasty |
ejs | 3.1.9 | render | client ; escapeFunction |
ACE | Dasty |
esformatter | 0.11.3 | format | plugins |
LFI | Dasty |
exec | 0.2.1 | exec | shell |
ACI | Dasty |
external-editor | 3.1.0 | edit | shell ; NODE_OPTIONS |
ACI | Dasty |
external-editor | 3.1.0 | editAsync | shell ; NODE_OPTIONS |
ACI | Dasty |
fibers | 5.0.3 | require | shell ; NODE_OPTIONS |
ACI | Dasty |
find-process | 1.4.7 | find-process | shell ; NODE_OPTIONS |
ACI* | Dasty |
fluent-ffmpeg | 2.1.2 | preset | presets |
LFI* | Dasty |
forever-monitor | 3.0.3 | start | command |
ACI | Dasty |
gh-pages | 5.0.0 | publish | shell ; NODE_OPTIONS |
ACI | Dasty |
gift | 0.10.2 | clone | shell ; NODE_OPTIONS |
ACI | Dasty |
git-clone | 0.2.0 | git-clone | GIT_SSH_COMMAND |
ACI | Dasty |
gm | 1.25.0 | gm | appPath |
ACI | Dasty |
growl | 1.10.5 | growl | exec |
ACI | Dasty |
handlebars | 4.5.2 | ret |
type ;body |
ACE | |
hbsfy | 2.8.1 | configure | p |
LFI | Dasty |
hbsfy | 2.8.1 | compile | p |
LFI | Dasty |
jsdoc-api | 8.0.0 | explain | NODE_OPTIONS |
ACI | Dasty |
jsdoc-api | 8.0.0 | explainSync | env.NODE_OPTIONS |
ACI | Dasty |
jsdoc-api | 8.0.0 | renderSync | NODE_OPTIONS |
ACI | Dasty |
jsdoc-to-markdown | 8.0.0 | render | NODE_OPTIONS ; source |
ACI | Dasty |
jsdoc-to-markdown | 8.0.0 | renderSync | NODE_OPTIONS ; source |
ACI | Dasty |
liftoff | 4.0.0 | prepare | env.NODE_OPTIONS |
ACI | Dasty |
lodash.template | 4.5.0 | lodash.template | sourceURL |
ACE | Alex Brasetvik |
mrm-core | 7.1.14 | install | shell ; env.NODE_OPTIONS |
ACI | Dasty |
nodemailer | 6.9.1 | sendMail | sendmail ; path ; args |
ACI | Dasty |
ping | 0.4.4 | sys.probe | shell |
ACI | Dasty |
play-sound | 1.1.5 | play-sound | players |
ACI | Dasty |
play-sound | 1.1.5 | play | player ; env.NODE_OPTIONS |
ACI | Dasty |
primus | 8.0.7 | parser | parser ; value |
LFI | Dasty |
primus | 8.0.7 | transformer | transformer ; value |
LFI | Dasty |
pug | all versions | Template |
block |
ACE | |
python-shell | 5.0.0 | runString | pythonPath ; NODE_OPTIONS |
ACI | Dasty |
require-from-string | 2.0.2 | require-from-string | prependPaths |
LFI* | Dasty |
requireg | 0.2.2 | resolve | shell ; env.NODE_OPTIONS |
ACI | Dasty |
sonarqube-scanner | 3.0.1 | sonarqube-scanner | version |
ACI | Dasty |
teen_process | 2.0.4 | start | shell ; env.NODE_OPTIONS |
ACI | Dasty |
the-script-jsdoc | 2.0.4 | the-script-jsdoc | shell ; env.NODE_OPTIONS |
ACI | Dasty |
tingodb | 0.6.1 | findOne | _sub |
ACE | Dasty |
window-size | 1.1.1 | tput | shell ; NODE_OPTIONS |
ACI | Dasty |
winreg | 1.2.4 | values | shell ; NODE_OPTIONS |
ACI | Dasty |
workerpool | 6.4.0 | exec | env.NODE_OPTIONS |
ACI | Dasty |
*
: denotes the gadgets that require the attacker’s control of a local file for
arbitrary code execution.
Vulnerability Report | Application | Version | Attack | Gadget |
---|---|---|---|---|
CVE-2019-7609 | Kibana | 6.6.0 | RCE | child_process.spawn.lnx |
HackerOne #852613 | Kibana | 7.6.2 | RCE | lodash.template |
HackerOne #861744 | Kibana | 7.7.0 | RCE | lodash.template |
Reported by Silent Spring | npm cli | 8.1.0 | RCE | child_process.spawn |
CVE-2022-24760 | Parse Server | 4.10.6 | RCE | bson |
CVE-2022-39396 | Parse Server | 5.3.1 | RCE | bson |
CVE-2022-41878 | Parse Server | 5.3.1 | RCE | bson |
CVE-2022-41879 | Parse Server | 5.3.1 | RCE | bson |
Reported by Silent Spring | Parse Server | 5.3.1 | RCE | require #1 |
CVE-2023-23917 | Rocket.Chat | 5.1.5 | RCE | bson |
CVE-2023-31414 | Kibana | 8.7.0 | RCE | require #2 |
CVE-2023-31415 | Kibana | 8.7.0 | RCE | nodemailer |
CVE-2023-36475 | Parse Server | 6.2.1 | RCE | bson |