Skip to content

fix(core): authorize cross-workspace session listing (light-tested) - #2615

Open
1688mengdie wants to merge 2 commits into
GCWing:mainfrom
BitFun-SIG:fix/security-session-control-list-auth
Open

fix(core): authorize cross-workspace session listing (light-tested)#2615
1688mengdie wants to merge 2 commits into
GCWing:mainfrom
BitFun-SIG:fix/security-session-control-list-auth

Conversation

@1688mengdie

Copy link
Copy Markdown

Summary

SessionControl's list action accepted an explicit workspace argument
and enumerated every session in it without checking whether the caller
session belongs to that workspace, so a delegated session could enumerate
other workspaces' session summaries (ids, names, activity times).

This PR requires list callers to stay inside their current workspace;
listing a different workspace is allowed only for the owner (a top-level
session with no creator, matching the ownership semantics used for
transcript exports). Calls without a session identity keep their existing
behavior. The gate is covered by owner/delegated/cross-workspace
assertions, and the SessionHistory read-authorization suite stays green.

Stacked on #2613 (shares the session-authorization context introduced
there); review order: #2613 first, then this PR.

Fixes #2606

Type and Areas

Type: security fix

Areas: Agent runtime / core

Verification

  • cargo check --locked -p bitfun-core --jobs 4 — passed (0 errors, 0 warnings).
  • cargo test --locked -p bitfun-core --features agent-runtime --lib list_gate read_authz --jobs 4 — 3 + 9 passed (new list-gate suite plus the transcript-authorization suite kept green).
  • Full bitfun-core lib suite: 1498 passed, 1 pre-existing failure unrelated to this change (coordinator btw_session_persists_relationship_and_seeds_forked_listing_baselines, already failing on the clean base commit).

Reviewer Notes

  • The gate reuses the same owner determination (top-level session with no creator) as the transcript-export authorization, so the two authorization surfaces stay semantically consistent.
  • No new dependencies and no storage changes.
  • Rollback is a revert of the single-file change.

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable. (Not applicable: no user-facing change.)

This is an AI-assisted change.

user added 2 commits August 28, 2026 19:58
…sion

The SessionHistory tool resolved a session workspace and exported its
persisted transcript without checking whether the caller was allowed to
read it, so any session could export transcripts of unrelated sessions,
including tool inputs and thinking content.

Add a tool-level authorization gate for transcript exports. The gate
rejects callers outside the target session workspace outright, then
authorizes the export when the caller owns the workspace (top-level
session with no creator), created the target session, or is an
ancestor/descendant of the target within the same session tree. Ancestor
chains are resolved from persisted session metadata with cycle
protection, and every path fails closed when no relationship can be
established.

Cover the gate with an attacker-matrix test suite: unrelated callers,
owner bypass (enabled and disabled), creator matches, both ancestry
directions, sibling rejection, cross-workspace rejection, and
missing-metadata fail-closed.

Test: cargo check --locked -p bitfun-core --jobs 4 (0 errors, 0 warnings);
cargo test --locked -p bitfun-core --features agent-runtime --lib
read_authz --jobs 4 (9 passed); full bitfun-core lib suite 1495 passed,
1 pre-existing failure unrelated to this change (coordinator
btw_session_persists_relationship_and_seeds_forked_listing_baselines,
verified failing on the clean base commit via stash round-trip).
AI: AI-assisted, locally tested (cargo check + targeted/full lib tests).
SessionControl's list action resolved the effective workspace (falling
back to an explicit `workspace` argument) and enumerated every session in
it without checking whether the caller belongs to that workspace, so a
delegated session could enumerate other workspaces' session summaries.

Require list callers to stay inside their current workspace; listing a
different workspace is allowed only for the owner (a top-level session
with no creator, matching the ownership semantics used for transcript
exports). Calls without a session identity keep their existing behavior.
Cover the gate with owner/delegated/cross-workspace assertions and keep
the SessionHistory read-authorization suite green.

Test: cargo check --locked -p bitfun-core --jobs 4 (0 errors, 0 warnings);
cargo test --locked -p bitfun-core --features agent-runtime --lib
list_gate read_authz --jobs 4 (3 + 9 passed); full bitfun-core lib suite
1498 passed, 1 pre-existing failure unrelated to this change (coordinator
btw_session_persists_relationship_and_seeds_forked_listing_baselines,
already failing on the clean base commit).
AI: AI-assisted, locally tested (cargo check + targeted/full lib tests).
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.

[Security]: SessionControl list enumerates sessions in any workspace without caller-ownership check

1 participant