Found during an independent audit of #185. Pre-existing on main — not introduced by that PR, though #185 widens the set of reachable providers.
The leak
For any provider with no PROVIDER_TO_VAR entry (custom today; google and any ?request=-appended provider under #185), resolveEnvVar derives the env-var name from the key's current name hint. removeKeyFromEnv (lib/services/keys.ts:455-473) therefore resolves a different var after a rename, because rotateValue (:611-632) and remove (:648) pass the post-rename name.
Reproduced against the real service:
write google key, name="Team Key" -> TEAM_KEY_API_KEY=<secret> written to agent .env
remove, name="Renamed Key" -> TEAM_KEY_API_KEY=<secret> STILL PRESENT
The secret stays in the agent's .env in plaintext under the stale variable, indefinitely, after the operator has deleted the key in HSM.
Why it matters
The code states the opposite intent — lib/services/keys.ts:642-646 says deleting a key should strip it from the fleet. An operator who rotates or revokes a credential reasonably believes it is gone from the agents.
Suggested fix
Persist the resolved env-var name alongside the key record at write time and use that for removal, rather than re-deriving it from a mutable name hint. Re-deriving can never be correct across a rename.
Related: making PROVIDER_TO_VAR the single source of truth (see the #185 review) shrinks the set of providers that depend on name-derived vars at all, but does not fix custom.
Found during an independent audit of #185. Pre-existing on
main— not introduced by that PR, though #185 widens the set of reachable providers.The leak
For any provider with no
PROVIDER_TO_VARentry (customtoday;googleand any?request=-appended provider under #185),resolveEnvVarderives the env-var name from the key's current name hint.removeKeyFromEnv(lib/services/keys.ts:455-473) therefore resolves a different var after a rename, becauserotateValue(:611-632) andremove(:648) pass the post-rename name.Reproduced against the real service:
The secret stays in the agent's
.envin plaintext under the stale variable, indefinitely, after the operator has deleted the key in HSM.Why it matters
The code states the opposite intent —
lib/services/keys.ts:642-646says deleting a key should strip it from the fleet. An operator who rotates or revokes a credential reasonably believes it is gone from the agents.Suggested fix
Persist the resolved env-var name alongside the key record at write time and use that for removal, rather than re-deriving it from a mutable name hint. Re-deriving can never be correct across a rename.
Related: making
PROVIDER_TO_VARthe single source of truth (see the #185 review) shrinks the set of providers that depend on name-derived vars at all, but does not fixcustom.