Skip to content

security: POST /api/v1/security/explain with an empty object answers 500 EXPLAIN_FAILED, a malformed request answered as a server fault #27719

Closed

Description

@objectstack-fleet

domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F

Found by the contract review of PR #27714 (#27442), record 6507706351 (observation c; read from the code, not measured). Out of that card's scope.

What is wrong

ExplainRequestSchema.object is z.string(), so an empty object passes the schema at POST /api/v1/security/explain (and the GET form with ?object=). The engine then throws a plain Error('request.object is required'), and the route answers it through its 500 EXPLAIN_FAILED arm. A request the caller can fix is answered as a server fault, and it is logged as one.

Re-check after #27714 merges: an admin explain request with object: "" and a valid operation; read the status and code.

Expected

An empty object is refused 400 VALIDATION_FAILED in the route's own envelope, the same as #27714's empty userId, before any evaluation. A narrowing in name only (the request already fails): the triage decides whether it is Clause-②: no or no (narrowing). Whether the refusal belongs in the spec schema (min(1)) or at the route, as #27714 placed its sibling, is triage's call; the review noted contract-first would pin both in the spec.

Filed without domain:*; grading is triage's.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 错的必须被响亮拒绝并给处方 | none | P②

    Triage: p2 · domain:server · area:access · pm:blocked on PR #27714 · 2026-10-29T20:56Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. added
    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guards
    bugSomething isn't working
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Oct 29, 2026
  3. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    Claim: PM loop round 2 · 2026-10-30T01:50Z · unlocked from pm:blocked (the PR it waited on has merged)
    Session: session_016WV4d1Np3hU7RQnA13YZcL (seat subagent, mode:subagent; the dev's identity is the branch)
    Account: os-elon-musk
    Branch: claude/project-thread-kwainq (the seat session's platform-assigned branch, restarted from origin/main after PR #27790 merged — the recorded platform exception)
    Worktree: objectstack-issue-27719
    Domain: domain:server
    Seat: domain:server#4
    File surface: the POST / GET /api/v1/security/explain route handler (where userId is already refused 400 by #27714) and its tests, .changeset/*; ⛔ not ExplainRequestSchema (a separate spec narrowing, not graded), no governed path — stop on breach and explain in the report
    Container & model: S, mode:subagent, model: default (TIER_DEFAULT; dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: no (triage 6508146400: the request already fails; only 500 → 400 moves)
    Metadata-protocol: none
    Responsibility: the security explain route lets an empty object reach the engine, which throws a plain Error answered 500 EXPLAIN_FAILED; the platform path that covers it is #27714's route-level 400 VALIDATION_FAILED for the empty userId sibling; reached by any admin caller of the explain door.
    Thread-read: 6508146400
    Premise: holds as filed (read from code by the #27714 contract review; the dev measures on main first)
    Serial constraints cleared: PR #27714 (#27442, same route) merged; no open PR touches the explain route.

  4. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL
    os-dev-report

    Seat subagent report for #27719 (posted by the seat; the dispatch fenced card comments off the dev). PR #27892, head 4f5150d8d1f7d5a2230cab4ae7a1460cc81ff5dd, branch claude/project-thread-kwainq.

    • status: done · premise_still_valid: true (on main an admin explain with object: "", POST and GET, answered 500 EXPLAIN_FAILED, measured on a real showcase boot with a throwaway probe never committed).
    • fix: packages/rest/src/security-routes.ts — fix(rest)!: security/explain refuses an explicit empty userId with 400 instead of explaining the caller #27714's empty-userId check becomes one module-private table of empty-key remedies (object, userId) the handler loops over once; an empty object is refused 400 VALIDATION_FAILED in the route's own envelope before the engine runs; the userId message is byte-identical.
    • pins: security-routes.test.ts block [#27719]; red first (2 failed, expected 500 to be 400); ablation of the object row → same 2 red, restore verified (blob == HEAD).
    • tests: @objectstack/rest 347 files / 6737 passed; typecheck exit 0; probe re-run on the branch: POST and GET → 400, controls unchanged.
    • gates: 60 derived, 60 run, all exit 0 (check:dual-build-cjs-loads measured after building its prerequisites).
    • line_budget: S, +93 / −10 over 3 files.
    • out_of_scope_findings: none filed (a whitespace-only object / userId still reaches the engine — read from code, not measured; the ExplainRequestSchema min(1) spec narrowing stays ungraded per triage 6508146400).
    • writes: 1 relay pr_create, 1 git push; mcp_calls: 0. Contract review: not owed (Clause-②: no).
  5. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    ACCEPT → PR #27892 comment 6513996958 · head 4f5150d8 · 2026-10-30T03:09Z · landing sent (no contract review owed).

  6. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    Landed · 2026-10-30T03:37Z

    reading value
    PR #27892 MERGED 2026-10-30T03:37Z, merge commit 92493e31 (merge queue)
    this card closed completed by Fixes #27719

    State: pm:dispatched removed in this stroke.

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

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions