An automated secret-scanning gate exists in the CI or pre-commit change path
Why it matters
A one-time secrets sweep tells you what has already leaked; a scanning gate in the change path is what stops the next leak, and the next one is coming: GitGuardian measured 23.8 million new secrets pushed to public GitHub in 2023 alone, and the Toyota incident (an access key sitting in a public repo for five years) shows how long a single miss survives. This evidences SOC 2 CC7.1 (detection and monitoring of configuration changes and vulnerabilities): the auditor wants to see a recurring, automated detection mechanism, not a clean point-in-time grep. AI-generated and vibe-coded apps typically fail here because coding assistants scaffold the app and sometimes even a test workflow, but no tutorial-shaped prompt ever adds gitleaks or trufflehog to CI, so the change path ships with zero secret detection while .env values migrate into committed config during rapid iteration. One leg of this check is an evidence-pointer: GitHub's native secret scanning and push protection live in repo settings that are invisible from a clone, so a committed doc stating they are enabled counts as the evidence an auditor will ask for, with the detail noting it is doc-evidenced rather than directly observed.
Severity rationale
Medium because this is a layered detective control: its absence does not itself expose a secret, it removes the automated gate that would catch the hardcoded credentials other checks score directly, so exposure accrues on the next mistake rather than immediately.
Remediation
Add a blocking gitleaks step to your CI workflow, e.g. in .github/workflows/ci.yml:
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Do not add continue-on-error: true; the step must be able to fail the build. Alternatively wire gitleaks protect --staged into .husky/pre-commit or add the gitleaks hook to .pre-commit-config.yaml. If you rely on GitHub's built-in secret scanning with push protection instead, enable it in repo settings and commit a short note in SECURITY.md stating that it is enabled, so the control is evidenced in the repo an auditor reviews.
Detection
- ID:
secret-scanning-in-ci - Severity:
medium - What to look for: First enumerate CI configuration:
.github/workflows/*.ymland*.yaml,.gitlab-ci.yml,.circleci/config.yml,bitbucket-pipelines.yml,Jenkinsfile,azure-pipelines.yml. Then search four pass legs. (1) CI step invoking a dedicated secret scanner:uses: gitleaks/gitleaks-action@...,gitleaks detect/gitleaks git/gitleaks protectin arun:step,uses: trufflesecurity/trufflehog@...ortrufflehog git|filesystemin arun:, ordetect-secrets scan/detect-secrets-hook. Include indirect invocations: apackage.jsonscript,Makefiletarget, ornoxfile.py/tox.inisession that runs one of these tools AND is itself called from a CI step. (2) Commit-time hook config:.pre-commit-config.yamlcontaining a gitleaks, trufflehog, or detect-secrets hook (e.g.repo: https://github.com/gitleaks/gitleakswithid: gitleaks, orid: detect-secrets); JS-ecosystem equivalents count the same way:.husky/pre-commitorlefthook.ymlinvoking one of the three scanners. (3) Committed scanner config (.gitleaks.toml/gitleaks.toml,.secrets.baseline,trufflehog.yaml/.trufflehog.yaml) paired with a CI invocation of the matching tool per leg 1. (4) Evidence-pointer doc: a committed document (SECURITY.md,README.md,docs/**,compliance/**) explicitly stating that GitHub secret scanning and/or push protection is enabled for this repo. - Pass criteria: Any one of the four legs is satisfied with the invocation live (not commented out, not gated behind
if: false, exit code not swallowed). Leg 4 passes on the doc alone, since the host-side setting is invisible from a clone, but the receipt must note it is doc-evidenced. - Fail criteria: CI configuration exists and none of the four legs is satisfied. Sneaky variants that still fail:
gitleaks,trufflehog, ordetect-secretspresent inpackage.jsondevDependencies orrequirements*.txtwith no CI step or hook ever invoking it (vocabulary presence is not a gate); a scanner step that is commented out, behindif: false, or in a workflow triggered only byworkflow_dispatchwith no push/PR trigger; a scannerrun:suffixed|| trueor a step withcontinue-on-error: true(it can never block a change, so it is not a gate); a committed.secrets.baselineor.gitleaks.tomlwith no invocation anywhere (leg 3 requires the pairing); a.pre-commit-config.yamlthat exists but contains no secret-scanning hook; a doc that merely recommends enabling secret scanning without stating it is enabled. - Skip (N/A) when: No pass leg is satisfied AND no CI configuration exists at all: the CI-absence root cause is already scored by this audit's automated-tests check, so do not double-punish it here. Quote:
"No CI configuration found (.github/workflows/, .gitlab-ci.yml, .circleci/config.yml, bitbucket-pipelines.yml, Jenkinsfile, azure-pipelines.yml all absent) — CI absence is scored by the automated-tests check". - Before evaluating, quote: The satisfying evidence verbatim with its file path: the CI step or
run:line (leg 1), the hook stanza (leg 2), the config filename plus the CI line invoking the tool (leg 3), or the doc sentence claiming secret scanning / push protection is enabled (leg 4). On fail, list the CI files found (proving CI exists) and state that a search for gitleaks, trufflehog, detect-secrets, and a secret-scanning doc across workflows, hook configs, and docs returned nothing live. - Report even on pass:
"Secret-scanning gate: <tool> via <path> (blocking CI step | pre-commit hook | config + CI invocation | doc-evidenced GitHub push protection)". - Detail on fail:
"CI exists (.github/workflows/ci.yml, deploy.yml) but no secret-scanning step, hook, or doc found; gitleaks is in devDependencies yet nothing in any workflow, .husky/, or .pre-commit-config.yaml invokes it"or"gitleaks step in .github/workflows/ci.yml has continue-on-error: true, so findings can never block a merge — not a gate; no other scanner or push-protection doc found. If the control lives in GitHub repo settings, commit evidence of it (e.g. a SECURITY.md note)". - Remediation: Add a blocking
gitleaks/gitleaks-actionstep to.github/workflows/ci.yml(nocontinue-on-error), or wiregitleaks protect --stagedinto.husky/pre-commit, or add thegitleakshook to.pre-commit-config.yaml. If you use GitHub's native secret scanning with push protection instead, enable it and commit a note inSECURITY.mdstating it is enabled. This gate prevents the next leak; already-committed secrets are scored by theno-hardcoded-secretscheck in theproject-snapshotStack Scan.
External references
- soc2:2017 · CC7.1 — Detection and monitoring of configuration changes and vulnerabilities
- iso-27001:2022 · A.8.8 — Management of technical vulnerabilities
- nist:rev5 · RA-5 — Vulnerability Monitoring and Scanning
Taxons
History
- 2026-07-03·v1.0.0·Initial soc2-readiness v1 authoring, an automated secret-scanning gate in the change path (CI step, pre-commit hook, config plus invocation, or doc-evidenced GitHub push protection) evidences SOC 2 CC7.1 detection and monitoring.·by soc2-readiness-v1-build