Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,37 @@ for (const key of envKeys) {

Check that code you can see it's possible en **poison `envPairs`** just by **polluting** the **attribute `.env`.**

### Dynamic-key grouping (`??=`) to Git SSH RCE

When auditing object-building code, look beyond recursive merge functions for grouping patterns that use untrusted strings as keys on ordinary objects. If both keys and the value are attacker-controlled, the following pattern is a direct pollution source:<sup>[[9]](#references)[[10]](#references)</sup>

```javascript
const grouped = {}

for (const { groupKey, fieldKey, value } of userFields) {
grouped[groupKey] ??= {}
grouped[groupKey][fieldKey] = value
}
```

With `groupKey = "__proto__"`, the first lookup invokes the inherited `__proto__` getter and returns `Object.prototype`. Because that value is not nullish, `??=` does not create an own property; the next statement becomes `Object.prototype[fieldKey] = value`. The mutation remains even if later validation, an API call, or the surrounding workflow step fails, so inspect side effects that occur before error-prone operations.<sup>[[9]](#references)</sup>

A useful external-process gadget is **Git over SSH**. In the demonstrated n8n chain, polluting `GIT_SSH_COMMAND` was inherited by a plain environment object created through `simple-git`, propagated to the spawned Git process, and interpreted by Git through the shell when cloning an SSH-style remote. The exact child-process/library path is version-dependent: exploitation requires the inherited enumerable property to be copied into the child environment and no own property to shadow it.<sup>[[9]](#references)[[11]](#references)</sup>

```json
{
"groupKey": "__proto__",
"fieldKey": "GIT_SSH_COMMAND",
"value": "sh -c 'id > /tmp/pp-git' --"
}
```

Therefore, search for a three-stage chain: **dynamic-key pollution → plain environment map → Git operation using an SSH remote**. The pollution-producing operation does not need to finish successfully if the prototype write happens first.<sup>[[9]](#references)</sup>

This source can also cause process-wide denial of service without an RCE gadget. A later `for...in` loop enumerates inherited enumerable keys; in the documented case, TypeORM treated the polluted name as an entity field and repeatedly threw `EntityPropertyNotFoundError` until the Node.js process was restarted.<sup>[[9]](#references)</sup>

For dictionary-like data, use `Object.create(null)`, validate every path component against `__proto__`, `constructor`, and `prototype`, and iterate only own keys (`Object.keys()` or an `Object.hasOwn()` check). Build child environments from explicit own properties rather than inheriting from application objects.<sup>[[9]](#references)[[10]](#references)</sup>

### **Poisoning `__proto__`**

> [!WARNING]
Expand Down Expand Up @@ -780,5 +811,8 @@ Additional gadget collections and CTF examples can help identify application-spe
- [6] [Exploiting prototype pollution in Node without the filesystem](https://portswigger.net/research/exploiting-prototype-pollution-in-node-without-the-filesystem)
- [7] [Uncovering a Prototype Pollution Regression in Node.js (archived)](https://web.archive.org/web/20250130155632id_/https://dzone.com/articles/uncovering-prototype-pollution-regression)
- [8] [Summary of CTF Web Frontend and JS Challenges in 2022](https://blog.huli.tw/2022/12/26/en/ctf-2022-web-js-summary/)
- [9] [n8n GSuiteAdmin Prototype Pollution to Remote Code Execution](https://simonkoeck.com/writeups/n8n-gsuiteadmin-prototype-pollution-rce)
- [10] [Prototype Pollution in GSuiteAdmin node parameters leads to RCE - n8n Security Advisory](https://github.com/n8n-io/n8n/security/advisories/GHSA-mxrg-77hm-89hv)
- [11] [Git environment variables - `GIT_SSH_COMMAND`](https://git-scm.com/docs/git#Documentation/git.txt-codeGITSSHCOMMANDcode)

{{#include ../../../banners/hacktricks-training.md}}