How would you integrate SAST, dependency scanning, and secrets scanning into a CI/CD pipeline without making every single PR painfully slow?
Short Answer
Split scans by cost and urgency: run fast, high-signal checks (secrets scanning, incremental/diff-based SAST on changed files) synchronously and blocking on every PR, and push slow, whole-repo scans (full dependency tree audits, deep SAST) to a separate async schedule (nightly, or on merge to main) that reports findings without blocking every individual PR — combined with tuning severity thresholds so only high-confidence, high-severity findings block merges, keeping noise low enough that engineers don't start ignoring the tool.
Detailed Explanation
The naive approach — bolt all three scanners onto every PR pipeline as blocking steps — fails for two related reasons: it makes CI slow (full SAST and full dependency-tree scans can easily take minutes on any nontrivial codebase), and it generates enough low-confidence findings that engineers learn to click through security gates without reading them, which defeats the entire purpose. The fix is treating "run on every PR" and "run comprehensively" as separable, not the same requirement.
Secrets scanning is naturally fast and high-signal (matching known secret patterns against a diff), so it belongs on every PR as a blocking check — a leaked credential is unambiguous and worth blocking on immediately, and scanning just the diff (not the whole repo history) keeps it fast.
SAST can be split: a fast incremental pass against only the changed files runs on every PR (catching new issues introduced by that change), while a deeper, whole-codebase pass runs on a schedule (nightly, or on merge to the default branch) and reports into a dashboard/issue tracker rather than blocking anyone's PR. This catches both "don't introduce new problems" (fast path) and "surface existing problems for prioritized cleanup" (slow path) without making either goal block the other.
Dependency scanning is usually the slowest of the three if done thoroughly (resolving a full dependency tree and checking every transitive package against a vulnerability database), so it's the best candidate for caching — most CI dependency-scan tools support caching the resolved tree and vulnerability database locally, only re-checking what changed. Combined with only failing the build on new, high/critical-severity vulnerabilities introduced by the current change (not the entire pre-existing backlog of medium-severity findings in transitive dependencies), this keeps the check fast and actionable rather than an undifferentiated wall of findings.
Across all three, severity-based gating matters as much as the split between sync/async: a scanner that blocks on every low-severity finding trains engineers to bypass or ignore it; a scanner that blocks only on high-confidence, high-severity, newly-introduced findings stays credible and actually gets acted on.
Interview Follow-Up Questions
- How would you handle a pre-existing backlog of medium-severity findings that predates this rollout, without blocking every team's work on day one?
- How would you measure whether engineers are actually acting on scan findings versus just dismissing them?
- What's the trade-off between running scans as a separate CI job versus as a pre-commit/pre-push local hook?
Key Takeaways
- Split scanning into a fast, blocking, diff-scoped pass on every PR and a slower, comprehensive, scheduled pass that reports without blocking.
- Secrets scanning is cheap enough to always run blocking on every PR; full SAST and full dependency-tree audits are not.
- Gate merges only on high-confidence, high-severity, newly-introduced findings — blocking on everything trains engineers to ignore the tool.
- Caching resolved dependency trees and vulnerability databases is the main lever for keeping dependency scanning fast.
References
Last updated August 21, 2026 · Last reviewed August 21, 2026