Leveraging git hook for hardcoded secrets scanning in a codebase
Almost everyone knows how to use .gitignore, the git file that helps in keeping sensitive files like .env out of the tracking, commit, and pushing process, and also unwanted folders like node_modules and all.
But do you know secrets, hardcoded credentials, and API aren't easy to deal with using a .gitignore file? you don't want to keep your config.js or config.go file out of the commit process, these are essential files to your project.
Okay, since you can't keep them out, you probably think, yes, I would use dummy creds, and sandbox API, so you are good.
Yes, but in the dev process/circle, mistakes are inevitable, you are not always perfect, and the pressure of delivering early is definitely real, hence you end up pushing secrets to the public domain via github.
So how do you automate this secret/API/hardcoded creds process to avoid mistakes like this?
That brings us to Git Hooks
discovered git hook recently also, been a git user for a while and I am just discovering git hook this month, haha
So what is Git Hook?
Git hooks are scripts or programs that are placed in the hooks directory to trigger at a certain point in the git's execution process.
Types of git hooks
There are many types of git hooks but here I will only be discussing two which are pre-commit and pre-push
What's the pre-commit hook?
The pre-commit hook is the script that runs immediately after you enter the git commit -m "Committing my changes"
, meaning that whatever instruction is given to the pre-commit hook would initiate first before the commit.
So if the instructions fail, the commit would not take place and if the instructions are successful the commit will proceed.
Pros:
- Your secret/API/hardcoded keys would never make it into the commit history
Cons:
- It would be a blocker to the developer and can slow down the dev process
What's the pre-push hook?
The pre-push hook is the script that runs right after you enter git push
command, whatever instruction is given to the pre-push hook gets executed first before the git push command execution,
So if the instructions fail, the git push
command won't get executed, but if the pre-push hook instructions are successful, the git push command will also execute.
Pros:
- Your secret/API/hardcoded keys won't make it to the remote repository
- Scanning collections of commit in one go
Cons:
- The secret/API/hardcoded keys still remain in your git history
Well, you can always clean your git history and rebase, here is a detailed guide on that.
So now let's jump into the implementation;
Implementing secrets scan via pre-push hook
I would be using detect-secrets as my secret scanning tool in this guide.
- Firstly, you need to install pre-commit tool.
pip install pre-commit
- Navigate into your project folder, create and open the .pre-commit-config.yaml file in the root of your folder via your terminal.
touch .pre-commit-config.yaml
open .pre-commit-config.yaml
- copy and paste the following hook mapping inside the file you just created above.
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.3.0
hooks:
- id: detect-secrets
This hook mapping tells pre-commit the repo where it will get the code for the hook, here I am using detect-secrets tool for the secret scanning, but there are many other tools to use.
You have ggshield, gitleaks and more.
- Now let's install the pre-push hook.
By default if you run pre-commit install
in your project folder, it will install the default pre-commit hook, so to install the pre-push hook, here is the command to use
pre-commit install --hook-type pre-push
So now that you have the pre-push hook installed, let's test it out.
- You can create config.js, config.yaml, config.json, .env, and config.py files for the testing.
touch config.js config.yaml config.json .env config.py
- Now open those files you just created and paste these dummy creds/secrets in them.
kred_herring = 'DEADBEEF'
id = 'YW1pYWx3YXlzZ2VuZXJhdGluZ3BheWxvYWRzd2hlbmltaHVuZ3J5b3JhbWlhbHdheXNodW5ncnk'
base64_secret = 'c2VjcmV0IG1lc3NhZ2Ugc28geW91J2xsIG5ldmVyIGd1ZXNzIG15IHBhc3N3b3Jk'
hex_secret = '8b1118b376c313ed420e5133ba91307817ed52c2'
basic_auth = 'http://username:[email protected]'
aws_access_key = 'AKIAIOSFODNN7EXAMPLE'
aws_secret_access_key = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
- When you are done with adding the dummy keys into those files, add the file to git tracking and commit to saving your changes.
git add . && git commit -m "Git secret scanning using pre-commit hooks"
- After the commit, you can then push to your remote repository using
git push
as you can see in the screenshot below.
Yeah, the push failed and the secrets/hardcoded APIs are being pointed out.
Whenever you are fixing the pointed creds/API if they aren't false positive(keys you deliberately add and are not real keys).
You will need to clean your commit history else, the pointed creds/API will still show up in your remote repository if you later push to the remote repository.
And that's all 😁.
In addition, if some hardcoded API or keys escape the pre-push hook.
You can then proceed to set up the github workflow of gguard or gitleak, so you can catch them there 😁.
Layering does help when doing shift-left in SDLC.
What else can you do with git hooks?
I think you can also do some SAST testing, like the Golang security checker, they have a pre-commit hook, see here.