Summary
Merge() in @11ty/eleventy-utils ≤ 2.0.7 is vulnerable to prototype pollution. A _data/*.json file containing {"__proto__": {...}} pollutes Object.prototype in the Node.js build process, causing TransformsUtil.changeTransformsToArray() to crash the entire build (DoS).
Root Cause
getMergedItem() in Merge.js uses for (let key in source) + bracket assignment without guarding __proto__. Additionally, isPlainObject(Object.prototype) === true causes recursion into Object.prototype.
Proof of Concept
echo '{"__proto__": {"x_pwned": true}}' > _data/config.json
npx @11ty/eleventy@3.0.0
# → TypeError: callback.call is not a function → BUILD CRASHES
Direct Node.js confirmation:
const { Merge } = require('@11ty/eleventy-utils');
Merge({}, JSON.parse('{"__proto__":{"polluted":"HACKED"}}'));
console.log({}.polluted); // "HACKED"
Impact
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:N/A:H (6.5 Medium, CWE-1321)
Any contributor who can add a .json file to _data/ can crash the build. Affects multi-author Eleventy/buildawesome setups, PR-based CI/CD pipelines, and CMS integrations.
Fix
In @11ty/eleventy-utils/src/Merge.js:
const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
for (let key in source) {
if (UNSAFE_KEYS.has(key)) continue; // ADD THIS
// ...
}
Also in IsPlainObject.js: explicitly return false for Object.prototype itself.
Summary
Merge()in@11ty/eleventy-utils≤ 2.0.7 is vulnerable to prototype pollution. A_data/*.jsonfile containing{"__proto__": {...}}pollutesObject.prototypein the Node.js build process, causingTransformsUtil.changeTransformsToArray()to crash the entire build (DoS).Root Cause
getMergedItem()inMerge.jsusesfor (let key in source)+ bracket assignment without guarding__proto__. Additionally,isPlainObject(Object.prototype) === truecauses recursion intoObject.prototype.Proof of Concept
Direct Node.js confirmation:
Impact
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:N/A:H (6.5 Medium, CWE-1321)
Any contributor who can add a
.jsonfile to_data/can crash the build. Affects multi-author Eleventy/buildawesome setups, PR-based CI/CD pipelines, and CMS integrations.Fix
In
@11ty/eleventy-utils/src/Merge.js:Also in
IsPlainObject.js: explicitly returnfalseforObject.prototypeitself.