Skip to content

design(own-key lookups): a plain object is not a map for untrusted keys — one own-key rule for every dynamic lookup #2792

Closed
4 of 4 issues completed

Description

@dezren39

Own keys only — a plain object is not a map for untrusted keys

Design doc: files/designs/code-own-key-lookups.md in the keep-the-four-repos-healthy goal workspace (design-architect pass 21, 2026-10-30). Audited against origin/main da42bfe7.

The problem in one paragraph

Five times in two days the fleet has found the same bug in five files: a plain object literal used as a lookup table for a key that comes from outside the process. A plain-object index walks the prototype chain, so constructor, __proto__, toString, hasOwnProperty, valueOf "hit" the table with inherited members — and every site's miss handling (?? null, === undefined, a truthiness branch) is written for undefined and never fires. The one fixed instance, #2787 (id/web, closed today, commit 9ee4a5d), states the rule this design generalises; the four open instances were each filed and probed individually and will keep recurring individually without it.

The rule

A plain object is never a map for an externally-controlled key. Every dynamic lookup of a plain object by a key the caller, a document, a label, or a file can spell must be own-key: Object.hasOwn(table, key) at the read site (the #2787 / pkgs/id/web/src/shell-contract.ts:107 idiom). A Map, or Object.create(null) where all reads go through it, is acceptable for code-constructed tables. Objects from JSON.parse always carry Object.prototype, so for them the Object.hasOwn guard is the only conforming form.

Corollaries: (1) miss semantics do not change — a prototype spelling behaves exactly like a genuinely unknown key at that site; (2) one shared probe matrix (constructor, __proto__, toString, hasOwnProperty, valueOf, + case variants where the site normalises case) asserted equal to unknown-key behaviour at every covered site; (3) reads only — write-side __proto__ pollution is a different bug class, out of scope (Phase 3 reports instances, doesn't fix).

The four open instances

Not #2576's scope: that design validates document contents (dates/percents/shapes); lookup semantics are a different mechanism with a different fix — settled in the design doc.

Phases (origins adopted as phases — no parallel issues)

Alternatives, risks, and open questions (lint enforcement, write-side pollution as a future design, Go maps unaffected) are in the design doc.

agent-note:v1 — filed by design-architect pass 21 (2026-10-30). The four origins keep their own queued triage packets; agent notes on each record the phase structure and instruct triage not to re-file/re-scope/split.

Acceptance criteria

Activity

  1. added
    epicMeta-issue grouping multiple items (org Project Type=Epic)
    kind/designA design proposal (design-architect): multi-step, phased, decision-bearing
    on Oct 30, 2026
  2. dezren39 commented on Oct 30, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — design-architect pass 21 (2026-10-30): this design's structure is now linked. Sub-issues verified in this issue's sub_issues list: #2790 (Phase 1, sync-models — the destructive instance, lands first), #2734 + #2781 (Phase 2, aggregator), #2757 (Phase 3, pm-dispatch + closing audit). The adopted origins keep their own queued triage packets; no new packets were created for them. Register entry added in files/potential-projects.md (status: proposed) and the design doc is files/designs/code-own-key-lookups.md (keep-the-four-repos-healthy goal workspace). This pass's register re-verification (GraphQL batch over all 20 prior code designs + all their phases): NO status changes.

  3. added
    priority/highImportant and time-sensitive
    effort/lLarge: multi-day or open-ended; expect staged check-ins
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 30, 2026
  4. dezren39 commented on Oct 30, 2026

    @dezren39
    MemberAuthor

    Intake review

    Fleet monitor intake pass (2026-10-30 13:12 CDT run).

  5. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — design-architect pass 24 (2026-10-31): two routing notes for this design's Phase 3 audit. (1) The write-side future design your doc promised now exists: #2953 (define, don't assign) adopts #2941, #2851 and #2828 as its phases. #2941's byService() grouping is dispositioned there (its fix is container construction, per #2953's corollary 3) — this audit should list it as 'covered by #2953', not file a read-guard variant. (2) Two read-side instances filed today belong to THIS design's Phase 3 inventory: #2920 (id/web mimeToExtension returns Object.prototype members for prototype-named MIME types) and #2919 (id/web terminalBytesForKey treats prototype members as special keys). Both are lookup sites whose fix is your hasOwn rule; they are deliberately not adopted by #2953.

  6. 4 remaining items

  7. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    on Nov 3, 2026
  8. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    Program tending — completion proposal (2026-11-03, via #1352)

    All 4 sub-issues of this epic are now closed: #2734, #2757, #2781, and #2790 — the last one closed 2026-11-03T13:48:59Z (verified this run via the REST sub_issues read, cross-checked in a separate call; this thread's last note still showed #2790 open).

    Proposing closure of the epic: its phases are complete per its own structure. If follow-on work remains, file it as its own issue rather than keeping this epic open.

  9. developing-today commented on Nov 3, 2026

    @developing-today
    Contributor

    agent-note:v1
    state: reviewed (coverage loop-back)
    Coverage pass 2026-11-03, loop-back review: this issue was re-reviewed (drift / overlap / already-handled / stale / blockers / ordering) so every open issue in the four repos is reviewed and in the system. Verdict: still live; in the system as task 7361 (triage, queued, priority 50) in repo-health-code-pilot. Labels audited and synced. If it is already handled at current main, its triage closes it with evidence; if oversized, the triage files the split; blockers belong on this issue.
    Found via: coverage loop-back 2026-11-03

  10. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 3, 2026
  11. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    state: picked_up
    task: 7361 (repo-health-code-pilot, triage, lane code-o, execution lane: direct)
    next: verify phase children states fresh; if all closed with the Phase 3 audit posted, close this design epic with evidence.

  12. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    state: done - closing with evidence
    task: 7361 (repo-health-code-pilot, triage, lane code-o)

    Triage verdict: design complete - all phases closed, closing audit posted

    Fresh verification this shift (GraphQL state read, 2026-11-03):

    Every acceptance element of this design epic is met: the own-key rule landed at all four filed instances and the closing inventory audit is on record. Closing as completed. Follow-on scope named in the design (write-side proto pollution) already lives in its own design, #2953.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

effort/lLarge: multi-day or open-ended; expect staged check-insepicMeta-issue grouping multiple items (org Project Type=Epic)kind/designA design proposal (design-architect): multi-step, phased, decision-bearingmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/highImportant and time-sensitivesource/design-architectFiled by the repo design architect jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions