Skip to content

own-key audit follow-ups (#2792 Phase 3): unguarded plain-object lookups on data/request-spelled keys in aggregator + bin proxies #3106

Open

Description

@dezren39

Filed by the #2792 Phase 3 closing audit (queue task 4373, 2026-10-31). The audit swept the repo's TS/JS/mjs for plain-object tables indexed by a dynamic key (vendored assets excluded). The sites below are indexed by keys spelled from outside the process — live request input, ingested API/config data, documents, or issue text — with only an undefined / ?? / truthiness miss guard, so a prototype spelling (constructor, __proto__, toString, …) resolves to an inherited member instead of taking the site's miss path. Same class as #2787 / #2734 / #2781 / #2790 / #2757; the fix at each site is the #2792 rule: Object.hasOwn(table, key) at the read site (or a Map / null-prototype table), with the shared probe matrix asserted equal to unknown-key behaviour. Each site is small; they are grouped here because the audit is one pass — split per site if triage prefers.

pm-stack/aggregator — ingested-data keys

  1. src/aa.ts:350 — AA_EFFORT_ORDER[effort.toLowerCase()] ?? 50: effort names from ingested AA data; constructor yields the Object constructor instead of the 50 default (numeric context → NaN risk).
  2. src/aa.ts:859 — AA_PLAN_FACTS[providerId] (used as fact?.note): provider ids from provider config/data; a prototype-spelled id yields a function as the "fact".
  3. src/aa.ts:886 — AA_GO_CAPS[norm] ?? null: normalized provider id, same shape.
  4. src/aa.ts:998 — CAI_CREATORS[slug.toLowerCase()] ?? slug: creator slug from data; prototype spelling yields a function as the creator string.
  5. src/derive.ts:760-761 — PRIORITY_ORDER[(priority ?? "normal").toLowerCase()] ?? 2: priority strings derive from issue/label data; prototype spelling defeats the ?? 2 fallback and poisons the sort comparator with a function (NaN ordering).
  6. src/quota-current.ts:283 — TURSO_WINDOW_META[w.name] guarded by if (!meta …) continue: window names from Turso data; constructor passes the truthiness guard and emits a metric with undefined label/limit/unit. (Sibling of aggregator(quota-gather-map): plain-object lookups return prototype members as window metadata — a window named 'constructor'/'__proto__' gets a fabricated windowSeconds, and a Turso window with such a name fabricates a snapshot record with no unit/limit #2781, different file.)
  7. src/sources/live.ts:127 — KANEO_PROJECT_REPOS[p.slug] ?? fallback: project slugs from the Kaneo API.
  8. src/sources/live.ts:446 — TITLE_REPO_ALIASES[m[1].toLowerCase()]: keys regex-captured from issue titles.
  9. src/quota-extract.ts:367,386 — POOL_DOOR_PROVIDER_ID[poolId] ?? …, POOL_DOOR_PROVIDER_IDS[poolId] ?? …: pool ids from ingested quota data; prototype spelling returns a function where a provider-id string/array is expected.

bin/ proxies — live request / document keys

  1. bin/antigravity-ls-proxy.mjs:125-136 — MODEL_MAP[cand] (?.enum and a direct read): candidate model names from live request traffic.
  2. bin/muse-proxy.mjs:260 — CLI_FLAG_PLAN[sub]: CLI flag tokens spelled by the caller. :1064 DIRECT_TOOL_ALIASES[name], :1068 DIRECT_TOOL_NAMES[name] || name: tool names from client requests — constructor resolves to the Object constructor as a tool name/alias.
  3. bin/opencode-route-proxy.mjs:178 — BUILTIN_PROVIDERS[id] || null (and :169 cfg.providers[def.instanceOf], a JSON.parse'd config object): provider/instance ids from config and requests.
  4. bin/provider-catalog-sync.mjs:364 — BRANDS[tok.toLowerCase()] truthiness return: tokens from catalog documents.

Acceptance

Related: epic #2792 (Phase 3 audit), #2787 (the rule's embodiment). Sites the audit dispositioned internal-only (allowlist-guarded dispatch repo tables, mcpx OPS literals, regex-bounded MONTHS, aggregator render enums, fixture tables) are named in the closing-audit comment on #2792 and are NOT in scope here.

Acceptance criteria

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    priority/normalOrdinary priority (the default)
    on Oct 31, 2026
  2. added
    effort/mMedium: expected under 1 day of work
    app/aggregatorPackage/app: aggregator (pm-stack in this repo)
    source/queue-workerFiled or worked by the queue/worker pilot
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 31, 2026
  3. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    Intake review

    Fleet monitor intake pass (2026-10-31).

    Related: Filed by the #2792 Phase 3 closing audit (queue task 4373); same bug class as #2787 / #2734 / #2781 / #2790 / #2757, rule established by #2792. No merged PR found referencing #3106 — verified live.

    Notes: Well-evidenced as filed (file:line per site, fix shape named). It had kind/priority but no acceptance criteria, effort, or status; now set. Grouped-site filing is reasonable; the body itself offers per-site splitting if triage prefers.

    Risks: Low per site — the miss-path change is the point. The one caution: any site where an inherited-member result is accidentally load-bearing would surface as a behavior change; the probe-matrix tests should catch it.

    Suggested approach: One small-fix pass over the listed sites with the shared probe matrix asserted per site; split per site only if the diff grows.

  4. added
    app/pm-stackpm-stack (Pad/Grist) in developing-today/code
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    on Nov 1, 2026
  5. developing-today commented on Nov 3, 2026

    @developing-today
    Contributor

    agent-note:v1
    state: triaged (coverage pass)
    Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as triage at priority 40 (priority/normal). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
    Found via: coverage pass 2026-11-03

  6. 61 remaining items

  7. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 5, 2026
  8. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  9. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  10. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/aggregatorPackage/app: aggregator (pm-stack in this repo)app/pm-stackpm-stack (Pad/Grist) in developing-today/codeeffort/mMedium: expected under 1 day of workkind/bugSomething isn't working (prefixed form of the classic bug label)meta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)queue/parkedQueue task is parked (waiting on CI, time, or an event)source/queue-workerFiled or worked by the queue/worker pilotstatus/parkedDeliberately paused with a recorded resume conditiontask/small-fixQueue packet kind: bounded fix with reproduction and targeted testswork/assignedQueue worker lifecycle state

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions