Unit 1: Secrets in code · Lesson 1 of 4 · 18 min
Find the secrets in a repository
Scan quay-api for credentials, then work out why a staging password slipped past .gitignore.
mission
- You are
- You are the application security engineer at Quayside.
- Situation
- quay-api is about to be shared with an outside contractor. Before anyone outside the company gets a copy, you check what secrets sit in the code.
- Goal
- List every credential in the working tree and explain how each one got there.
- Hand in
- A short list of findings with file, type and who added it.
A secret scanner as a baggage X-ray
Look around the repository
ls -a . .. .git .github .gitignore .npmrc README.md config docker package-lock.json package.json src test tests git log --oneline | wc -l 10
you should see A Node.js service with config, docker and tests folders and ten commits of history.
ls- Lists the files in a folder. Built into Linux and macOS.
git- Tracks changes to code and shows its history. Install with sudo apt install git, or brew install git on a Mac.
wc- Counts lines, words and bytes. Built into Linux and macOS.
Read the scanner's rules
gitleaks is a free, open source secret scanner. Install it with brew install gitleaks or from the gitleaks releases page on GitHub. Quayside's ~/gitleaks.toml keeps the built-in rules and adds two of its own: one for its payments key format and one for passwords in config files.
grep -E '^(id|regex) ' gitleaks.toml
id = "quay-live-key"
regex = '''qsk_live_[A-Za-z0-9]{24}'''
id = "password-in-config"
regex = '''(?i)[a-z_]*(?:password|passwd|pwd)\s*[=:]\s*["']?([^\s"',;]{6,})'''
you should see Two extra rules, each a regular expression.
grep- Prints the lines of text that match a pattern. Built into Linux and macOS.
Run the scanner
gitleaks dir scans the files on disk. -f json -r - prints the report as JSON and jq turns it into one line per finding: file, line and rule. -v --redact prints a finding in full without showing the secret.
gitleaks dir . -c ~/gitleaks.toml --no-banner -l error -f json -r - | jq -r 'sort_by(.File)[] | [.File, .StartLine, .RuleID] | @tsv' docker/.env.staging 3 password-in-config tests/fixtures/deploy_key 1 private-key gitleaks dir docker/.env.staging -c ~/gitleaks.toml --no-banner --no-color --redact -v Finding: DB_PASSWORD=REDACTED Secret: REDACTED RuleID: password-in-config Entropy: 3.916127 File: docker/.env.staging Line: 3 Fingerprint: docker/.env.staging:password-in-config:3 6:18PM INF scanned ~84 bytes (84 bytes) in 3.5ms 6:18PM WRN leaks found: 1
you should see A staging database password and a private key, both committed as ordinary files.
defender tip gitleaks ships well over a hundred rules for cloud, payment and chat tokens. trufflehog and GitHub secret scanning can also check whether a found key still works.
gitleaks- Scans files and git history for secrets such as API keys and passwords. Install with brew install gitleaks, or from its GitHub releases page.
jq- Picks fields out of JSON and reshapes it. Install with sudo apt install jq, or brew install jq on a Mac.
See who added the password
cat docker/.env.staging DB_HOST=db.staging.quay.internal DB_USER=quay_app DB_PASSWORD=Harbour-Staging-2026! git log --format='%h %an %ad %s' --date=short -- docker/.env.staging e70bc03 Ines Rocha 2026-09-18 Add staging config and test fixtures
you should see Ines added a staging config file with a real database password on 18 September.
cat- Prints the contents of one or more files. Built into Linux and macOS.
Find out why .gitignore missed it
git check-ignore -v prints the rule that ignores a path, or nothing when no rule matches.
cat .gitignore node_modules/ .env git check-ignore -v docker/.env.staging; echo "exit $?" exit 1
you should see The rule .env matches only a file named exactly .env, so .env.staging was committed.
defender tip Ignore patterns are an easy place for gaps. Use .env* and keep a committed .env.example with placeholder values instead.
echo- Prints its arguments. Built into Linux and macOS.
What a defender takes away
- 1Scan every repository you inherit before you share or publish it.
- 2Secrets hide in configs, test fixtures and docker files, not just in code.
- 3Check ignore rules with git check-ignore, do not assume them.
Questions
0 of 3 solved
Answer each one from what you find on your lab machine.