CI security checks
CI security checks are scanners that run automatically on every pull request: secret scanning for credentials, static analysis (SAST) for unsafe code patterns and software composition analysis (SCA) for vulnerable dependencies. A written gate decides which findings stop the merge and which go to an owner's backlog.
They catch mechanical mistakes while the author still has the change open: a token pasted into a config file, SQL built from a request parameter, a new dependency with an advisory. A reviewer can miss these in a long diff; a scanner checks every change the same way. NIST's minimum standard for developer verification (NISTIR 8397) includes static analysis, a search for hardcoded secrets and checks of included code.
- Who
- Platform or AppSec engineers set up the checks and the gate; the author of each pull request fixes or triages what they report
- When
- On every pull request before merge, plus a scheduled full scan of the default branch for new advisories
- How often
- Every pull request; full scans nightly or weekly; gate rules and open exceptions reviewed on a fixed schedule
- You end up with
- Required status checks, a written gate policy, findings tracked with owners, and an exception file with reasons and expiry dates
Do this
Start with secrets and dependencies
Adopt first the checks that give the best precision for the least tuning: secret scanning that reads Git history, such as gitleaks or TruffleHog, and SCA on lockfiles, such as OSV-Scanner, Trivy or Grype. Add SAST, such as Semgrep or CodeQL, next, then IaC scanning if infrastructure lives in the repository. Scan a lockfile that records what you actually install, because a scanner that resolves versions itself can report different ones.
Scan each pull request and the whole branch on a schedule
Pull request scans catch what the change adds. A scheduled scan of the default branch catches new advisories against code nobody changed, and a full-history secret scan finds tokens that a later commit deleted. A pre-commit secret hook gives the fastest feedback, but anyone can skip it with
git commit --no-verify, so repeat the scan in CI and turn on server-side push protection where your platform offers it.Write down what blocks a merge
A common rule: block when the change introduced the finding, the rule or advisory is one you trust, and the author can fix it now; report everything else to an owner. Diff-aware modes make this practical: Semgrep's
--baseline-commitshows only findings absent from the base commit, and OSV-Scanner's pull request workflow compares scans of the target and feature branches. Treat any real secret as blocking. NIST SSDF task PO.4.1 asks for these criteria to be defined.Make the checks required and protect the scanners
Mark each blocking check as a required status check in branch protection or rulesets, so a merge cannot skip it. Scanners run next to your source and often your secrets, so pin scanner actions to commit SHAs and tool images to digests, and update them through reviewed pull requests. In March 2026 attackers force-pushed 76 of 77 trivy-action version tags to malicious commits that collected CI secrets; Trivy images referenced by digest were not affected.
Route findings to owners in one place
Publish results as SARIF 2.1.0, the OASIS format that code scanning services and most finding trackers import, so one view covers every tool. Triage within an agreed time: fix true positives or open a ticket with an owner and a due date, and record each false positive with its reason. NIST SSDF task PW.7.2 asks you to record and triage all discovered issues in the team's workflow or issue tracking system.
Give every exception a reason and an expiry date
Suppress one finding in one place, in a file reviewed like code:
ignoreUntilinosv-scanner.toml,exp:in.trivyignore, anosemgrepcomment with a reason, or a fingerprint in.gitleaksignore. A suppression with a date lapses instead of lasting forever. Count expired and renewed exceptions: a growing pile means the gate is wrong or nobody owns the backlog. Exceptions and metrics covers approving and measuring them.Prove each gate fails when it should
On a test branch, commit a fake token that matches your secret scanner's rules but grants nothing, add a dependency with a known advisory, and add one flaw your SAST rules should catch. Each job must fail and name the finding. Repeat after tool or rule upgrades: a gate that never fails may be scanning the wrong directory or ignoring the tool's exit code.
Done when
The blocking criteria are written down, findings are triaged within an agreed time, and exceptions expire.
Mark it in the gap checkCommon mistakes
- Blocking on every existing finding on day one. Developers learn to override or disable the gate; block on what the change introduces and work the old backlog separately.
- Reading a green pipeline as secure. Each scanner sees one representation of the code and none knows your authorization rules, so a missing ownership check passes them all; Automated security tests covers that gap.
- Relying on a pre-commit hook alone. It can be skipped, so the secret still reaches the remote, and deleting the commit later does not revoke the credential.
- Silencing one false positive by disabling a whole rule or directory, which also hides the next real finding there.
- Pulling scanners by mutable tags into jobs that hold secrets, which turns one compromised tool release into a compromised pipeline.
- Leaving findings in a dashboard with no owner or due date. The check becomes noise that everyone learns to ignore.
What each check scans and when it blocks
A common starting policy. Adjust the blocking column to what a developer can fix within one pull request.
| Check | Scans | Blocks the merge when | Reported only |
|---|---|---|---|
| Secret scanning | The pull request's commits; full history on a schedule | Any match that is not a recorded false positive | Matches in old history, which still need rotating |
| SAST | Changed code, compared with the base commit | A new finding from a high-severity rule you trust | Existing findings and lower-confidence rules |
| SCA | Lockfiles and manifests | The change adds a dependency with a known vulnerability that has a fix | New advisories against unchanged dependencies, from the scheduled scan |
| IaC scanning | Terraform, Kubernetes manifests and Dockerfiles | One of a short list of critical checks fails, such as public storage or an open admin port | Every other failed check |
Tools and guides
- Tool: OSV dependency lookup
- Workflow: Fix a finding
- Place each security control in the pipeline and decide what it blocks
Put secrets scanning, SAST, SCA, IaC and image scanning, DAST, fuzzing, attestation and admission control where each sees the right input, block only on findings a developer can act on, and deploy only images the pipeline has attested.
- Choose and evaluate application security testing tools
What SAST, DAST, IAST, SCA, secrets, IaC, container and API scanners and ASPM each find and miss, where each runs, how to evaluate them on a seeded repository with per-CWE scoring and triage cost, and which to adopt first.
- Approve, expire and measure security exceptions without hiding risk
Keep temporary acceptance separate from remediation and measure outcomes using definitions that survive changing visibility.
Standards
- NIST SSDF 1.1
- PO.3 Implement Supporting ToolchainsPO.4 Define and Use Criteria for Software Security ChecksPW.7 Analyze Human-Readable Code to Identify Vulnerabilities and Verify Compliance with Security Requirements
- OWASP SAMM 2
- Security TestingSecure BuildDefect Management
Sources
- NIST IR 8397: Guidelines on Minimum Standards for Developer Verification of Software. July 2021, with October 2021 errata.
- NIST SP 800-218: Secure Software Development Framework (SSDF) Version 1.1. February 2022.
- OWASP CI/CD Security Cheat Sheet
- Semgrep: CLI reference (--baseline-commit, --error, --severity)
- OSV-Scanner: GitHub Action and pull request scanning
- OSV-Scanner: configuration (ignored vulnerabilities and ignoreUntil)
- Trivy: filtering (.trivyignore and exp:)
- GitHub Docs: Push protection
- GitHub Advisory GHSA-69fq-xp46-6x23 (CVE-2026-33634): Trivy ecosystem supply chain compromise
- OASIS Static Analysis Results Interchange Format (SARIF) Version 2.1.0. OASIS Standard incorporating Approved Errata 01, 28 August 2023.
- OWASP SAMM: Security Testing