Security Pre-Commit Check

SkillSecurity

Pre-commit security scanner for git repos — blocks API keys, proxy credentials, private keys, and project-specific secrets before they reach a remote. Provides a central rule definition + per-repo customization + one-line installer that wires up `.git/hooks/pre-commit`. Use when you want to prevent accidental credential / identity / brand leaks across multiple repos. Triggers on "set up pre-commit security check", "block API keys in commits", "git secret scanner", "prevent credential leaks", "protect identity isolation in public repos".

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Security Pre-Commit Check skill

What this skill tells your AI

The instructions your AI receives, as published by noique/cross-border-ecommerce-skills in tools/security-precommit-check/SKILL.md and read by ahel’s review.

Layered defense against accidental secret / identity leaks in git commits. Combines a central scanner + universal rule set (this skill) with per-repo custom rules and one-line installer that wires up .git/hooks/pre-commit.

Architecture

tools/security-precommit-check/
├── SKILL.md                                      ← this file
├── scripts/
│   ├── scan.sh                                   ← scanner (called by hook OR ad-hoc)
│   └── install-hook.sh                           ← one-line installer per repo
├── rules/
│   └── default.txt                               ← universal rules (API keys / proxies / paths)
└── templates/
    └── security-precommit-rules.txt.example      ← copy to each repo as starting point

In each repo where you install the hook:

<repo>/
├── .git/hooks/pre-commit                         ← auto-generated by install-hook.sh
└── .security-precommit-rules.txt                 ← per-repo rules (loaded in addition to default)

The hook delegates to scripts/scan.sh --staged, which reads BOTH default.txt (universal) AND the repo's .security-precommit-rules.txt (per-project).

Install (one line per repo)

# Replace this path with where you cloned cross-border-ecommerce-skills
SKILLS=~/Documents/Code/cross-border-ecommerce-skills
cd /path/to/your/repo
$SKILLS/tools/security-precommit-check/scripts/install-hook.sh

The installer:

  1. Writes .git/hooks/pre-commit (idempotent — re-run to refresh)
  2. If .security-precommit-rules.txt doesn't exist in your repo, copies the template

After install, every git commit runs the scanner against staged files. BLOCK matches refuse the commit; WARN matches print a warning but allow.

Bypass (when intentional)

git commit --no-verify -m "..."

Ad-hoc scan (without commit)

# Scan all tracked files (good for initial audit on existing repos)
$SKILLS/tools/security-precommit-check/scripts/scan.sh --all

# Scan specific files
$SKILLS/tools/security-precommit-check/scripts/scan.sh --files path1 path2

# Scan staged files (default — same as the hook)
$SKILLS/tools/security-precommit-check/scripts/scan.sh

Selftest — run this after ANY rule edit

$SKILLS/tools/security-precommit-check/scripts/selftest.sh   # exit 0 = every rule is alive

Every rule in rules/default.txt must fire on a known-positive sample in rules/selftest-samples.txt (DESCRIPTION|SAMPLE, all values synthetic). The scanner fails open, in two ways, and only the first is visible:

FailureSymptomCaught by
Invalid regexscan.sh prints dropping invalid rule regexthe warning — but only if you read it
Valid regex that matches nothingnothing at all — the rule looks like coverageonly the selftest

The second class is why this exists. \| inside a group is a LITERAL pipe in ERE, not alternation, so (api[_-]?key\|secret[_-]?key) matched only the text api_key|secret_key — dead, silently, for its whole life. Add a positive control with every new rule; a rule without one fails the selftest.

The selftest also asserts benign lines trip no BLOCK rule (an over-broad rule teaches people to --no-verify, which costs more than it saves) and that the generic sk- rule does not shadow the vendor-specific Anthropic/OpenAI ones.

Rule format

SEVERITY|PATTERN|DESCRIPTION
  • SEVERITY = BLOCK (rejects commit) or WARN (prints warning, exit 0)
  • PATTERN = extended-regex passed to grep -E
  • DESCRIPTION = human-readable label (printed in scanner output; the selftest's sample key)

Lines starting with # and blank lines are ignored.

🔴 POSIX ERE only — no PCRE. No (?!…) lookahead, no (?=…), no \d/\w shorthand you rely on. Write | for alternation unquoted — the parser takes SEV as the first field and DESC as the last, so a pattern may contain pipes freely; escaping them as \| silently turns them into literal characters.

What's in rules/default.txt (universal)

SeverityCategoryExamples
BLOCKAPI keysAnthropic / OpenAI / GitHub PAT / Slack / AWS / Stripe
BLOCKConnection stringshost:port:user:pass proxy strings, postgres / mysql / mongodb URLs with embedded password
BLOCKPrivate keysPEM private keys, JWT tokens
WARNPersonal paths/Users/{name}/... and /home/{name}/...
WARNHardcoded literalspassword = "..." and api_key = "..." patterns

What goes in your .security-precommit-rules.txt (per-repo)

Repo typeExample rules
Public skill / template repo (e.g. cross-border-ecommerce-skills)BLOCK / WARN: founder real name, project-specific competitor names, internal Org-only hostnames
Private project repoMostly empty — project-specific terms ARE expected here. Maybe BLOCK known-leaked credentials so re-paste fails
Open-source libraryWARN founder email; BLOCK known internal hostnames
Engineering platform repo (e.g. internal services)BLOCK production hostnames / DB URLs; WARN dev hostnames

See templates/security-precommit-rules.txt.example for a starting point.

Layered defense — relationship to other security practices

This hook is layer 3. It does NOT replace:

  • Layer 1 — Rotate secrets when leaked. A hook can't fix what's already on a remote. If you find a leaked credential, rotate it AT THE PROVIDER, not just commit a redaction.
  • Layer 2 — Configure git author identity. git config user.name / user.email is set per-commit; this scanner doesn't touch that. Ensure your ~/.gitconfig uses an anonymized noreply email if you don't want your real email in commit metadata.
  • Layer 3 — This hook. Prevents accidental commits of new secrets / identity strings going forward.
  • Layer 4 — History hygiene. If past commits have secrets, git filter-repo + force-push is the only way to scrub them. Reserve for cases where rotation isn't enough (e.g. permanent credentials).

False-positive handling

If the scanner BLOCKs a legit string:

  1. First, double-check it's actually OK to commit. Most "false positives" are real near-misses worth fixing (env-var instead of literal, etc.).
  2. If genuinely OK: git commit --no-verify for that one commit; don't disable the hook.
  3. If a pattern false-positives consistently: tune the regex in default.txt (PR back to this skill repo) or shadow it via a more specific WARN in your per-repo rules.

Caveats / known limitations

  • Pattern-based scanning will miss base64-encoded secrets, secrets concatenated from multiple variables, and binary-encoded credentials. This skill catches the obvious paste-from-clipboard cases — it's not a full secret-scanning solution like TruffleHog / git-secrets / gitleaks.
  • The grep -E engine doesn't support negative lookahead, so some "exclude localhost" rules are approximated via positive constraints (e.g. requiring user/pass length ≥ 8).
  • Hook only fires on git commit. git push --force of an already-committed bad blob won't be caught — keep secrets out at commit time.

Related

  • For full repo-history scanning of past leaks, see gitleaks or trufflehog.
  • For automated rotation workflows after a leak: out of scope for this skill.

Signals

GitHub stars
50
Forks
6
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
security-precommit-check
Source
github.com/noique/cross-border-ecommerce-skills