The fact
DeviceState::apply_settlement_to_reserves (device_state.rs:2115) is a public method that moves encumbered vault reserves — the input leg in, the output leg out — taking no Operation and therefore carrying no authorization material of any kind.
Every other route to the same mutation goes through DeviceState::advance with VaultReserveMutation::ApplySettlement, where two guards apply:
apply_settlement_to_reserves reaches the same reserve leaves without either.
It has zero production callers
All call sites are tests or test-gated fixtures:
dsm/src/types/device_state.rs — 2672, 3183, 3243, 3255, 3275, 3280, 3283 (all in #[cfg(test)] mod tests)
dsm_sdk/src/sdk/vault_rehydration.rs:247 — inside #[cfg(test)] mod tests (attribute at :203, mod tests at :204)
So this is not a live bypass today. It is a public API on a production type that, if ever called from production, would move encumbered value with no operation and no signature — and it is exactly the kind of thing that gets reached for later precisely because it is simpler than the guarded path.
Likely fix
Make the API non-public or test-only (#[cfg(test)], or pub(crate) plus a test-utils gate), matching its actual callers.
Do not invent a second authorization mechanism around it. The guarded path already exists and is the one production uses; adding a parallel authorization scheme for a dead path would create two ways to authorize the same mutation, which is worse than the current state.
Not fixed in #635
Deliberately out of scope there — #635 is the narrow signing repair. Filed separately so the chokepoint question is decided on its own merits.
The fact
DeviceState::apply_settlement_to_reserves(device_state.rs:2115) is a public method that moves encumbered vault reserves — the input leg in, the output leg out — taking noOperationand therefore carrying no authorization material of any kind.Every other route to the same mutation goes through
DeviceState::advancewithVaultReserveMutation::ApplySettlement, where two guards apply:advancerefuses the mutation unless the operation isDlvOwnerApply(device_state.rs:1395)advancerequires and verifies that operation's signature against the advancing head's own AK, beforecompute_chain_tipapply_settlement_to_reservesreaches the same reserve leaves without either.It has zero production callers
All call sites are tests or test-gated fixtures:
dsm/src/types/device_state.rs— 2672, 3183, 3243, 3255, 3275, 3280, 3283 (all in#[cfg(test)] mod tests)dsm_sdk/src/sdk/vault_rehydration.rs:247— inside#[cfg(test)] mod tests(attribute at :203,mod testsat :204)So this is not a live bypass today. It is a public API on a production type that, if ever called from production, would move encumbered value with no operation and no signature — and it is exactly the kind of thing that gets reached for later precisely because it is simpler than the guarded path.
Likely fix
Make the API non-public or test-only (
#[cfg(test)], orpub(crate)plus a test-utils gate), matching its actual callers.Do not invent a second authorization mechanism around it. The guarded path already exists and is the one production uses; adding a parallel authorization scheme for a dead path would create two ways to authorize the same mutation, which is worse than the current state.
Not fixed in #635
Deliberately out of scope there — #635 is the narrow signing repair. Filed separately so the chokepoint question is decided on its own merits.