Skip to content

fix(kv,blob): close cross-tenant IDOR on KV and Blob data planes - #327

Merged
dviejokfs merged 4 commits into
mainfrom
fix/kv-blob-cross-tenant-idor
Jul 31, 2026
Merged

dviejokfs merged 4 commits into
mainfrom
fix/kv-blob-cross-tenant-idor

Conversation

@dviejokfs

Copy link
Copy Markdown
Contributor

Security review finding #3 — Cross-tenant IDOR on the KV and Blob data plane (High)

Location: `crates/temps-kv/src/handlers/handler.rs` (`extract_project_id`), `crates/temps-blob/src/handlers/handler.rs` (`extract_project_id`, `blob_head`, `blob_download`)

These data endpoints authenticated the caller but never verified that the client-supplied `project_id` belonged to them. For session/API-key auth the `project_id` was trusted verbatim, so any authenticated principal could read/write/list/copy/delete another project's KV entries and blobs by passing an arbitrary id. (Deployment tokens were already correctly constrained; the session/API-key path was the hole.)

Fix

Route every data-plane handler through the team-based `project_access_guard!` — the same ADR-028 mechanism every other project-scoped resource already uses:

  • KV: fold the guard into the (now async) `extract_project_id` chokepoint — covers all 7 data handlers, and a future handler cannot forget it.
  • Blob: fold it into `extract_project_id` for the body handlers (`blob_put/delete/list/copy`) and add an explicit `authorize_project_access()` call to the path-based `blob_head`/`blob_download`.
  • Wire an optional `ProjectAccessChecker` into `KvAppState`/`BlobAppState` from the plugin context; register `temps-kv`/`temps-blob` in the ADR-028 coverage snapshot.

Behavioural note: no-op in plain OSS (no checker registered — identical to prior behaviour); enforced when a team-access plugin is present. This matches how the entire codebase models multi-tenant project access.

Verification (regression tests only)

  • `cargo test -p temps-kv -p temps-blob idor_tests` — 7 pass: denied project → 403, allowed project → accepted, and OSS-without-checker → no-op, for both body and path handlers. The denied-project inputs are exactly what the old code returned `Ok(project_id)` for.
  • `cargo test -p temps-auth --lib` ADR-028 coverage + companion snapshot tests pass with the two new crates registered.
  • `cargo clippy -p temps-kv -p temps-blob -p temps-auth --all-targets -- -D warnings` clean.

The KV and Blob data endpoints authenticated the caller but never verified
that the client-supplied project_id belonged to them (security review
finding #3). For session/API-key auth the project_id was trusted verbatim,
so any authenticated principal could read/write/list/copy/delete another
project's KV entries and blobs by passing an arbitrary id. Deployment
tokens were already constrained; the session/API-key path was the hole.

Route every data-plane handler through the team-based project_access_guard!
(the same ADR-028 mechanism every other project-scoped resource uses):

- KV: fold the guard into the async extract_project_id chokepoint (covers
  all 7 data handlers).
- Blob: fold it into extract_project_id for the body handlers and add an
  explicit authorize_project_access() call to the path-based blob_head and
  blob_download handlers.
- Wire an optional ProjectAccessChecker into KvAppState/BlobAppState from the
  plugin context, and register temps-kv/temps-blob in the ADR-028 coverage
  snapshot.

No-op in plain OSS (no checker registered, matching prior behaviour);
enforced when a team-access plugin is present. Regression tests cover the
denied/allowed/no-checker paths for both data planes.
@github-actions

github-actions Bot commented Jul 13, 2026 •

Copy link
Copy Markdown

📓 Changelog preview

This is what your commits will add to the generated CHANGELOG.md at release time (via git-cliff). Do not edit CHANGELOG.md by hand — it is generated from your Conventional Commit messages.

## [Unreleased]

### Fixed

- **kv,blob:** Confine data-plane access to the caller's projects

### Styling

- **kv,blob:** Apply rustfmt

@dviejokfs
dviejokfs merged commit 68d6221 into main Jul 31, 2026
14 checks passed
@dviejokfs
dviejokfs deleted the fix/kv-blob-cross-tenant-idor branch August 6, 2026 22:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant