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:

  1. A developer commits code to a repository.
  2. GitHub scans the repository content for supported secret patterns.
  3. A matching credential is identified.
  4. 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:

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:

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:

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:

  1. Who investigates the alert.
  2. Who can revoke the credential.
  3. How replacement credentials are deployed.
  4. How repository history is cleaned when necessary.
  5. 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:

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:

  1. Is the detected value a real credential?
  2. Which service generated it?
  3. Is it still active?
  4. What permissions does it have?
  5. Which commit introduced it?
  6. Does the credential exist in other branches?
  7. Does it exist in Git history?
  8. Does it appear in CI/CD configuration?
  9. Has the credential been rotated?
  10. 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:

Production Checklist

Before deploying an application that uses external tokens or credentials, verify:

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.