Security Tip: Finding Secrets

[Tip#30] Who wants to go on a treasure hunt for secrets, credentials, and API keys?

Security Tip: Finding Secrets

Secrets, API keys, credentials, passwords, encryption keys, private keys… the list goes on. There are a lot of different types of secrets that could appear in your code, either intentionally or otherwise. Maybe you commit your `auth.json` so everyone can easily download Nova, or your Slack webhooks are hard-coded in a controller. Or maybe you accidently used `git add .` and didn’t realise what files were being included…

There are many reasons why secrets could end up in your code repository, but you really don’t want your secrets stored in your code.

Why?

Because anyone with access to your code repository can find and use the secrets. This doesn’t just mean your developer team, but also your repository host (GitHub, GitLab, etc), and your code quality, build, deploy tools, etc. Even specialised tools like Laravel Shift will have access to your secrets. So not only do you need to worry about your developers going rogue or being hacked, but potentially many other systems too!

In short: it spreads your secrets around many different places and opens up a lot of failure points where your code and secrets could be exposed1.

So what do we do about it? We go hunting for secrets!

These are the two tools I use for finding secrets in code:

TruffleHog

https://github.com/trufflesecurity/trufflehog

TruffleHog is an awesome tool because not only does it find secrets within your code, it also safely checks the API keys it finds to see if they are legitimate secrets or not.

This saves you a bunch of time checking any secrets you find, immediately alerting you to the ones you need to change.

This is an example of the output from one of my test apps2:

$ trufflehog filesystem --directory=./
🐷🔑🐷  TruffleHog. Unearth your secrets. 🐷🔑🐷

Found unverified result 🐷🔑❓
Detector Type: MaxMindLicense
Raw result: Gm...
File: .env

Found verified result 🐷🔑
Detector Type: AWS
Raw result: AK...
File: .env.example

Found verified result 🐷🔑
Detector Type: Convertkit
Raw result: rq...
File: .env

Found unverified result 🐷🔑❓
Detector Type: MaxMindLicense
Raw result: Gm...
File: .env

Found verified result 🐷🔑
Detector Type: Convertkit
Raw result: rq...
File: .env

Found unverified result 🐷🔑❓
Detector Type: URI
Raw result: https://user:password@sindresorhus.com
File: node_modules/normalize-url/index.d.ts

Found unverified result 🐷🔑❓
Detector Type: URI
Raw result: https://user:password@sindresorhus.com
File: node_modules/normalize-url/readme.md

Gitleaks

https://github.com/zricethezav/gitleaks

The other tool I love is Gitleaks. Unlike TruffleHog, it doesn’t test the secrets it finds, but it does search your Git history. This allows it to find secrets you’ve previously committed and them removed - but are still present in the Git history!

Here is the Gitleaks output from the same project as before:

$ gitleaks detect --verbose

    ○
    │╲
    │ ○
    ○ ░
    ░    gitleaks

Finding:     AWS_ACCESS_KEY_ID=AK...
Secret:      AK...
RuleID:      aws-access-token
Entropy:     3.921928
File:        .env.example
Line:        42
Commit:      a701a5f2b27c504cf3307a8a004790c33177273c
Author:      Stephen Rees-Carter
Email:       stephen@rees-carter.net
Date:        2020-11-20T03:28:07Z
Fingerprint: a701a5f2b27c504cf3307a8a004790c33177273c:.env.example:aws-access-token:42

Finding:     ...1137253/deploy/http?token=pE..."
Secret:      pE...
RuleID:      generic-api-key
Entropy:     4.584184
File:        .github/workflows/laravel.yml
Line:        38
Commit:      c9666716d92c9790a7f5c29a04431b275603fb39
Author:      Stephen Rees-Carter
Email:       stephen@rees-carter.net
Date:        2020-09-15T19:58:29Z
Fingerprint: c9666716d92c9790a7f5c29a04431b275603fb39:.github/workflows/laravel.yml:generic-api-key:38

Finding:     ...1136348/deploy/http?token=HG...
      if: github.re...
Secret:      HG...
RuleID:      generic-api-key
Entropy:     4.534184
File:        .github/workflows/laravel.yml
Line:        38
Commit:      62c7c7c606f9d2df5851fcfc56f188cbbf90d107
Author:      Stephen Rees-Carter
Email:       stephen@rees-carter.net
Date:        2020-09-15T11:35:19Z
Fingerprint: 62c7c7c606f9d2df5851fcfc56f188cbbf90d107:.github/workflows/laravel.yml:generic-api-key:38

Finding:     $secret = 'Sh...';
Secret:      Sh...
RuleID:      generic-api-key
Entropy:     3.750000
File:        app/Http/Controllers/DownloadController.php
Line:        49
Commit:      43cd5d31d722b0bfd03cc409c5ea1d976ac8848f
Author:      Stephen Rees-Carter
Email:       stephen@rees-carter.net
Date:        2020-02-20T23:03:22Z
Fingerprint: 43cd5d31d722b0bfd03cc409c5ea1d976ac8848f:app/Http/Controllers/DownloadController.php:generic-api-key:49

The downside of these tools is that they rely on pattern matching, so you’ll see false positives, and it will miss secrets in unfamiliar formats. However, I believe it’s far better to wade through some false positives to find the secrets you’re leaking, then leave them for someone else to find!

You can also include these tools in your build pipelines, allowing you to quickly detect when someone accidently commits a secret!


  1. To clarify a point here, many of these systems and tools require some of your secrets for doing their jobs (i.e. deployment tools), but they should have a separate secrets management system that isolates it from the code.

  2. I’ve truncated the keys for this email, but TruffleHog shows the actual keys it finds.
    Also, entertainingly the AWS keys it found are actually Canary Tokens, and I did receive an alert when TruffleHog tested them!