Secret Scanning & Push Protection
Accidentally committing secrets to GitHub is one of the most common and dangerous security mistakes. Secret scanning detects exposed credentials in your repository, and push protection blocks them before they ever reach GitHub—keeping your tokens, keys, and passwords safe from attackers.
Secret scanning is a GitHub security feature that automatically scans your repositories for accidentally committed secrets. It looks for patterns that match known credential formats—AWS access keys, GitHub tokens, Slack webhooks, API keys, database passwords, and hundreds of other secret types. When a secret is detected, GitHub creates an alert and notifies the repository administrators and the affected service provider, who can revoke the compromised credential.
This feature is critical because once a secret is committed to Git, it remains in the repository history forever unless explicitly removed. Attackers routinely scrape GitHub for exposed secrets, and compromised credentials can lead to data breaches, unauthorized cloud resource usage, and serious security incidents. Secret scanning acts as a safety net, catching mistakes before they become disasters.
GitHub's secret scanning detects over 200 different secret patterns from dozens of service providers. Here are some of the most commonly detected types:
Cloud Providers: AWS access keys and secret keys, Azure credentials, Google Cloud service account keys, DigitalOcean tokens, and more.
Code Platforms: GitHub personal access tokens, GitHub App tokens, GitLab tokens, Bitbucket credentials.
Communication Tools: Slack webhooks and tokens, Discord webhooks, Microsoft Teams webhooks, Twilio credentials.
Database & Services: PostgreSQL, MySQL, MongoDB connection strings, Redis credentials, Stripe API keys, PayPal credentials, SendGrid API keys.
Tokens & Keys: JSON Web Tokens (JWT), SSH private keys, RSA private keys, PGP private keys, TLS certificates.
For private repositories, secret scanning also includes high-confidence patterns for generic secrets and custom patterns you can define yourself.
Secret scanning runs continuously across your repositories. When you push code, when new secrets are added to the advisory database, and on a scheduled basis, GitHub scans both the current content and the entire commit history for secret patterns.
When a match is found, several things happen. First, an alert is created in the repository's Security tab, showing the secret type, location (file and line number), and the time it was detected. Second, GitHub notifies the repository administrators and users who have access to the security alerts. Third, for many partner services, GitHub automatically notifies the service provider, who can revoke the exposed credential to prevent abuse.
For public repositories, secret scanning is completely free and enabled by default. For private repositories, it's included in GitHub Advanced Security, which is available with GitHub Enterprise plans. Once a secret is detected, you can view the alert, follow remediation steps, and mark it as resolved after the secret is revoked and removed from history.
# Example secret scanning alert details
Secret type: AWS Access Key
Location: src/config.js line 15
Detected: 2 hours ago
Status: Open
Remediation steps:
1. Revoke the exposed credential in your cloud provider
2. Remove the secret from your repository history
3. Use GitHub Secrets or environment variables instead
While secret scanning catches secrets after they're committed, push protection stops them from being pushed in the first place. When push protection is enabled, any attempt to push code containing a detected secret is blocked at the command line. The developer sees a clear error message explaining which secret was detected and in which file.
This is a game-changer for security. Instead of discovering secrets days or weeks later, developers get immediate feedback and can remove the secret before it ever reaches the remote repository. Push protection supports the same secret patterns as secret scanning and can be enabled for specific repositories or at the organization level.
When a push is blocked, the developer has several options. They can remove the secret from the files being pushed, rewrite history to remove it from earlier commits, or—if they're certain it's a false positive—use a bypass token to override the protection. Bypasses are logged for audit purposes.
# Push protection error message
$ git push origin main
remote: error: GH013: Push contains a secret detected by push protection.
remote: Scanning for known secrets (14.7 MB scanned)
remote:
remote: secret: AWS_ACCESS_KEY_ID (AKIAXXXXXXXXXXXXXXXX)
remote: locations:
remote: - src/aws_config.js:3
remote:
remote: To push, remove the secret from the commit history,
remote: or use a bypass token with `git push --push-option=...`
error: failed to push some refs to 'https://github.com/user/repo.git'
For public repositories, secret scanning is enabled by default. You can verify this by going to your repository's Settings → Security & analysis. For private repositories, you'll need GitHub Advanced Security enabled on your organization.
To enable push protection, navigate to Settings → Code security and analysis → Push protection. Click "Enable" to turn it on. You can enable it for all repositories in an organization, or for specific repositories. Once enabled, any push containing a detected secret will be blocked.
You can also configure custom patterns if your organization uses proprietary credential formats. Go to Settings → Code security and analysis → Secret scanning → Custom patterns. Define a regular expression pattern, provide a description, and test it against sample code. Custom patterns apply to both secret scanning and push protection.
# Custom pattern for internal API keys
Pattern: (internal-api-key-[A-Za-z0-9]{32})
Description: Internal API keys used by our services
# Sample matches:
internal-api-key-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
When you receive a secret scanning alert, take immediate action. The first step is to revoke the exposed credential at the service provider. For AWS keys, go to the AWS console and delete or deactivate the key. For GitHub tokens, regenerate them. This prevents attackers from using the exposed secret, even if it's still in your repository history.
Next, remove the secret from your repository. If it was just added in the most recent commit, you can use git commit --amend to remove it. If it's deeper in history, you'll need to use git filter-repo or BFG Repo-Cleaner to rewrite history and remove the secret from all commits. After cleaning, force-push to update the remote repository.
Finally, back in GitHub, mark the alert as resolved. This removes it from the active alerts list. Document the incident and consider reviewing your development practices to prevent similar leaks in the future—like using environment variables or GitHub Secrets instead of hardcoding credentials.
# Remove a secret from the most recent commit
git commit --amend
# Remove the secret from the file, then save and close
git push --force-with-lease origin main
# Remove a secret from entire history using BFG
bfg --replace-text passwords.txt my-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push --force-with-lease
Never hardcode secrets. This is the most important rule. Secrets should never appear in source code. Use environment variables, configuration files outside version control, or secret management tools.
Use GitHub Secrets for Actions. When using GitHub Actions, always store credentials in repository secrets. They're encrypted and never appear in logs.
Enable push protection on all repositories. This creates a safety net that catches mistakes immediately, preventing secrets from ever reaching GitHub.
Rotate secrets regularly. Even without exposure, regular rotation limits the window of opportunity if a secret is compromised without your knowledge.
Use OIDC when possible. OpenID Connect allows GitHub Actions to authenticate to cloud providers without storing any long-lived secrets at all.
Audit your repository history. Even with protections, periodically scan your repository for any missed secrets. Tools like truffleHog or gitleaks can help.
Train your team. Developers are the first line of defense. Make sure everyone understands why secrets should never be committed and how to use environment variables and secret stores.
git filter-repo or BFG Repo-Cleaner to rewrite history and remove the secret from all commits. After cleaning, force-push to update the remote. All collaborators must re-clone after this operation.Secrets are the keys to your infrastructure. Protect them with secret scanning and push protection, and build a culture of security in your development workflow.