GHSA-MHWJ-73QX-JQXM: Root-cause fix for deepMerge() prototype pollution
Summary
Version 1.0.1 addresses prototype pollution in deepMerge() by rejecting dangerous property names during recursive merge. The patch directly targets the pollution primitive described in the advisory and expands protection beyond __proto__ to constructor and prototype.
Analysis
Vulnerability
GHSA-MHWJ-73QX-JQXM describes a prototype pollution issue in @theecryptochad/merge-guard v1.0.0. The vulnerable behavior is in deepMerge(), where attacker-controlled object keys are merged without validating special property names. A crafted JSON payload containing __proto__ can mutate Object.prototype, which can in turn alter application behavior globally. The advisory states that the issue is fixed in v1.0.1 by adding a restricted key denylist.
This is a classic unsafe recursive merge pattern: if merge logic traverses arbitrary keys and writes them into target objects, meta-properties such as __proto__, constructor, and prototype can redirect writes into prototype chains rather than ordinary data fields. That makes the root cause insufficient key validation on untrusted input before property assignment.
Patch
The patch in the upstream commit 25e4b4f2618578a656ef3cb4946a1b475f736736 introduces a denylist of dangerous keys and skips them during merge. The package version is also bumped from 1.0.0 to 1.0.1.
const BLOCKED_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
if (BLOCKED_KEYS.has(key)) continue; // CVE fix: block prototype pollution keysTechnically, this changes the merge semantics from accepting all enumerable keys to rejecting known prototype-manipulation primitives. The inclusion of constructor and prototype is important because it broadens coverage beyond the specific __proto__ payload called out in the advisory and addresses common alternate gadget paths used in JavaScript prototype pollution exploitation.
Review
Pros
The patch is tightly aligned with the documented vulnerability in the advisory. It blocks the exact attacker-controlled keys that enable prototype chain mutation in recursive merge code. The implementation is low-risk and minimally invasive: a constant denylist plus an early continue avoids changing unrelated merge behavior. Adding constructor and prototype in addition to __proto__ is a strong engineering choice because it addresses the broader class of prototype pollution entry points rather than only the reported proof-of-concept.
From a maintenance perspective, the patch is easy to audit. The security control is explicit, local to the merge loop, and visible in a single guard. The version bump to 1.0.1 in the same change set also clearly marks the security release boundary.
Cons
The fix uses a denylist, which is effective for the known dangerous keys shown in the sources but is still a narrower strategy than structural hardening. Without the full function context in the provided diff, it is not possible to verify whether all write paths in deepMerge() pass through this guard, whether inherited properties are excluded, or whether object creation semantics avoid prototype-bearing containers entirely. A more defensive design would also consider using objects with null prototypes for merge targets where appropriate, or constraining mergeable input types.
The provided patch summary does not show accompanying regression tests. For a vulnerability in recursive merge logic, tests should cover direct and nested payloads for __proto__, constructor.prototype, and benign keys to confirm both security coverage and compatibility.
Verdict
Root-cause.
Based on the available sources, the patch addresses the underlying flaw: unvalidated special keys were allowed to flow into merge assignments. By rejecting the prototype-pollution primitives at merge time, v1.0.1 removes the dangerous input class that caused the vulnerability. While denylist-based defenses are not the most comprehensive possible hardening pattern, this change is source-grounded, directly mapped to the exploit mechanism, and appears sufficient for the reported issue in the fixing commit and the advisory.
Recommended Labs
Try this vulnerability pattern yourself with hands-on labs.
- Merge.js
Best match for this GHSA because it is a JavaScript lab centered on unsafe merge behavior and is tagged with CWE-1321, aligning closely with prototype pollution in a deepMerge()-style function. It should help practice defensive fixes such as blocking dangerous keys like __proto__, constructor, and prototype, and validating recursive merge inputs.
- Property.js
Strong complementary JavaScript lab for understanding how attacker-controlled object properties can lead to pollution-style issues. Its easier difficulty makes it useful for building intuition before or alongside patch review of denylist-based protections in merge logic.
- Pollution.js
Useful adjacent lab for reinforcing broader input validation and object-handling defenses in JavaScript. While not as directly titled around merge operations as Merge.js, it is still relevant hands-on practice for pollution-related defensive coding patterns and defense-in-depth remediation.