Context
Reviewing PR #17513 against its close target #17512 falsified the proposed dismissal premise. The exact Neo.merge implementation is part of Neo's default public export, and an independent runtime probe showed that a JSON-parsed __proto__ key reaches shared prototype state.
Live latest-open sweep: checked the latest 20 open issues and the 30 most recent all-state A2A messages at 2026-08-22T00:34:00.864Z; no equivalent successor or in-flight claim was found. The existing #17512 is the premise being superseded, not a duplicate implementation ticket.
The Problem
Neo.merge(target, source, defaults) recursively enumerates source with for…in, reads target[key], and writes back through that reference. For a source created by JSON.parse, __proto__ is an own enumerable key. Reading the matching property from a normal target reaches Object.prototype; the recursive write then mutates shared prototype state.
Exact falsifier against the implementation reviewed at PR #17513 (its src/Neo.mjs delta is comment-only):
const source = JSON.parse('{"__proto__":{"neo17513Probe":"reached"}}');
Neo.merge({}, source);
Object.hasOwn(Object.prototype, 'neo17513Probe'); The probe was process-local and removed its sentinel after observation. This is a public-API reachability failure: enumerating only repository-internal callers cannot prove safety for application-defined consumers. The claimed 19-call census in #17512 also counted four static issue-archive strings as calls; excluding those archives yields 16 direct call expressions.
CodeQL alerts 62 and 63 therefore describe a real reachable behavior. Dismissing them as safe would encode a false security decision rather than resolve the defect.
The Architectural Reality
src/Neo.mjs owns the public Neo.merge primitive and exports the containing Neo object as the module default.
- The hazardous traversal is centralized inside
Neo.merge; fixing individual internal callers would leave the public contract unsafe.
src/worker/Base.mjs also feeds worker-message data / config objects into Neo.merge, reinforcing that the boundary must defend itself rather than rely on a repository call census.
- GitHub's current code-scanning REST contract accepts
false positive, won't fix, or used in tests; it does not accept the proposed used in a safe context. It also stores dismissed_comment, so repository documentation must not pretend the alert lacks durable reasoning.
The Fix
Harden Neo.merge at the public boundary so source keys cannot traverse or replace prototype-chain state. Preserve existing safe deep-merge and defaults behavior, and add a permanent RED-to-GREEN unit witness covering parsed JSON at the public API.
Do not add a dismissal ledger entry for alerts 62/63. Once the hardened implementation lands on dev, let CodeQL resolve the alerts as fixed.
Contract Ledger
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
Neo.merge(target, source, defaults) |
src/Neo.mjs public method |
Safe keys retain current recursive/default merge semantics; prototype-chain traversal keys cannot mutate global or target prototype state |
No caller-side sanitizer; the primitive defends its own boundary |
Update JSDoc only if the chosen ignore/reject behavior changes caller-visible semantics |
Exact public-API parsed-JSON RED/GREEN unit proof |
| Global prototype integrity |
JavaScript object model + CodeQL alerts 62/63 |
A merge cannot add properties to Object.prototype or replace a normal target's prototype |
Fail closed for hazardous keys |
N/A |
Assert both prototype identity and sentinel absence after nested and defaults-path probes |
Decision Record impact: none — localized security hardening of an existing core public utility; no accepted ADR is changed.
Acceptance Criteria
Out of Scope
- A global CodeQL query exclusion or
paths-ignore entry.
- A general-purpose object sanitizer outside
Neo.merge.
- Unrelated
mergeFrom / config-descriptor behavior.
- Dismissing alerts 62/63.
Avoided Traps
Repository-call census as a public-API security proof. Internal callers cannot bound downstream application input.
Documenting acceptance before falsifying reachability. The exact runtime probe is the authority; prose and green CI cannot overrule it.
Fixing the alerts instead of the primitive. A dismissal or workflow exclusion would preserve the reachable mutation.
Related
- Supersedes the prescription in #17512 and PR #17513.
- Same CodeQL rule, different earlier defect: #17494 / PR #17496.
- Live alerts: 62 and 63.
Origin Session ID: bbd4f722-ca03-4269-a88e-29555b12b9f9
Retrieval Hint: Neo.merge parsed JSON __proto__ CodeQL alerts 62 63 PR 17513 Drop Supersede
Context
Reviewing PR #17513 against its close target #17512 falsified the proposed dismissal premise. The exact
Neo.mergeimplementation is part of Neo's default public export, and an independent runtime probe showed that a JSON-parsed__proto__key reaches shared prototype state.Live latest-open sweep: checked the latest 20 open issues and the 30 most recent all-state A2A messages at 2026-08-22T00:34:00.864Z; no equivalent successor or in-flight claim was found. The existing #17512 is the premise being superseded, not a duplicate implementation ticket.
The Problem
Neo.merge(target, source, defaults)recursively enumeratessourcewithfor…in, readstarget[key], and writes back through that reference. For a source created byJSON.parse,__proto__is an own enumerable key. Reading the matching property from a normal target reachesObject.prototype; the recursive write then mutates shared prototype state.Exact falsifier against the implementation reviewed at PR #17513 (its
src/Neo.mjsdelta is comment-only):const source = JSON.parse('{"__proto__":{"neo17513Probe":"reached"}}'); Neo.merge({}, source); Object.hasOwn(Object.prototype, 'neo17513Probe'); // trueThe probe was process-local and removed its sentinel after observation. This is a public-API reachability failure: enumerating only repository-internal callers cannot prove safety for application-defined consumers. The claimed 19-call census in #17512 also counted four static issue-archive strings as calls; excluding those archives yields 16 direct call expressions.
CodeQL alerts 62 and 63 therefore describe a real reachable behavior. Dismissing them as safe would encode a false security decision rather than resolve the defect.
The Architectural Reality
src/Neo.mjsowns the publicNeo.mergeprimitive and exports the containingNeoobject as the module default.Neo.merge; fixing individual internal callers would leave the public contract unsafe.src/worker/Base.mjsalso feeds worker-messagedata/configobjects intoNeo.merge, reinforcing that the boundary must defend itself rather than rely on a repository call census.false positive,won't fix, orused in tests; it does not accept the proposedused in a safe context. It also storesdismissed_comment, so repository documentation must not pretend the alert lacks durable reasoning.The Fix
Harden
Neo.mergeat the public boundary so source keys cannot traverse or replace prototype-chain state. Preserve existing safe deep-merge and defaults behavior, and add a permanent RED-to-GREEN unit witness covering parsed JSON at the public API.Do not add a dismissal ledger entry for alerts 62/63. Once the hardened implementation lands on
dev, let CodeQL resolve the alerts as fixed.Contract Ledger
Neo.merge(target, source, defaults)src/Neo.mjspublic methodObject.prototypeor replace a normal target's prototypeDecision Record impact: none — localized security hardening of an existing core public utility; no accepted ADR is changed.
Acceptance Criteria
__proto__payload is RED on pre-fixdevand GREEN at the PR head.Neo.mergecannot mutateObject.prototypeor replace a normal target's prototype throughsourceordefaults, including nested payloads.dev; if they remain open, create a new successor ticket rather than reopening this resolved one.Out of Scope
paths-ignoreentry.Neo.merge.mergeFrom/ config-descriptor behavior.Avoided Traps
Repository-call census as a public-API security proof. Internal callers cannot bound downstream application input.
Documenting acceptance before falsifying reachability. The exact runtime probe is the authority; prose and green CI cannot overrule it.
Fixing the alerts instead of the primitive. A dismissal or workflow exclusion would preserve the reachable mutation.
Related
Origin Session ID: bbd4f722-ca03-4269-a88e-29555b12b9f9
Retrieval Hint:
Neo.merge parsed JSON __proto__ CodeQL alerts 62 63 PR 17513 Drop Supersede