Skip to content

ADR-0096 (execution-surface identity admission) + fixes for the 3 confirmed-exploitable holes it surfaced (#2980, #2981, #2982) - #2975

Merged
os-zhuang merged 3 commits into
mainfrom
claude/security-unbounded-rls-fls-qusv11
Jul 15, 2026
Merged

ADR-0096 (execution-surface identity admission) + fixes for the 3 confirmed-exploitable holes it surfaced (#2980, #2981, #2982)#2975
os-zhuang merged 3 commits into
mainfrom
claude/security-unbounded-rls-fls-qusv11

Conversation

@os-zhuang

@os-zhuangos-zhuang commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #2964 / #2849. Two parts: the decision record (ADR-0096) and the three confirmed-exploitable fixes its evidence sweep surfaced. See the branch/PR note at the bottom — these can be split if a separate fast-merge PR is preferred.

Part 1 — ADR-0096: Execution-Surface Identity Admission (docs)

Names the failure class behind #2849 and #2308: a metadata-driven execution surface reaches the data engine without an ExecutionContext, and the SecurityPlugin's empty-principal fall-open rewards the omission with full authority — silently. Decisions:

Part 2 — the three confirmed-exploitable fixes

Each fixed at its own enforcement point; no behaviour change for correctly-scoped callers. Tests added; plugin-reports 38, service-knowledge 22, plugin-sharing 85 green; eslint + doc-authoring guard clean; changeset added.

Scheduled-reports behavior change (#2980). Correctly fixing the exfiltration requires running the report under the owner's resolved RLS, which needs the ADR-0073 M2 principal resolver (not available to the reports plugin today). Until it's wired, scheduled reports fail closed (skipped + marked failed) rather than run elevated. Interactive run/runAdHoc are unaffected. Flagged for reviewer sign-off.

Branch/PR note. These fixes and the ADR share the designated task branch, so they landed on one PR. If you'd prefer the three P1/P2 fixes as a separate fast-merge PR decoupled from the ADR's architectural review, say so and I'll split them out.

🤖 Generated with Claude Code

https://claude.ai/code/session_0155bjzJZxZaZTKSMSvg6Aum

Generalizes #2849 from an action-shaped bug to its class: metadata-driven
execution surfaces that reach the data engine without an ExecutionContext
silently inherit full authority via the security plugin's empty-principal
fall-open (#2308 and #2849 are two instances found only by adversarial
review).
Decides one invariant and four mechanisms: every engine call carries a real
principal or an explicit audited SystemGrant (D1); a single elevation
constructor systemContext(reason) (D2); identity-required engine signatures
so forgetting context is a compile error, not a fall-open (D3); an
execution-surface admission test wired into the authz conformance matrix
with a CI meta-test (D4); and a staged fail-closed strict mode (D5).
Re-bases #2849 Phase 2/3 as D6: action-level runAs adopts ADR-0073's
three-posture vocabulary and lands as this mechanism's first application.
Staged per ADR-0049: v1 is the decision record + systemContext + honest
matrix rows + the ai.exposed/trusted-body lint; signature migration and
the strict-mode default flip are evidence-gated M2+.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155bjzJZxZaZTKSMSvg6Aum
@vercel

vercelBot commented Jul 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
specCanceledCanceledJul 15, 2026 4:32pm

Request Review

claude added 2 commits July 15, 2026 15:29
A four-axis sweep (context-less calls, elevation literals, fall-open
seams, execution-surface identity) confirms #2849 is a populated class,
not a lone bug. Records the findings as the ADR's evidence base:
- E1: the empty-principal fall-open predicate replicated across getReadFilter,
the tenant-scope path, guest routes, custom API endpoints, the authored-body
sandbox, MCP resource reads, and messaging.
- E2: three confirmed-exploitable trusted-implicit surfaces, spun out as
#2980 (reports IDOR + scheduled-report RLS bypass), #2981 (knowledge/RAG
retrieval fall-open), #2982 (bulk-write OWD gap) — fixed independently.
- E3: structural middleware-bypass paths (executeAction, raw execute, driver
getters).
- E4: unknown seams (GraphQL, realtime, blob RLS, chatWithTools contract).
- E5: the D2 migration sizing (~300 sites / ~50 constructors / ~25 files) and
its existing prototype (resolveRunDataContext).
Wires the seed rows into D4, the exploitable instances into 'what lands now',
and the References/Trigger notes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155bjzJZxZaZTKSMSvg6Aum
…write OWD gap (#2980, #2981, #2982)
Three confirmed-exploitable execution-surface authz holes from the ADR-0096
class sweep, each fixed at its enforcement point; no change for correctly-
scoped callers.
- #2980 reports: getReport/deleteReport/saveReport/listReports were caller-
identity-blind (read/wrote sys_saved_report with a system context) → any
authenticated user could read/delete/overwrite/enumerate any report. Now
owner-scoped (system read of the protection-locked metadata object, authz
by owner match); create/overwrite can't spoof ownership. Scheduled dispatch
no longer runs isSystem (which emailed the target object's whole table past
the owner's RLS): resolves the owner via a new resolveOwnerContext seam and
fails closed when unresolved (ADR-0073 user-less identity consumer).
- #2981 knowledge/RAG: applyPermissionFilter returned all hits on missing OR
system context. Missing identity now fails closed (drops object-backed hits,
keeps ACL-less file/http); only an explicit system context passes through.
- #2982 sharing: bulk update({multi:true})/deleteMany had no single id to
canEdit-gate, skipping owner scoping on private/public_read objects. New
SharingService.buildWriteFilter (edit-set analogue of buildReadFilter) is
AND-ed into the multi-write AST, incl. the on-behalf-of delegator intersection.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155bjzJZxZaZTKSMSvg6Aum
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/plugin-reports, @objectstack/plugin-sharing, packages/services.

9 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/automation/webhooks.mdx(via packages/services)
  • content/docs/kernel/runtime-services/audit-service.mdx(via packages/services)
  • content/docs/kernel/runtime-services/index.mdx(via packages/services)
  • content/docs/kernel/runtime-services/settings-service.mdx(via packages/services)
  • content/docs/permissions/authorization.mdx(via packages/plugins/plugin-sharing)
  • content/docs/permissions/permissions-matrix.mdx(via packages/plugins/plugin-sharing)
  • content/docs/plugins/packages.mdx(via @objectstack/plugin-reports, @objectstack/plugin-sharing, packages/services)
  • content/docs/protocol/kernel/i18n-standard.mdx(via packages/services)
  • content/docs/protocol/objectql/security.mdx(via packages/plugins/plugin-sharing)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuangos-zhuang changed the title docs(adr): ADR-0096 — execution-surface identity admission (generalizes #2849)ADR-0096 (execution-surface identity admission) + fixes for the 3 confirmed-exploitable holes it surfaced (#2980, #2981, #2982)Jul 15, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review July 15, 2026 16:31
@os-zhuang
os-zhuang merged commit e07645c into mainJul 15, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/security-unbounded-rls-fls-qusv11 branch July 15, 2026 16:32
os-zhuang pushed a commit that referenced this pull request Jul 16, 2026
…d statuses, mark PRIORITIZATION stale
Follow-up to the ADR-0086 re-evaluation (#2557): an audit of docs/adr found
three hygiene defects; this fixes the mechanical ones.
1. Resolve the ADR-0096 numbering collision. Two unrelated ADRs landed as
0096 on the same day; the first-merged one (execution-surface identity
admission, #2975) keeps 0096, and the connector ADR (#2977) is renumbered
to ADR-0097. All connector-semantic "ADR-0096" references in code comments,
test titles, and zod describe/message strings are updated to ADR-0097;
execution-surface references (http-dispatcher, authz-conformance,
graphql/realtime contracts, service-realtime README) are untouched.
CHANGELOGs and commit history are left as historical record.
2. Flip Status lines of implemented ADRs that were still Proposed, with
evidence: 0093 (tenancy service + membership reconciler + dogfood test)
and 0095 (tenant-layer.ts + posture-ladder.ts + matrix-gate tests).
Verified code+tests on main before flipping; other stale-looking ADRs
(0049/0056/0057/0066/...) are left for per-ADR verification.
3. Mark docs/adr/PRIORITIZATION.md as a historical snapshot (it predates
ADR-0050+) and record the status-hygiene rule: the PR that lands an ADR's
implementation flips its Status line with one line of evidence.
os-zhuang pushed a commit that referenced this pull request Jul 16, 2026
…d statuses, mark PRIORITIZATION stale
Follow-up to the ADR-0086 re-evaluation (#2557): an audit of docs/adr found
three hygiene defects; this fixes the mechanical ones.
1. Resolve the ADR-0096 numbering collision. Two unrelated ADRs landed as
0096 on the same day; the first-merged one (execution-surface identity
admission, #2975) keeps 0096, and the connector ADR (#2977) is renumbered
to ADR-0097. All connector-semantic "ADR-0096" references in code comments,
test titles, and zod describe/message strings are updated to ADR-0097;
execution-surface references (http-dispatcher, authz-conformance,
graphql/realtime contracts, service-realtime README) are untouched.
CHANGELOGs and commit history are left as historical record.
2. Flip Status lines of implemented ADRs that were still Proposed, with
evidence: 0093 (tenancy service + membership reconciler + dogfood test)
and 0095 (tenant-layer.ts + posture-ladder.ts + matrix-gate tests).
Verified code+tests on main before flipping; other stale-looking ADRs
(0049/0056/0057/0066/...) are left for per-ADR verification.
3. Mark docs/adr/PRIORITIZATION.md as a historical snapshot (it predates
ADR-0050+) and record the status-hygiene rule: the PR that lands an ADR's
implementation flips its Status line with one line of evidence.
os-zhuang added a commit that referenced this pull request Jul 16, 2026
…d statuses, mark PRIORITIZATION stale (#3032)
* docs(adr): status-hygiene sweep — fix 0096 collision, flip implemented statuses, mark PRIORITIZATION stale
Follow-up to the ADR-0086 re-evaluation (#2557): an audit of docs/adr found
three hygiene defects; this fixes the mechanical ones.
1. Resolve the ADR-0096 numbering collision. Two unrelated ADRs landed as
0096 on the same day; the first-merged one (execution-surface identity
admission, #2975) keeps 0096, and the connector ADR (#2977) is renumbered
to ADR-0097. All connector-semantic "ADR-0096" references in code comments,
test titles, and zod describe/message strings are updated to ADR-0097;
execution-surface references (http-dispatcher, authz-conformance,
graphql/realtime contracts, service-realtime README) are untouched.
CHANGELOGs and commit history are left as historical record.
2. Flip Status lines of implemented ADRs that were still Proposed, with
evidence: 0093 (tenancy service + membership reconciler + dogfood test)
and 0095 (tenant-layer.ts + posture-ladder.ts + matrix-gate tests).
Verified code+tests on main before flipping; other stale-looking ADRs
(0049/0056/0057/0066/...) are left for per-ADR verification.
3. Mark docs/adr/PRIORITIZATION.md as a historical snapshot (it predates
ADR-0050+) and record the status-hygiene rule: the PR that lands an ADR's
implementation flips its Status line with one line of evidence.
* chore: retrigger CI
* docs: rename remaining connector-semantic ADR-0096 refs introduced by #3016/#3029
---------
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@os-zhuang@claude