Tracking issue linking three findings from the 32-crate audit that are individually filed, but together describe one systemic gap: the API-key scope system currently provides no real write-side enforcement anywhere in the engine.
The chain
- dpp-types (
src/api_key.rs:62-71) — ApiKeyScope::from_scopes falls through to Admin on any unrecognized scope string, not just the documented empty-array back-compat case.
- dpp-dal (
src/pg/repo_api_key.rs:27-35) — key_from_row maps a NULL/empty scopes column to Admin as well, on the auth hot path.
- dpp-vault (
src/handlers/create.rs:48 and 6 sibling handlers) — ApiKeyScope::can_write(), the function that exists specifically to gate passport writes to Write/Admin scope, is never called anywhere in dpp-engine. None of the seven mutation handlers check auth.scope at all.
Why this matters as one issue, not three
Fixing any single link doesn't fix the chain. Even if from_scopes is corrected to fail closed to Read on an unrecognized value, dpp-vault still doesn't check scope at all — a genuinely Read-scoped key still gets full write access today. Conversely, wiring up can_write() in dpp-vault doesn't help if a corrupted/legacy row still resolves to Admin by default. All three need to land together (or in a sequence where the least-privilege default lands before enforcement is turned on, to avoid a transitional window where "unknown scope" both means "deny" and "no one checks it anyway").
Suggested acceptance criteria
ApiKeyScope::from_scopes fails closed (least privilege / explicit error) on any value it doesn't recognize, in both dpp-types and wherever dpp-dal constructs it from a DB row.
- Every mutation handler in
dpp-vault (create/update/publish/suspend/archive/eol/transfer) calls can_write() (or equivalent) before touching state, matching the pattern already used correctly in handlers/api_keys.rs, registry_identity.rs, and operator.rs.
- A regression test that mints a
Read-scoped key and asserts every mutation endpoint returns 403, so this can't silently regress again.
See the individual issues in dpp-types, dpp-dal, and dpp-vault for full file:line detail and failure scenarios.
Tracking issue linking three findings from the 32-crate audit that are individually filed, but together describe one systemic gap: the API-key scope system currently provides no real write-side enforcement anywhere in the engine.
The chain
src/api_key.rs:62-71) —ApiKeyScope::from_scopesfalls through toAdminon any unrecognized scope string, not just the documented empty-array back-compat case.src/pg/repo_api_key.rs:27-35) —key_from_rowmaps a NULL/emptyscopescolumn toAdminas well, on the auth hot path.src/handlers/create.rs:48and 6 sibling handlers) —ApiKeyScope::can_write(), the function that exists specifically to gate passport writes toWrite/Adminscope, is never called anywhere indpp-engine. None of the seven mutation handlers checkauth.scopeat all.Why this matters as one issue, not three
Fixing any single link doesn't fix the chain. Even if
from_scopesis corrected to fail closed toReadon an unrecognized value,dpp-vaultstill doesn't check scope at all — a genuinelyRead-scoped key still gets full write access today. Conversely, wiring upcan_write()indpp-vaultdoesn't help if a corrupted/legacy row still resolves toAdminby default. All three need to land together (or in a sequence where the least-privilege default lands before enforcement is turned on, to avoid a transitional window where "unknown scope" both means "deny" and "no one checks it anyway").Suggested acceptance criteria
ApiKeyScope::from_scopesfails closed (least privilege / explicit error) on any value it doesn't recognize, in bothdpp-typesand whereverdpp-dalconstructs it from a DB row.dpp-vault(create/update/publish/suspend/archive/eol/transfer) callscan_write()(or equivalent) before touching state, matching the pattern already used correctly inhandlers/api_keys.rs,registry_identity.rs, andoperator.rs.Read-scoped key and asserts every mutation endpoint returns 403, so this can't silently regress again.See the individual issues in
dpp-types,dpp-dal, anddpp-vaultfor full file:line detail and failure scenarios.