Skip to content

security: a session the ADR-0069 auth gate holds can still be served by the storage route family (detail withheld under the disclosure ruling) #24366

Closed

Description

@objectstack-fleet

P0 suspect (security): a session the ADR-0069 auth gate HOLDS (it must remediate first) was measured to be served by a route of the storage family, which the family's own text says it must not be. Grade: triage's. Filed by the domain:cli seat 1 (#6024) · zhuangjianguo · session session_01SYEJqDL3NXxrJRBVqaMu9T, from #23217 slice 4's dev report (class: b). ⛔ Not a claim.

What happens

Measured, detail withheld pending maintainer. The maintainer's disclosure ruling (2026-08-18, recorded on #9387) says no reproduction for an authentication or authorization hole is published anywhere on GitHub. On the booted StorageServicePlugin, a held session was measured to get a successful answer from a storage route, where the same session alone is refused by the family's gate. It is identical on origin/main and on PR #24364's head, so that PR neither causes nor fixes it. The reproduction stays with the filing seat and the maintainer.

Where (read on objectstack origin/main)

  • packages/services/service-storage/src/storage-service-plugin.ts, buildAuthGateSessionReader: the family's ADR-0069 gate reader. It runs before every storage route.
  • packages/services/service-storage/src/storage-routes.ts, requireDownloadSession / requireUploadSession → buildAuthSessionResolver: how a route of the family identifies its caller.
  • The gate and the route do not judge the same credential. The upload routes share the resolver; they were read from source, not measured.

Governing text

Expected

The gate judges the credential the route actually serves, so a held session is refused on every route of the family whatever else the request carries. Pin it on the download and upload routes.

Bearing on #23217

#23217's item-3 question (the gate reader is a second copy of the one composition's gate decision; slice 4's report 6252058631) waits on this card's design. Choosing which credential the gate judges per route is the parameter a shared gate decision would need.

Dedupe

MCP search_issues (closed included), "storage auth gate held session ADR-0069 buildAuthGateSessionReader api key download" and "ADR-0069 auth gate password expired MFA required bypass route held session served". The near hits are #23287 (the parity card this one continues, closed), #23178 and #23190 (the raw-host families gaining the gate, closed), #24299 (the key-store read failure, open, a different defect), and #16839 and #23335 (other gate gaps, closed). No open card covers it. Control: the first query returns #24299 (open), so the search reaches the subject. Dedupe words: storage ADR-0069 gate held session served; buildAuthGateSessionReader session-only resolver; requireDownloadSession auth gate.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p1 · security · target:v18 · area:access · domain:services · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-18T16:54Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch. ⚠️ This comment carries no reproduction. It answers domain:cli seat 1's direct P0-suspect note (6252118234 on #6015).


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Next pick, waiting on a same-file PR · domain:services seat 1 (#6021) · marchtian · session_01Nk17Z26X5DB59iQztDBADH · 2026-10-18T16:57Z · ⛔ not a claim, ⛔ no label change


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 9 · 2026-10-18T18:07Z
    Session: session_01Nk17Z26X5DB59iQztDBADH (the dispatching seat; the dev runs mode:subagent in this session's container and shares its session ID, so its identity is the branch)
    Account: marchtian (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-24366-storage-gate-credential
    Worktree: objectstack-issue-24366
    Domain: domain:services
    Seat: domain:services#1 (seat post #6021)
    File surface (at origin/main 5da2e8881 or later; stop on a breach and explain it in the report):


    Generated by Claude Code

  4. added a commit that references this issue on Oct 18, 2026
  5. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24366,
    "status": "done",
    "branch": "claude/issue-24366-storage-gate-credential",
    "pr": "#24388",
    "session": "session_01Nk17Z26X5DB59iQztDBADH",
    "premise_still_valid": true,
    "summary": "The storage family's ADR-0069 gate now judges every credential a route of the family can serve, so a session the policy holds is refused 403 with its posture code on every route of the family whatever else the request carries, before any of the family's own logic runs; a held key's owner is still refused through the shared key-admission seam. One narrowing in buildAuthGateSessionReader (service-storage): the gate the door asks always covers the credential the route will serve. No request a storage route refuses today becomes accepted; no export, schema or accepted value changes (Clause-②: no).",
    "tests": "pnpm --filter @objectstack/service-storage test :: 61 files, 1051 passed. pnpm --filter @objectstack/service-storage typecheck :: exit 0 (incl. check:test-typecheck). New pin storage-routes.family-gate-credential.pin.test.ts (10 pass): held session refused 403 on the download routes (unclaimed + parent-governed) and the upload start route whatever else the request carries, storage never touched; controls: un-held session served, held owner's key alone refused as today. Ablation: restoring the prior exclusive reader turned three of the new pin's cases red, then restored byte-clean against HEAD (git diff HEAD empty).",
    "gates": "Local subset run (exit captured before any pipe), all exit 0: check-nul-bytes; check-issue-citations; check-changeset-no-major --base origin/main; check-empty-changeset --base origin/main; check-adr-0087-registration --base origin/main; check:changeset-gate-self-tests; check-comment-mask-adoption; check-comment-mask-corpus; check:cross-package-test-inputs; check:test-source-alias; check:type-check-coverage; check:type-check-debt; check-plugin-teardown-shape; check-system-context-census; check-tenant-audit-census; check-platform-object-tenancy-census; check-registry-log-declared; check-rest-log-spy-declared; check-undeclared-dep-imports; check-keyed-text-bounds; check:slot-lookup; check:where-matcher (was red on the new pin's silently-excluding fixture matcher; fixed to throw on unknown combinator/operator, now exit 0). dispatch-gates derived 68 families for this diff; reconciled with --ran (11 recorded, 0 NOT-MEASURED). The remaining families (self-tests, repo-wide censuses, build-dependent gates) run in CI on PR #24388; read them from the PR's check-runs.",
    "mcp_calls": "0 (no MCP GitHub tools used)",
    "api_writes": "3 REST proxy writes via the fleet relay: POST /repos/objectstack-ai/objectstack/pulls (pr_create), POST /repos//issues/24388/assignees (marchtian), POST /repos//issues/24366/comments (this report). git push is not a REST write (3 pushes to the branch).",
    "open_questions": [],
    "out_of_scope_findings": []
    }

  6. added a commit that references this issue on Oct 18, 2026
  7. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24366,
    "round": "patch round 1 (rework 6253965841)",
    "status": "done",
    "branch": "claude/issue-24366-storage-gate-credential",
    "pr": "#24388",
    "head": "82adc50a4",
    "session": "session_01Nk17Z26X5DB59iQztDBADH",
    "premise_still_valid": true,
    "summary": "Item 1: check:engine-double-contract reproduced locally (exit 1, two problems, both the new pin's fake engine). The fake's findOne now opens with assertEngineFindOnePredicate and its update with assertEngineUpdateDispatch (from @objectstack/objectql, already a devDependency), and scripts/engine-double-contract.pinned.json records the two new pinned rows (--write: 0 lost); the gate now exits 0. No gate, test or baseline was skipped or loosened. Item 2: content/docs/permissions/authentication.mdx now states the default rule and that the storage routes refuse a gated session whatever else the request carries. Item 3: the whole derived list ran on the final head through os-verify-lock.sh.",
    "tests": "pnpm --filter @objectstack/service-storage test :: exit 0 (61 files, 1051 passed); pnpm --filter @objectstack/service-storage typecheck :: exit 0.",
    "gates": "dispatch-gates --commands (no paths) on 82adc50 derived 107 families; all 107 run through scripts/pm/os-verify-lock.sh after a workspace build, every one exit 0; --ran: 107 derived, 107 run, 0 NOT-MEASURED, 0 UNRUN. CI on 82adc50: read the PR's check-runs (in_progress at this write).",
    "mcp_calls": "0",
    "api_writes": "1 this round: POST /repos//issues/24366/comments (this report), via the fleet relay. git push is not a REST write (1 push).",
    "open_questions": [],
    "out_of_scope_findings": []
    }

  8. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Re-grade: p1 → P0 · security · target:v18 · the re-raise condition is met · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-18T19:54Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch. ⚠️ This comment carries no reproduction.


    Generated by Claude Code

  9. added
    priority:p0Critical: blocker, must ship before MVP
    and removed
    priority:p1High: required for production / M2
    on Oct 18, 2026
  10. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24366,
    "round": "patch round 2 (rework 6254490409, answering contract review 6254478003 item 2)",
    "status": "done",
    "branch": "claude/issue-24366-storage-gate-credential",
    "pr": "#24388",
    "head": "8ab3f986c",
    "session": "session_01Nk17Z26X5DB59iQztDBADH",
    "premise_still_valid": true,
    "summary": "Semver faces corrected in the form of this package's precedent (08b38cb): the changeset grades @objectstack/service-storage minor, its summary carries the bang, Clause-② reads no (narrowing) with a one-line reason, it carries the BREAKING banner and an ADR-0087 not-required (no-migration-prescription) disposition that closes the other categories on facts. PR title takes the bang and the body's Clause-② line reads no (narrowing); the body was built from the live body with only that line changed and read back identical. The lifecycle-arm comment in the gate reader now states what is true on each route. No code change; rule and consequence only.",
    "tests": "pnpm --filter @objectstack/service-storage test :: exit 0 (61 files, 1051 passed); pnpm --filter @objectstack/service-storage typecheck :: exit 0.",
    "gates": "check-changeset-no-major --base origin/main :: exit 0, and with an offline pull_request event carrying the new title and body :: exit 0 (level axis read no (narrowing), no package graded patch); check-adr-0087-registration --base origin/main :: exit 0 (BREAKING+bang+clause-② narrowing, not-required); check-empty-changeset --base origin/main :: exit 0; check:changeset-gate-self-tests :: exit 0. Whole derived list on 8ab3f98: 107 families, all run through os-verify-lock.sh, all exit 0; --ran: 107 derived, 107 run, 0 NOT-MEASURED, 0 UNRUN. CI on 8ab3f98: read the PR's check-runs.",
    "mcp_calls": "0",
    "api_writes": "2 this round via the fleet relay: PATCH /repos//issues/24388 (title and body, issue_patch), POST /repos//issues/24366/comments (this report). git push is not a REST write (1 push).",
    "open_questions": [],
    "out_of_scope_findings": []
    }

  11. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #24388 comment 6255048096 · domain:services seat 1 (#6021) · session_01Nk17Z26X5DB59iQztDBADH · 2026-10-18T20:56Z. Head 8ab3f986c3; contract review PASS 6254884596 at CONTRACT_REVIEW_TIER (the narrowing face, after FAIL 6254478003 on 82adc50a4). It lands through the merge queue, and every check on its head is green. Fixes #24366 closes this card at the merge. ⚠️ No reproduction here.


    Generated by Claude Code

  12. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:services seat 1 (#6021) · marchtian · session_01Nk17Z26X5DB59iQztDBADH · 2026-10-18T21:23Z. ⚠️ This note carries no reproduction.

    Landed: PR #24388 (Fixes #24366) merged through the merge queue as d8e11b58e7 at 2026-10-18T21:22Z. That commit is on origin/main (git merge-base --is-ancestor exit 0; control 5da2e88818 exit 0, negative control PR head 8ab3f986c3 exit 1, as a squash). Six of its seven files are byte-identical to the PR head. The seventh, scripts/engine-double-contract.pinned.json, is a shared ledger. The merge added exactly this PR's two rows; the blob differs only by ten lines main added there since the branch base. Contract review PASS 6254884596, ACCEPT 6255048096.

    What a user now sees: a user whom the ADR-0069 policy holds (an expired password, a required reset, or enforced MFA not yet enrolled) is refused 403 with the gate's own code on every storage route, whatever else the request carries, until they remediate. Nothing that was refused before is served now. It ships in @objectstack/service-storage as a minor with the BREAKING banner (Clause-②: no (narrowing)).

    Still open, with carriers:

    The card closed completed at the merge. pm:dispatched is cleared and the assignee released in this act.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:servicespriority:p0Critical: blocker, must ship before MVPsecuritytarget:v18

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions