Skip to content

Security: Prototype Pollution in Merge() via __proto__ key in JSON data — Build DoS #8

Description

@alanturing881

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions