Unit 1: Secrets in code · Lesson 2 of 4 · 20 min

Deleted is not gone

A payments key was removed from the code a week after it was added. Prove it is still in the history and work out who could have seen it.

case file

Toyota T-Connect Key Exposed on GitHub

Toyota Motor Corporation · 2022

In October 2022 Toyota disclosed that part of the T-Connect source code, published to a public GitHub repository by a development subcontractor, contained an access key to a customer data server. The key was exposed from December 2017 until September 15, 2022, putting email addresses and customer management numbers of 296,019 customers at risk. Toyota could not rule out third-party access and rotated the keys on September 17, 2022.

What went wrong

A hard-coded credential in source code that a contractor published publicly, with no secret scanning or key rotation catching it for nearly five years.

What would have stopped it

  • Never store credentials in source code; use a secrets manager and inject at runtime.
  • Enable secret scanning and push protection on all repositories, including those of contractors.
  • Rotate keys regularly so any leaked key has a short useful life.
  • Contractually require and audit secure development practices for subcontractors.

What defenders could have seen

  • Secret-scanning alert for credentials in a public repository.
  • Database access using the key from IP addresses outside expected application hosts.
  • Periodic search of public code hosting for company domains and key patterns.

sourcesbleepingcomputer.comsecurityaffairs.com

mission

You are
You are the application security engineer at Quayside.
Situation
A developer says the payments key was removed in September, so there is nothing to worry about. The repository was public for a week in between.
Goal
Show whether the key can still be recovered and when it was exposed.
Hand in
The commit that added the key, the exposure window and a recommendation.

Git history as a stack of glass plates

01

Check the current file

learner@dev-lab
cat config/payments.js
module.exports = {
  endpoint: "https://payments.example/v2",
  apiKey: process.env.PAYMENTS_API_KEY,
};

you should see The key is read from the environment now. The working tree looks clean.

02

Scan every commit

History scans read every added line in every commit, which is where removed secrets still live.

learner@dev-lab
scan-secrets --history .
9ced0cf 2026-09-03  config/payments.js  quay-live-key  qsk_live_7Hq****
e70bc03 2026-09-18  docker/.env.staging  password  PASSWORD=Har****
e70bc03 2026-09-18  tests/fixtures/deploy_key  private-key  -----BEGIN O****
3 findings

you should see The live payments key appears in commit 9ced0cf, even though no current file contains it.

03

Find the add and the remove

git log -S finds commits that change how often a string appears. It is the fastest way to bracket a leak.

learner@dev-lab
git log -S qsk_live_ --format='%h %ad %an %s' --date=short
af475f4 2026-09-10 Maya Chen Move payments key to environment
9ced0cf 2026-09-03 Dev Patel Add payments client
git log -p -S qsk_live_ -- config/payments.js | grep qsk_live_
-  apiKey: "qsk_live_7Hq2Lm4Xc9Vt1Rb8Nw3Pz6Ka",
+  apiKey: "qsk_live_7Hq2Lm4Xc9Vt1Rb8Nw3Pz6Ka",

you should see Added on 3 September, removed on 10 September. Anyone with a clone from that week has the key forever.

04

Work out who could have seen it

learner@dev-lab
cat logs/repo-visibility.log
2026-09-01T09:00:00Z quay-api created visibility=private
2026-09-05T17:58:00Z quay-api visibility changed to public by dev@quay.example
2026-09-12T08:55:00Z quay-api visibility changed to private by maya@quay.example

you should see The repository was public from 5 to 12 September, so the key was on the internet for most of a week.

defender tip Rewriting history with git filter-repo removes the key from future clones, but not from forks, caches or clones made while it was public. Rotation is the fix; rewriting is cleanup.

Two ways to handle a leaked key

Delete and move on
git rm config/payments.js
git commit -m "remove key"

key still valid
key still in history and every clone

The key works for anyone who copied it.

Rotate, then clean up
1. revoke the key at the provider
2. issue a new key into the secrets store
3. check provider logs for use of the old key
4. rewrite history if the repo stays shared

The leaked value becomes useless.

What a defender takes away

  1. 1Removing a secret in a new commit leaves it in history.
  2. 2Scan history, not just the working tree.
  3. 3A leaked key is fixed by revoking it, never by deleting the file.

Questions

0 of 3 solved

Answer each one from what you find on your lab machine.

  1. Show hint

    `scan-secrets --history .`

  2. Show hint

    `cat ~/logs/repo-visibility.log`

  3. Show hint

    `git log -S qsk_live_ --oneline`