On December 9, 2021, a single deserialization flaw in Apache Log4j — CVE-2021-44228, better known as Log4Shell — scored a perfect 10.0 on CVSS and put hundreds of millions of Java applications at risk, not because of code any of those teams wrote, but because of a logging library sitting three or four dependencies deep in their build. Chen Zhaojun at Alibaba Cloud had reported it privately just two weeks earlier, on November 24. NIST would go on to publish SP 800-218, the Secure Software Development Framework (SSDF), less than two months after Log4Shell broke — organizing secure development into four practice groups: Prepare the Organization, Protect the Software, Produce Well-Secured Software, and Respond to Vulnerabilities — and a draft SSDF v1.2 (SP 800-218 Rev. 1) later opened for public comment in December 2025. The framework arrived after the fact; the gate that would have flagged a vulnerable transitive dependency before release did not exist in most of the affected organizations, then or since. That gap — a documented standard versus an actually-enforced checkpoint — is the subject of this guide: where to place threat modeling, static analysis, dependency scanning, dynamic testing, and penetration testing so each one blocks bad code from advancing, rather than auditing it after the fact.
What does "gate" mean versus a one-time security review?
A gate is a checkpoint a build or release cannot pass without meeting a defined condition — block, warn, or require approval — enforced automatically, not a human reading a report weeks later. OWASP SAMM v2.0, released in 2020, formalizes this distinction by scoring five business functions (Governance, Design, Implementation, Verification, Operations) on both coverage and quality, which forces teams to admit that a control run once on one project isn't the same as a control that fires on every pull request. A one-time review produces a PDF; a gate produces a pass/fail signal a CI pipeline can act on, typically configured as block-on-critical, warn-and-continue, or require-manual-approval for exceptions with an expiration date. Practically, this means threat modeling isn't a workshop you did last year, SAST isn't a scan someone ran before a big launch, and dependency scanning isn't a spreadsheet — each is a rule evaluated automatically at a specific point in every single change that moves toward production.
Where does threat modeling belong, and what does it catch that scanners can't?
Threat modeling belongs at design time, before code exists, because it catches architectural and trust-boundary problems that no scanner can find in source — scanners see code, not decisions about what a service should trust. A STRIDE-based session on a new feature (Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege) forces the team to draw data flows and mark every point where trust changes, which is exactly the kind of question — "should this internal service accept unauthenticated requests from that other internal service?" — that a static or dynamic scanner never asks. Log4Shell is again instructive here from the other direction: a threat model of "what happens if a string we log is attacker-controlled and our logging library resolves lookups in it" would have flagged the JNDI-lookup behavior years before disclosure, independent of any scan. The gate here isn't automated pass/fail — it's a required artifact: no design ships to implementation without a documented threat model reviewed by someone outside the feature team.
Where does SAST fit, and what should block a pull request versus just warn?
SAST fits at the pull-request stage, running on every diff before merge, because that is the cheapest point in the lifecycle to fix a bug — before it is built, deployed, or depended on by other code. The gate condition should map to CWE severity, not raw finding count: a rule like "block on any CWE-89 (SQL injection) or CWE-502 (unsafe deserialization) finding above a defined severity, warn on lower-severity style issues" keeps developers from ignoring the tool entirely, which is what happens when every PR gets blocked by a low-risk lint warning. Safeguard's SAST engine, for example, traces untrusted input from source to sink across JavaScript/TypeScript, Python, and Java, attaching the full dataflow path to each finding — the difference between "there's a call to a query function" and "here is the exact request parameter that reaches it unsanitized," which is what a merge-blocking gate needs to be trustworthy rather than noisy.
Where does dependency scanning (SCA) fit, and how should findings be prioritized?
Dependency scanning fits continuously — on every build and again whenever the vulnerability feed itself updates, since a dependency you pinned safely six months ago can become critical overnight without a single line of your code changing. This is precisely the Log4Shell pattern: the vulnerable library was already sitting in the dependency tree before CVE-2021-44228 existed, and only a continuously re-evaluated gate against CVE/GHSA feeds would have caught it the moment the advisory published. Prioritization should combine EPSS (exploit prediction) and the CISA Known Exploited Vulnerabilities list with reachability — whether your code actually calls the vulnerable function — so a security team isn't stuck triaging hundreds of theoretical findings equally. Safeguard's SCA resolves the full transitive dependency graph, enriches matches with EPSS/KEV context, and cross-references reachability so a vulnerable-but-uncalled function is deprioritized without being suppressed outright, since malware and secrets findings are never allowed to be silently dropped regardless of reachability.
Where does DAST fit, and why does target verification matter as a gate itself?
DAST fits pre-release, against a staging or pre-production environment that mirrors production closely enough for findings to transfer, because it tests behavior a static scanner cannot see — how the running application actually responds to a crafted request, missing security headers, or a misconfigured endpoint. The verification step is itself a gate, and a defensive one: a target must prove ownership (DNS TXT record, file upload, meta tag, or verified email domain) before any active check runs against it, and out-of-scope hosts or paths get blocked and logged rather than silently skipped. Safeguard's DAST engine enforces this in code rather than as a UI convenience — passive, safe_active, and authenticated_safe_active modes cover normal use, while a heavier lab_aggressive mode stays off by default and requires elevated authorization plus an explicitly owned-and-isolated target. When a DAST finding correlates back to the exact SAST source-code sink that caused it, that confirmed-and-reachable finding should be the one gate that blocks release outright, ahead of anything still theoretical.
Where does penetration testing fit, and what can't a platform replace?
Penetration testing belongs before major releases and on a recurring cadence (commonly annual, or after significant architecture changes) as a human-driven gate, because a skilled tester chains findings, tests business logic, and improvises in ways automated tools — however good — do not. It's worth being precise about what's automatable and what isn't: breach-and-attack simulation (BAS) and purple-teaming, such as Safeguard's Red Team engine, validate that your detections actually fire against known ATT&CK techniques using benign detection canaries, gated behind a signed rules-of-engagement document, verified in-scope targets, and human approval for high-impact steps — but that is detection validation, not a substitute for an authorized third-party penetration test. Treat BAS as a gate that runs continuously between pen tests, catching detection regressions, while the pen test itself remains the go/no-go checkpoint before a release a regulator, customer, or auditor will scrutinize — SSDF's "Respond to Vulnerabilities" practice group assumes both exist and feed the same remediation process.