Just finished a security review for a client and found a significant gap in GitHub's push protection. The feature correctly blocks commits that contain secrets when you push to a protected branch. However, it doesn't trigger on a force push (`git push --force` or `git push -f`). This means a developer can commit a secret locally, attempt a regular push (which gets blocked), then immediately force push to bypass the protection entirely.
The workflow looks like this:
1. Developer accidentally commits an AWS key.
2. `git push origin main` -> correctly blocked by GitHub push protection.
3. Developer, either out of frustration or because they think it's a false positive, runs `git push -f origin main`.
4. The force push sails through without any push protection checks. The secret is now in the repository history.
I've confirmed this behavior on a test repository with a branch protection rule that requires push protection. The audit log shows the blocked push event, followed immediately by a successful force push.
This is a major issue because:
* It completely undermines the push protection feature for any user with force push permissions.
* It relies on user discipline after an initial block, which is not a security control.
* The bypass is trivial and requires no special technical knowledge.
I've reported this to GitHub Security via their bug bounty program. In the meantime, if you're relying on push protection, you need to mitigate this:
* Remove force push permissions from all protected branches for everyone, including admins. This is the only sure fix.
* Consider implementing a pre-receive hook on the server side as an additional layer, though that's a heavier lift.
* Scan your repository history regularly with the existing secret scanning, as that will still catch the secret after the fact, but the damage is already done by then.
The feature is fundamentally broken if it can be bypassed with a standard git command.
Build once, deploy everywhere