Secret Scan action

Last updated: Apr 24, 2026


The SS action detects hardcoded secrets and credentials (API keys, passwords, tokens, and similar sensitive data) in your repository. It is free and open source — no account, API key, or registration is required.

Marketplace: fluidattacks/secrets-scan

Scan modes

The action prefers differential scanning whenever a base commit is available, falling back to a full scan only when there is nothing to compare against. The default branch is detected automatically by running git remote show origin, so any branch name (main, master, trunk, develop, etc.) works without configuration.

TriggerModeBase for comparison
Push to any branchDifferential scanCommit before the push (github.event.before)
Pull requestDifferential scanPR base branch
Scheduled / manual triggerFull scan

Both differential modes compare against a known base commit, not just the previous commit, so all changes in a multi-commit push are analyzed. This keeps CI fast while ensuring nothing slips through.

Note: In differential mode, if no files changed, the scan is skipped and no output file is produced. This is expected behavior, not an error.

Setup

1. Create the workflow

Add .github/workflows/secret-scan.yml to your repository:

name: SECRET_SCAN
on:
  push:
  pull_request:
    types: [opened, synchronize, reopened]
  schedule:
    - cron: "0 8 * * 1" # optional: weekly full scan every Monday at 8am

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0 # required: full history enables differential scanning

      - uses: fluidattacks/ss-action@<version> # Use latest released version
        id: scan

      # Optional: upload findings to the GitHub Security tab
      - name: Upload results to GitHub Security tab
        if: always()
        uses: github/codeql-action/upload-sarif@v4
        with:
          sarif_file: ${{ steps.scan.outputs.sarif_file }}

Replace <version> with the latest release tag. Find it on the Marketplace page.

  • fetch-depth: 0 downloads the full git history, which is necessary for the differential scan to resolve the base commit and to detect the default branch via git remote show origin. You can omit it only if you force scanner_mode: full.
  • upload-sarif is optional. When included, run it with if: always() so results are uploaded even when secrets are found.
  • The optional schedule trigger adds a weekly full scan to catch secrets that were already present before you added this workflow.

Restriction: Uploading to the Security tab requires GitHub Advanced Security, which is available on all public repositories and on private repositories under a GitHub Advanced Security license. On private repositories without that license, the upload step will fail.

Without a configuration file, the action scans the entire repository and writes results to .fluidattacks-secret-scan-results.sarif.

2. (Optional) Add a configuration file

To customize scan paths or output format, create a YAML configuration file anywhere in your repository and pass its path to the action via scan_config_path:

- uses: fluidattacks/ss-action@<version>
  id: scan
  with:
    scan_config_path: .github/secret-scan-config.yaml

The path is relative to the repository root. The job fails immediately if the file does not exist at the given path.

3. Push and run

Commit the workflow file and push. The scan runs automatically.

Configuration

When scan_config_path is provided, the action uses that file exclusively. When omitted, the action runs with built-in defaults: scans the entire repository and writes results to .fluidattacks-secret-scan-results.sarif.

Only the ss and output keys are used by this action.

ss:
  include:
    - . # paths to scan (default: entire repo)
  exclude:
    - tests/ # paths to skip

output:
  file_path: .fluidattacks-secret-scan-results.sarif
  format: SARIF

ss.include

A list of paths (files or directories) to scan.

  • Full scan: uses this list, defaulting to . (entire repository) if not set.
  • Differential scan: always uses the list of changed files, regardless of this setting.

ss.exclude

A list of paths to exclude from the scan. Applied in both full and differential modes.

output

FieldDefaultDescription
file_path.fluidattacks-secret-scan-results.sarifPath to the results file
formatSARIFOutput format (SARIF or CSV)

Action inputs

InputRequiredDefaultDescription
scan_config_pathNoPath to the YAML configuration file, relative to the repository root. When omitted, built-in defaults are used. The job fails if the file does not exist.
scanner_modeNo(auto)Override the scan mode. full forces a full repository scan; diff forces a differential scan. If omitted, the mode is set automatically.

Forcing a full scan

Use scanner_mode: full to scan the entire repository on every run regardless of the trigger. This is useful for scheduled audits:

- uses: fluidattacks/ss-action@main
  id: scan
  with:
    scanner_mode: full

Action outputs

OutputDescription
sarif_filePath to the SARIF results file (only set when output.format is SARIF)
vulnerabilities_foundtrue if any secrets were detected, false otherwise

You can use these outputs in subsequent workflow steps:

- name: Comment on PR
  if: steps.scan.outputs.vulnerabilities_found == 'true'
  run: echo "Secrets detected — check the Security tab."

Viewing results

After the workflow runs, findings appear in two places:

  1. GitHub Security tab — Go to your repository → SecurityCode scanning alerts. Each finding shows severity, file location, and the exact line where the secret was detected.
  2. Pull request annotations — On pull requests, findings appear as inline annotations directly in the code diff.

Common scenarios

Scan only specific folders (monorepo)

ss:
  include:
    - services/api/
    - services/web/
  exclude:
    - services/legacy/

Export results as CSV

output:
  file_path: results.csv
  format: CSV

Troubleshooting

No results appear in the Security tab: Make sure the "Upload SARIF" step uses if: always() so it runs even when the scan finds secrets.

Differential scan analyzes all files instead of just changes: Verify that fetch-depth: 0 is set in the actions/checkout step. Without full git history, the action cannot resolve the base commit.

The action doesn't detect my default branch: The action runs git remote show origin to detect the default branch. This requires fetch-depth: 0 in the checkout step so remote metadata is available. If detection fails, verify that the origin remote is correctly configured.

The job fails with "not found in repository": The path provided to scan_config_path does not exist in the repository. Verify the path is correct and relative to the repository root.

Prerequisites

  • A GitHub repository (public or private).
  • GitHub Actions enabled on the repository.
  • A Linux runner (ubuntu-latest or equivalent) — the action requires Docker, which is only available on Linux-hosted runners.

On this page