If a secret is committed to a Git repository, removing it from the latest version of the file does not necessarily make it safe. The value may already exist in Git history, forks, logs, pull requests, or other places where it can be discovered.
This is why secret scanning is an important part of modern software development. GitHub can detect credentials and tokens that match known secret patterns and alert developers before those credentials are misused.
GitHub secret scanning now includes detection for additional token types, including Supabase and Pydantic tokens. For teams using these services in applications, this provides another layer of protection against accidentally committing sensitive credentials.
In this article, we will look at what these tokens are, how secret scanning works, how to handle an alert, and how developers can prevent secrets from entering Git repositories in the first place.
What Is GitHub Secret Scanning?
GitHub Secret Scanning is a security feature that searches repositories for credentials and other sensitive authentication values.
A developer might accidentally commit something like this:
const supabaseUrl = "https://example.supabase.co";
const supabaseKey = "your-secret-key";
Or a configuration file could contain an API token:
SUPABASE_URL=https://example.supabase.co
SUPABASE_KEY=your-secret-token
The problem is not limited to public repositories. Secrets can also be accidentally exposed inside private repositories when repository access is broader than expected or when a repository is later made public.
Secret scanning looks for patterns associated with supported credentials. When GitHub identifies a potential secret, it can generate an alert so that the repository owner or security team can investigate it.
The goal is simple:
Detect exposed credentials before they become a security incident.
Why Supabase and Pydantic Token Detection Matters
Supabase is commonly used for application backends, databases, authentication, storage, and APIs. Developers often configure Supabase credentials through environment variables.
Pydantic is widely used in Python applications for data validation and configuration management. Pydantic-related tokens or credentials may appear in projects that use Pydantic-based services and integrations.
A common development pattern is to keep configuration in environment variables:
DATABASE_URL=...
SUPABASE_URL=...
SUPABASE_KEY=...
API_TOKEN=...
The problem starts when developers accidentally copy those values into a source file or configuration file that is tracked by Git.
For example:
from pydantic_settings import BaseSettingsclass Settings(BaseSettings): API_TOKEN = "actual-token-value"
The code may work perfectly on the developer's machine. However, once the file is committed, the credential becomes part of the repository's history.
Secret scanning helps catch this type of mistake.
How Secret Scanning Works
At a high level, secret scanning looks for patterns that resemble known credentials.
The process can be thought of in four steps:
- A developer commits code to a repository.
- GitHub scans the repository content for supported secret patterns.
- A matching credential is identified.
- GitHub creates a security alert when the detected secret meets the relevant detection criteria.
For example:
Developer
|
v
Git commit
|
v
GitHub repository
|
v
Secret scanning
|
v
Potential secret detected
|
v
Security alert
Secret scanning is not a replacement for secure application configuration. It is a detection layer that helps identify credentials that have already entered repository content.
A Common Secret Exposure Scenario
Consider a Node.js application using Supabase.
A developer creates a configuration file:
const config = {
supabaseUrl: "https://example.supabase.co",
supabaseKey: "secret-value"
};
module.exports = config;
The developer then commits the file:
git add .
git commit -m "Add Supabase configuration"
git push
The repository now contains the credential.
Even if the developer realizes the mistake and changes the file:
const config = {
supabaseUrl: process.env.SUPABASE_URL,
supabaseKey: process.env.SUPABASE_KEY
};
the original secret may still exist in Git history.
This is an important point for developers:
Deleting a secret from the current file does not automatically remove the secret from Git history.
What Should You Do When GitHub Finds a Secret?
A secret-scanning alert should be treated as a security issue, not simply as a warning to dismiss.
Follow these steps.
1. Identify the Secret
First determine what credential was detected.
Ask:
- What service issued the credential?
- Which application uses it?
- Is it still active?
- What permissions does it have?
- Where was it committed?
Do not copy the secret into tickets, chat messages, or other systems while investigating.
2. Revoke or Rotate the Credential
If the credential is real and active, rotate it as soon as possible.
For example, if an API key has been exposed, generate a replacement and invalidate the old key.
The exact process depends on the service that issued the credential.
The important principle is:
Assume an exposed credential is compromised.
Do not wait for evidence that somebody actually used it.
3. Move the New Credential Into Secure Configuration
Instead of placing credentials directly in source code, use environment variables or a dedicated secret-management system.
For example:
const supabaseUrl = process.env.SUPABASE_URL;
const supabaseKey = process.env.SUPABASE_KEY;
The values can then be supplied through the deployment environment.
4. Remove the Old Secret From Repository History
Removing the secret from the latest version of a file is not always enough.
If the secret was committed previously, it may remain in Git history.
For sensitive credentials, teams should use an appropriate Git history-cleaning process and coordinate it with credential rotation.
This is especially important for repositories that have been cloned or forked.
Environment Variables Are Better Than Hardcoding Secrets
One of the simplest improvements developers can make is to separate application configuration from source code.
Instead of:
SUPABASE_KEY = "actual-secret"
use:
import os
SUPABASE_KEY = os.environ["SUPABASE_KEY"]
For local development, developers can use an environment configuration file that is excluded from Git.
A typical .gitignore entry might look like this:
.env
.env.local
.env.*.local
This prevents common local environment files from being accidentally committed.
However, .gitignore is not a security boundary.
If a developer has already committed .env, adding it to .gitignore later does not remove the existing file from Git history.
Secret Scanning vs .gitignore
These two approaches solve different problems.
Feature |
.gitignore |
Secret Scanning |
|---|---|---|
Prevents selected files from being tracked |
Yes |
No |
Detects secrets already committed |
No |
Yes |
Helps identify exposed credentials |
No |
Yes |
Works before a commit |
Yes, indirectly |
Depending on configured workflow |
Protects Git history |
No |
Detects exposed values |
Replaces credential rotation |
No |
No |
Using both is better than relying on either one alone.
Add Secret Detection Before Code Reaches GitHub
Production teams should try to catch secrets as early as possible.
A useful workflow is:
Developer writes code
|
v
Local secret check
|
v
Git commit
|
v
CI/CD security checks
|
v
GitHub repository
|
v
Secret scanning
This gives the development team multiple opportunities to detect a problem.
A local pre-commit check can catch accidentally staged credentials before they are pushed.
CI/CD security checks provide another layer.
GitHub secret scanning provides an additional repository-level detection mechanism.
Be Careful With Client-Side Applications
Developers sometimes assume that moving a credential into an environment variable automatically makes it secret.
That is not always true.
For example, frontend applications often replace environment variables during the build process:
const apiKey = process.env.PUBLIC_API_KEY;
If that value is included in browser JavaScript, users can potentially inspect it.
Therefore, developers must distinguish between:
- Server-side secrets
- Public application configuration
- Client-side identifiers
- Privileged API credentials
A credential should only be considered secret if it is actually kept away from untrusted clients.
This is particularly important when working with database and backend services.
Common Mistakes Developers Make
Committing .env Files
A developer creates:
.env
and forgets to add it to .gitignore.
The file gets committed with credentials.
Removing Only the Current Value
A developer deletes the credential from the latest source code but forgets that it exists in previous commits.
Using Production Credentials Locally
Using production credentials during development increases the impact of accidental exposure.
Development and production credentials should normally be separated.
Sharing Secrets Through Pull Requests
Putting credentials in pull request descriptions, issue comments, or screenshots can create another exposure path.
Treating Security Alerts as False Positives Without Investigation
Some values may look like secrets but are not active credentials.
That does not mean every alert should simply be dismissed. Verify what the value represents before deciding how to handle it.
Best Practices for Supabase and Pydantic-Based Applications
Keep Credentials Outside Source Code
Use environment variables or an appropriate secret-management solution.
import os
supabase_key = os.getenv("SUPABASE_KEY")
if not supabase_key:
raise RuntimeError("SUPABASE_KEY is not configured")
Failing early is better than silently running with an invalid configuration.
Use Separate Credentials for Different Environments
Maintain separate credentials for:
- Local development
- Testing
- Staging
- Production
If a development credential is exposed, the production environment should remain isolated.
Give Credentials the Minimum Required Access
A token should only have the permissions required by the application.
If a credential only needs read access, avoid giving it unnecessary write or administrative permissions.
Rotate Credentials Regularly
Rotation limits the lifetime of a compromised credential.
The rotation process should also be tested so that replacing a credential does not unexpectedly break production deployments.
Review Security Alerts Promptly
A secret-scanning alert should have an owner and a defined response process.
Teams should know:
- Who investigates the alert.
- Who can revoke the credential.
- How replacement credentials are deployed.
- How repository history is cleaned when necessary.
- How the incident is documented.
Advantages
GitHub's expanded secret detection provides several practical benefits.
Better Coverage
Detecting additional token types increases the number of credentials that can be identified automatically.
Earlier Detection
A repository-level alert can help developers discover accidental exposure before the problem becomes a larger security incident.
Less Manual Searching
Developers do not need to manually inspect every commit looking for known credential formats.
Useful for Security Teams
Security teams can use secret-scanning alerts as part of a broader application-security workflow.
Disadvantages and Limitations
Secret scanning is useful, but it does not solve every secret-management problem.
It Cannot Prevent Every Secret From Being Exposed
A secret may be stored in an unsupported format or service.
Detection Is Not Remediation
Finding a credential does not automatically revoke or replace it.
The development team still needs to respond.
False Positives Can Occur
Some strings may resemble credentials without actually being usable secrets.
Secrets Can Exist Outside Git
Credentials may also be exposed through:
- CI/CD logs
- Build artifacts
- Application logs
- Screenshots
- Chat messages
- Issue descriptions
- Configuration systems
- Container images
Secret scanning should therefore be one part of a larger security strategy.
Troubleshooting Secret-Scanning Alerts
If an alert appears, start with the actual value and its origin.
Check the following:
- Is the detected value a real credential?
- Which service generated it?
- Is it still active?
- What permissions does it have?
- Which commit introduced it?
- Does the credential exist in other branches?
- Does it exist in Git history?
- Does it appear in CI/CD configuration?
- Has the credential been rotated?
- Has the old value been removed from places where it is no longer needed?
Do not close the alert simply because the current version of the file no longer contains the value.
A Safer Configuration Pattern
A better application configuration looks like this:
import os
class Settings:
supabase_url = os.getenv("SUPABASE_URL")
supabase_key = os.getenv("SUPABASE_KEY")
def validate(self):
if not self.supabase_url:
raise RuntimeError("SUPABASE_URL is missing")
if not self.supabase_key:
raise RuntimeError("SUPABASE_KEY is missing")
The application code contains the configuration names, not the actual credentials.
For deployment, the values are supplied by the hosting or CI/CD environment.
This separation makes it easier to:
- Change credentials without changing source code
- Use different credentials per environment
- Rotate credentials
- Keep sensitive values out of Git
- Reduce accidental exposure
Production Checklist
Before deploying an application that uses external tokens or credentials, verify:
- Secrets are not hardcoded in source files.
.envand other local configuration files are ignored where appropriate.- Production credentials are separate from development credentials.
- CI/CD secrets are stored using secure secret configuration.
- Credentials have the minimum required permissions.
- Secret-scanning alerts are reviewed.
- Exposed credentials are rotated immediately.
- Old credentials are removed from active systems.
- Git history is considered when a credential has already been committed.
- Application logs do not print sensitive configuration values.
Summary
GitHub Secret Scanning provides an important safety net for development teams. The addition of detection for Supabase and Pydantic-related tokens is particularly useful for projects that depend on these technologies and may store their credentials in application configuration.
The most important lesson is that secret scanning should not be treated as the primary place where security starts. Developers should avoid hardcoding credentials, use environment-based configuration, separate credentials between environments, and apply least-privilege access.
When GitHub detects a real credential, the correct response is not simply to delete the value from the file. The credential should be treated as potentially compromised, rotated or revoked, and removed from places where it should not exist.
Good secret management is ultimately about reducing the chance that a credential reaches Git in the first place, while having reliable detection and response when mistakes happen.

Join the conversation! Your thoughts help the community grow.