Revoke Access
Remove an identity from a secret’s recipient set, and understand why rotation is what actually invalidates the value.
Prerequisites
Section titled “Prerequisites”- A secret shared with at least one other identity (Share a Secret)
-
Check who can decrypt the secret
The recipient set lives in the
available_tofield, which--all --jsonexposes (newest entry first):Terminal window dotsecenv secret get API_KEY --all --json | jq '.[0].available_to'# ["YOUR_FINGERPRINT", "TEAMMATE_FINGERPRINT"] -
Revoke the identity
Remove a fingerprint from the recipient set for future writes:
Terminal window dotsecenv secret revoke API_KEY TEAMMATE_FINGERPRINTRevoke from every vault that holds the secret with
--all:Terminal window dotsecenv secret revoke API_KEY TEAMMATE_FINGERPRINT --all -
Rotate the value
Store a fresh value. The new entry is encrypted only to the remaining recipients:
Terminal window echo "new-secret-value" | dotsecenv secret store API_KEY -
Confirm the new entry excludes them
Terminal window dotsecenv secret get API_KEY --all --json | jq '.[0].available_to'# ["YOUR_FINGERPRINT"] -
Update systems and commit
Roll the new value out to whatever consumes it, then commit:
Terminal window git add vaultgit commit -m "Revoke API_KEY access and rotate"git push
Expected Result
Section titled “Expected Result”- The revoked teammate cannot decrypt the new value.
- The revoked teammate can still decrypt the old value from vault history.
secret getfor the revoked teammate falls back to the most recent entry they were a recipient of (the pre-rotation value), andsecret get --allproduces decryption errors for the rotated entry they no longer hold a key for.
Example 02 shows exactly this: after revoke + rotate, Bob’s secret get prints the old value, and his secret get --all warns it cannot decrypt the rotated entry that was only ever encrypted to Alice.
What Revocation Does NOT Do
Section titled “What Revocation Does NOT Do”| Revocation prevents | Revocation does NOT prevent |
|---|---|
| Decrypting future values | Decrypting values already shared |
| Membership in new entries | Reading old entries from vault history |
| Reading rotated values | Copies of values they already decrypted |
- GPG is asymmetric: once a value is encrypted to a key, only that key decrypts it.
- The vault is append-only: old entries stay readable to their original recipients, including in the repo’s
githistory. - There is no time travel: you cannot retroactively change who could decrypt a past value.
What to do about it
Section titled “What to do about it”- Rotate the secret after revoking.
- Treat revocation as the trigger to change the value at its source.
- Update downstream systems with the new credentials.
Variations
Section titled “Variations”Revoke from every secret
Section titled “Revoke from every secret”secret revoke takes one secret name per call. To strip an identity from all of them, loop over the key list that secret get (no arguments) prints:
for s in $(dotsecenv secret get); do dotsecenv secret revoke "$s" FINGERPRINT --alldoneThen rotate each value, since the revoke alone leaves prior ciphertext intact.
Audit access history
Section titled “Audit access history”The vault keeps full history. Inspect who was a recipient of each version:
dotsecenv secret get API_KEY --all --json | jq '.[] | {added_at, available_to, signed_by}'Complete offboarding checklist
Section titled “Complete offboarding checklist”For the full runbook covering scope inventory, batch revoke, source rotation, and error handling, see Offboard a Departing Team Member.
At a glance:
FINGERPRINT="THEIR_FINGERPRINT"
# 1. Revoke from every secret in every vaultfor s in $(dotsecenv secret get); do dotsecenv secret revoke "$s" "$FINGERPRINT" --alldone
# 2. Rotate each secret at its source (production-critical first)echo "new-prod-db-password" | dotsecenv secret store DATABASE_PASSWORDecho "new-prod-api-key" | dotsecenv secret store API_KEY# ... continue for staging and dev
# 3. Confirm the leaver is gone from every current recipient setdotsecenv vault describe --json \ | jq --arg fp "$FINGERPRINT" \ '.[].secrets[] | select((.available_to // []) | index($fp)) | .key'# (empty output means the revoke took effect)
# 4. Commitgit add vaultgit commit -m "Offboard: revoke access for $FINGERPRINT"git pushTroubleshooting
Section titled “Troubleshooting”Can they still read secrets?
If they kept the old vault file, they can still decrypt every entry their fingerprint was a recipient of. That is the append-only contract, and it is why rotating the value is the real fix.
Vault getting large?
Old entries accumulate. Check vault health and optionally defragment:
dotsecenv vault doctorNext Steps
Section titled “Next Steps”- Threat Model: what dotsecenv protects against
- Vault Format: how the append-only vault and recipient sets work