Skip to content
Teams7 min read

Who saw which secret? Rebuilding access after someone leaves

Which API keys and credentials did a former employee access? What cloud and vault logs can tell you, what they can't, and how an exposure report helps.

Crunu teamPublished 7 min read

Example. Kiteline is a fictional company.
On this page

To know which secrets a former employee accessed, you need a record of reads, not just of permissions: which values they received, which versions of them, when, and from where. Cloud secret stores and Vault can give you part of that if logging was set up before the person left. A secrets vault that records every delivery can give you the full list as a report. No log anywhere can see copies made outside the system, such as a key pasted into chat or a .env file on a laptop, so the answer is always "at least these", never "only these".

This post explains what to collect, where each piece usually lives, and how to turn it into a list of values to reissue. The full offboarding process is in the guide on what to rotate when a developer leaves.

The question behind the question

"What did they have access to?" is easy to answer and not very useful. Permissions tell you what someone could have read. The reissue list depends on what they did read, and a busy engineer's permissions can be much wider than their reads.

The useful version of the question has four parts:

  • Which values. Named secrets or variables, not whole systems: "production Stripe secret key", not "the payments project".
  • Which versions. If a value changed after the person last read it, the current value may never have reached them.
  • When. Reads during normal work look different from a burst of reads in the last week.
  • From where. An office or VPN address is expected. An address you've never seen is a reason to look harder.

If you can answer all four for every value, the reissue list writes itself: every value whose current version the person received. If you can't, you fall back to "everything they could read", which is safe but slow.

What cloud logs can tell you

If your secrets live in a cloud secret store, the cloud's audit log is the first place to look.

AWS Secrets Manager. CloudTrail "records all API calls for Secrets Manager as events", and GetSecretValue is one of the logged operations (AWS: logging with CloudTrail, AWS: CloudTrail entries). Each record carries the identity that made the call, the time, the source IP address and the request parameters (CloudTrail record contents).

Two details matter for this job. The console shows only the last 90 days of events, so anything older needs a trail that delivers logs to S3, created before you needed it. And for read-only calls, the response is not recorded: responseElements is null. The log tells you that someone read a secret, not which version came back. To work that out, line the read up against the secret's own change events, such as PutSecretValue and rotation.

Shell
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=GetSecretValue \
  --start-time 2026-08-01 --end-time 2026-10-30

Filter the result by the person's IAM user or role session. If people read secrets through a shared role, the session name may be the only thing that tells them apart, so check that your sign-in setup puts the person's name there.

HashiCorp Vault. Vault's audit devices "record all API requests and responses in detail", with most string values written as HMAC-SHA256 hashes rather than plaintext. But "when you initialize a new Vault cluster, auditing is disabled" (Vault: audit devices). If an audit device was enabled, each entry has the API path, the client address as Vault saw it, the token's display name and, when the token belongs to an entity, its ID (Vault: audit schema). That is enough to list which secret paths a person read, provided they used their own token rather than a shared one.

Whichever store you use, the same limits apply. You only have what was logged before the person left, for as long as you kept it, under identities that map to people.

What those logs don't show

Even a perfect log of reads from the store misses copies made outside it.

  • Values outside the store. A .env file passed around in chat, a database password in a shared document, a key in a CI variable. None of these produce a read event anywhere.
  • Copies made after a read. The log shows the person fetched a value at 14:20. It can't show that they pasted it into a notes app at 14:21.
  • Shared identities. A read made with the deploy role or a team token is a read by "whoever had it".
  • Machines they controlled. If the person had root on a server that receives secrets, they could read everything that server received, without a log entry in your secret store.

This is why exposure is always a lower bound. A good log narrows the list from "everything they could read" to "everything they did read, plus anything we know they copied". It doesn't shrink it further.

Turning reads into a reissue list

Once you have the reads, the method is the same whatever produced them.

  1. List values, not systems. One row per secret or variable, with the environment it belongs to.
  2. Mark which versions they received. For each value, the last version the person read.
  3. Compare with what is live now. If the live version is the one they read, it goes on the reissue list. If it changed since, the person never saw the current value, though they may still hold a credential that works if the old one was never revoked.
  4. Add values from outside the store. Anything you know was shared in chat, documents or tickets during their time.
  5. Sort by impact. Payment keys, cloud keys with broad permissions and production database passwords first.

Then reissue each value at its provider, deploy it, and revoke the old one. The key rotation guides by service cover the provider side.

How Crunu builds the list

Crunu records deliveries as part of how it works, so this list is a report rather than a project.

Example. Kiteline is a fictional company.

The server keeps a delivery record: which versions of which environment it delivered to whom, the first and last delivery, how many times, and the last address. Each version delivered in the last 90 days is listed individually; older entries are summarized per key epoch. The server never sees values, so the record is about versions, not contents.

When an owner or admin removes someone with Remove from organization…, the first step of Member removal shows three things:

  • Exposure report. For each environment: the person's current access, Versions received, when, from which addresses, and whether they had the current key or an earlier one.
  • Reissue checklist. Values they received that are still in use. The admin's browser compares the versions the person received with the current ones and shows only file paths and variable names, never values.
  • What they could have carried away. Service tokens they created, machines not yet approved whose enrollment code they may have kept, and invitations and share links they created, each with a tick box to revoke.

The report can be downloaded for your security team. Removal itself stops the server from serving the person anything in the organization and rotates the keys of every environment where they had one, so their old keys open no new version. The steps are in offboarding a teammate, and the overview is on the offboarding feature page.

Records you can rely on later

An exposure list is evidence. It might be read months later, when a leaked value turns up and someone asks whether it was on the list. That only works if nobody could quietly edit the record in between.

Example. Kiteline is a fictional company.

Crunu's audit log is a hash chain: each record contains the hash of the previous one, so a changed, deleted or inserted record shows up when an owner or admin chooses Verify integrity. Export JSONL produces a file that an outside program can verify the same way. When someone shows, copies or exports a value in the web app, the browser sends a signed event, marked Client-reported, because the server can't observe those actions itself. The log keeps 365 days by default and can be extended per organization. More in the audit log feature and the glossary entries for exposure report and audit log hash chain.

The limits, stated plainly

Crunu's report has the same boundary as any log. It knows what the server delivered. It does not know what happened after decryption on the person's device: a value shown and copied into a chat, a file pulled onto a laptop, a variable printed in a terminal. Hiding values in the web app guards against accidents, not against someone who can decrypt them. And it does not reissue anything at the provider. Until a value is replaced at AWS, Stripe or your database, the former member can still use their copy.

What the report changes is the starting point. Instead of "everything they could read", you begin with the versions they actually received, compared against what is live today.

Sources