Commit Secret Guard

Scans the lines a diff adds for keys, passwords and high-entropy strings, so credentials are noticed before they go into a commit.

StopsAPI key committed to git

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/commit-secret-guard.json

The files land in your project. They're yours to edit.

Usage

commit-secret-guard-usage.tsx
import { CommitSecretGuard } from "@/components/ui/commit-secret-guard"

<CommitSecretGuard
  key={String(pushed)}
  diff={DIFF}
  pushed={pushed}
  onResolve={(_, __, fix) => setLog(fix.kind === "replace-line" ? `Patched ${fix.file}:${fix.line}` : fix.kind === "remove-line" ? `Dropped ${fix.file}:${fix.line}` : fix.kind === "command" ? `Ran: ${fix.command}` : "Added to the allowlist.")}
  onCommit={() => new Promise<void>((resolve) => setTimeout(() => (setLog("Committed with no secrets."), resolve()), 700))}
/>

What it catches

  • Provider key formats (AWS, GitHub, Stripe, OpenAI, Slack and others) and private keys
  • Passwords embedded in URLs and hard-coded secrets
  • High-entropy strings that look like tokens
  • .env and key files added to the commit
  • Changes already pushed, with a rotate-now link for the provider

Props

CommitSecretGuard props
PropTypeDefault
diff* (required)

Unified diff to check (`git diff --cached`, or a PR's .diff). Only added lines are scanned.

string—
pushed

True when these commits are already on a remote (a PR diff, a pre-push hook): every finding then says to rotate.

booleanfalse
fixturePatterns

Globs for test fixtures. Generic and entropy hits there are ignored; live provider keys are still flagged.

string[]DEFAULT_FIXTURE_PATTERNS
value

Controlled resolutions by finding id.

Record<string, SecretResolution>—
defaultValue

Initial resolutions when uncontrolled, e.g. ids your allowlist already holds as "allowed".

Record<string, SecretResolution>{}
onValueChange

Called with all resolutions whenever one changes.

(value: Record<string, SecretResolution>) => void—
onResolve

Called with what to apply when a finding is resolved: a replacement line, a removed line, a git command or an allowlist id.

(finding: SecretFinding, resolution: SecretResolution, fix: SecretFix) => void—
onCommit

Shows the commit button; enabled once every finding is handled. May return a Promise for a pending state.

() => void | Promise<void>—
messages

Any visible string.

Partial<CommitSecretMessages>—

* required. Also accepts the native props of <div> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Findings are a labelled list that can receive focus
  • Focus moves to the next unresolved finding or the commit button
  • Each finding states its file, line and kind in text
  • Rotate links open in a new tab with rel="noreferrer noopener"

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

This is a UX guard rail. Enforce on the server: Run secret scanning in CI or as a pre-receive hook, and rotate any credential that was pushed.

  • Pattern and entropy based: it can miss custom secret formats and flag random-looking test data
  • Only scans the diff you pass; history and other branches are not checked
  • Marking a false positive is your call; it does not verify the key is inactive

What it stops

API key committed to git

Also known as

git · commit · secret scanning · pre-commit · .env · gitleaks · diff · api key

Dependencies

Pairs well with