#Where do secrets leak from?
Secrets such as API keys, access tokens, and private keys are strings that let whoever holds them act as the owner. Instead of cracking a password, an attacker looks for a secret someone has already left behind. It is usually left in one of these four places.
| Place | What happens |
|---|---|
| Source code | A key written directly to test something gets committed as it is |
| Config files and logs | .env files or debug output get shared with a key still in them |
| Files published on the web | Build output (such as dist) has the key embedded as is |
| Source maps | Deployed to production too, so the entire original source can be read |
None of these requires breaking in. Reading a public place is enough to get the secret.
A secret that has been public even once is treated as leaked after you delete it. Copies may remain in search engine caches or in someone's clone. The core of the response is not deleting, but revoking at the issuer.
#Lab: find secrets in text
RoamSwitch's API key and private key detection looks for API keys and private keys in known formats, inside text and files.
The key below is an invalid sample from the AWS documentation. It does not exist, so it is safe to try. Do not use a real key.
roamswitch audit-secrets "aws_access_key_id=AKIAIOSFODNN7EXAMPLE"1件の機密情報・APIキー露出を検出しました。コミットや外部共有前に削除してください。
⚠️ AWS Access Key ID (AWS): 行番号 1
マスク済み: AKIAIO...MPLE (エントロピー: 3.68)
↳ 推奨対応: AWS IAMコンソールからアクセスキーを非アクティブ化してください。The output follows the language of your RoamSwitch settings (this example is in Japanese). Look at three things:
- Masked (マスク済み): the whole key is not left on screen or in records, so sharing the result does not leak the key
- Entropy (エントロピー): how random the characters are. The higher it is, the more it looks like a generated key rather than a name a person chose
- Recommended action (推奨対応): it asks you to revoke the key at its issuer. It does not end at deleting it from a file
#Lab: find secrets in files you publish
The build output of a website is published to the world as is. Secrets in published front-end files inspects the folder you publish.
Create dummy build output and check it. Write the sample key from the previous lab into app.js, and place a source map (app.js.map) too.
mkdir -p dist
printf 'const cfg = { accessKeyId: "AKIAIOSFODNN7EXAMPLE" };\n//# sourceMappingURL=app.js.map\n' > dist/app.js
echo '{"version":3,"sources":["src/app.ts"],"mappings":""}' > dist/app.js.map
roamswitch scan-frontend ./dist
echo "exit code: $?"調べた場所: .(ファイル 2 件)
- 機密情報(APIキー・秘密鍵など): app.js:1 AWS AKIAIO...MPLE
- ソースマップ(元のソースコードが読めてしまう): app.js.map
2 件(機密情報 1、トークン 0、ソースマップ 1)
見つかったキーやトークンは、すでに公開したなら流出したものとして、発行元で無効にして作り直してください。秘密はビルドに含めず、サーバー側に置いてください。ソースマップは、本番に置かないか、アクセスを制限してください。
終了コード: 1In short: the tool found 1 secret (the AWS key, masked) and 1 source map, and its advice is to revoke any key that was already published and recreate it, keep secrets out of the build, and not deploy the source map (or restrict access to it).
The exit code is 1, so if you add this command at the end of your build, it stops you when you are about to publish with a secret in it. With no problem found, the exit code is 0.
#When you find one, do this first
The order matters.
- Revoke the key at its issuer. Do not fix the Git history or delete the file first. The key keeps working while you do
- Look for signs of use. In the issuer's activity log (CloudTrail for AWS, for example), check for operations you do not recognize
- Issue a new key and replace it. Check that things work with the new one
- Remove it from the source. Keep secrets out of code and builds, and put them on the running side (server environment variables, or a secrets manager)
- Prevent a repeat. Run the check automatically before commits and at the end of builds
- Delete the key but leave it active
- Use the leaked key yourself to "see whether it really works"
- Paste the full key into chat or an issue to share the result (use the masked display)
#What it cannot see
As far as I verified on a real machine:
- Half of a key pair may not be found on its own. An AWS key is a pair: an "access key ID" starting with
AKIA, and a "secret access key" that has no fixed shape. Checking the secret access key alone printed "not detected." When it is written together with the ID, the ID is detected - Even when it prints "not detected" (検出されませんでした), that does not prove there is no key. It means "no key in a known format was found." A key in a custom format, or a nameless string, is out of scope
- The check only reads strings. It does not check whether the key is still valid. Only the issuer can tell
You checked only a secret access key and it printed "not detected." Which reading is right?
Show the explanation
This check searches by format (such as starting with
AKIA). A string without a format cannot be found even when it is a key. "Not found" does not mean "not there."
#What to learn next
- Attempts to steal keys are watched by features such as the credential decoys (we will turn these into lessons in this series)
- The route by which a dependency steals secrets is covered in Supply-chain attacks
Related techniques (ATT&CK): T1204.004
Verified on 2026-11-03. Target: Linux 1.17.30. Ran on Ubuntu 26.04, Server Edition, using the invalid sample key from the AWS documentation
Command output varies with the product version and the environment. If yours differs, check the version first.