Skip to content

fix(teams): require VIEW_SECRETS to read the legacy team vault blob - #11

Merged
kipavy merged 1 commit into
mainfrom
fix/team-blob-require-view-secrets
Aug 26, 2026
Merged

fix(teams): require VIEW_SECRETS to read the legacy team vault blob#11
kipavy merged 1 commit into
mainfrom
fix/team-blob-require-view-secrets

Conversation

@kipavy

@kipavy kipavy commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Found while working through VoltiusApp/voltius#187.

The hole

GET /v1/teams/:team_id/sync-blob checked team membership only:

if !is_team_member(&pool, team_id, auth.0).await? { ... }
require_teams_tier_for_vault(&pool, team_id).await?;

Its writer, put_team_blob, requires six permissions including VIEW_SECRETS, with a comment explaining why: the blob "can replace every object and secret in a team vault". The read side got none of that. Any member could download the entire vault ciphertext — objects and secrets together.

That is harmless only for as long as such a member holds no vault key. Which is exactly the gate voltius#187 proposes to widen: get_my_vault_key currently requires VIEW_SECRETS, and the issue's "Yes" option relaxes it to PERM_CONNECT || PERM_VIEW_SECRETS. Doing that on top of a membership-only blob read hands a connect-only member both halves — key and ciphertext — and every secret in the vault falls out. Close the read side first, and the widening becomes a decision about hosts rather than a secrets leak.

No client regression

The client only fetches the blob after getTeamVaultKey has already succeeded (src/services/teamVaultSync.ts), and that route has always required VIEW_SECRETS. Anyone who could use the blob could already pass the new check.

Also in this PR

The five team vault routes each repeated the same membership + Teams-tier + permission preamble. Extracted to require_vault_access(pool, team_id, user_id, action, permissions); the non-member warning keeps a greppable action field instead of five hand-written messages. Order of checks is unchanged.

Tests

Two new DB-backed tests: a connect-only member is refused the blob, and a VIEW_SECRETS member still reads it.

cargo test --all-targets → 298 passed; 0 failed

Related: VoltiusApp/voltius#187, VoltiusApp/voltius#70, VoltiusApp/voltius#190

GET /v1/teams/:team_id/sync-blob checked team membership only, while its
writer requires six permissions including VIEW_SECRETS. The blob carries
every object AND every secret in one ciphertext, so any member — a
connect-only one included — could download the whole vault.

Harmless only for as long as those members hold no vault key, which is
exactly the gate issue #187 proposes to widen. Close the read side first.

Also extracts the membership + Teams-tier + permission preamble the five
team vault routes each repeated into require_vault_access().
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