Know the attack, stop the attack

Credential theft and leaked secrets

Find API keys that slipped into code or public files, and learn what to do after you find one.

  • Level: Basics
  • About 35 min
  • 2026-11-03

#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.

PlaceWhat happens
Source codeA 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 webBuild output (such as dist) has the key embedded as is
Source mapsDeployed 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.

Deleting it is not the end

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.

Check a string

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"
Output
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.

Check a publish folder

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: $?"
Output
調べた場所: .(ファイル 2 件)
- 機密情報(APIキー・秘密鍵など): app.js:1 AWS AKIAIO...MPLE
- ソースマップ(元のソースコードが読めてしまう): app.js.map
2 件(機密情報 1、トークン 0、ソースマップ 1)
見つかったキーやトークンは、すでに公開したなら流出したものとして、発行元で無効にして作り直してください。秘密はビルドに含めず、サーバー側に置いてください。ソースマップは、本番に置かないか、アクセスを制限してください。
終了コード: 1

In 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.

  1. Revoke the key at its issuer. Do not fix the Git history or delete the file first. The key keeps working while you do
  2. Look for signs of use. In the issuer's activity log (CloudTrail for AWS, for example), check for operations you do not recognize
  3. Issue a new key and replace it. Check that things work with the new one
  4. 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)
  5. Prevent a repeat. Run the check automatically before commits and at the end of builds
What not to do
  • 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

What the check cannot find

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
Check yourself

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
Features covered

Related techniques (ATT&CK): T1204.004

What was verified

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.