Static code analysis is the automated examination of source code, bytecode, or binaries without executing the program, used to find bugs, security vulnerabilities, and quality issues before code ships. A static analyzer parses code into an abstract syntax tree, builds control-flow and data-flow graphs, and matches the results against a library of known-bad patterns — things like CWE-89 (SQL injection), CWE-79 (cross-site scripting), and CWE-798 (hardcoded credentials). Because it never runs the application, it can scan every line of a 2-million-line codebase in minutes and flag issues in code paths a QA team would never click through. Security teams call the security-focused version of this technique SAST (Static Application Security Testing), and it has been a required control in frameworks like PCI DSS 4.0 (requirement 6.2.4) and NIST's Secure Software Development Framework (SP 800-218) since 2022.
How does static code analysis actually work?
Static analysis works by converting source code into structural representations — an abstract syntax tree (AST), a control-flow graph (CFG), and a data-flow graph — and then running rule sets or taint-tracking algorithms against them. Taint tracking, the technique behind most SAST vulnerability detection, marks any data originating from an untrusted "source" (an HTTP request parameter, a file upload, an environment variable) and traces it through the program until it reaches a dangerous "sink" (a SQL query, a shell command, an eval() call). If tainted data reaches a sink without passing through a sanitizer, the tool flags it. Tools like CodeQL (open-sourced by GitHub in 2019), Semgrep, SonarQube, and Checkmarx static code analysis all use variations of this AST-plus-taint model, though they differ in how deeply they analyze interprocedural flows — i.e., taint that crosses function or file boundaries, which is where most false negatives in cheaper tools originate.
What's the difference between SAST, DAST, and SCA?
SAST analyzes source code before it runs, DAST (Dynamic Application Security Testing) attacks a running application from the outside, and SCA (Software Composition Analysis) inventories third-party and open-source dependencies for known CVEs. A SAST scan can catch a SQL injection flaw in a code review the same day it's written, weeks before the app is ever deployed to a test environment where a DAST scanner like OWASP ZAP or Burp Suite could reach it. SCA, by contrast, isn't reading your code at all — it's matching your package-lock.json or pom.xml against vulnerability databases like the National Vulnerability Database or OSV to catch issues like Log4Shell (CVE-2021-44228), which affected any application bundling Apache Log4j 2.0–2.14.1 regardless of what the application's own code looked like. Mature AppSec programs run all three, because each covers a blind spot the others miss: SAST misses runtime configuration issues, DAST misses code that isn't exercised by the crawler, and SCA misses vulnerabilities in code you wrote yourself.
What vulnerabilities does static analysis actually catch?
Static analysis is strongest at finding injection flaws, insecure API usage, and hardcoded secrets — the vulnerability classes that map directly to fixed code patterns. This includes SQL and NoSQL injection (CWE-89), cross-site scripting (CWE-79), path traversal (CWE-22), insecure deserialization (CWE-502), use of broken cryptographic algorithms like MD5 or DES (CWE-327), and hardcoded API keys or passwords (CWE-798) — the exact class of issue that led to the 2019 Capital One breach vector being discoverable in code review. The 2017 Equifax breach is the canonical counter-lesson: the root cause was a known, patchable vulnerability in Apache Struts (CVE-2017-5638), disclosed in March 2017, that went unpatched for two months before attackers exploited it in May 2017 — a case where SCA and patch management, not SAST, was the missing control. That distinction matters when you're building a scanning program: static code analysis finds flaws in code your team wrote; it does not, by itself, tell you which of your dependencies have disclosed CVEs.
Why do static analysis tools generate so many false positives?
Static analyzers generate false positives because they analyze code without the runtime context needed to know whether a flagged path is actually reachable by an attacker. A taint-tracking engine might flag a variable as "tainted" because it originated from user input three functions ago, even though a validation check the tool didn't model — or a WAF rule, or an internal-only API gateway — makes exploitation impossible in practice. Industry benchmarks have repeatedly shown legacy SAST tools flagging 30-50% or more of findings as noise on large codebases, which is the single biggest reason security teams report alert fatigue and why findings sit unfixed: a developer who's been burned by three false positives in a row starts ignoring the fourth finding, even if it's real. This is also why "shift left" mandates without triage tooling tend to fail — pushing thousands of untriaged findings into a pull request doesn't improve security, it just moves the backlog closer to the deadline.
When should static analysis run in the development lifecycle?
Static analysis should run at commit time in the IDE, again at pull-request time in CI, and as a full baseline scan on a recurring schedule — not just once before a release. IDE-integrated scanning (via a plugin or pre-commit hook) catches issues in the 10-30 seconds after a developer writes the vulnerable line, when fixing it costs nothing because the context is still in their head. CI-gated scanning on every pull request, which NIST SP 800-218 (PW.7) and PCI DSS 4.0 both effectively mandate for regulated software, catches anything that slipped past the IDE and blocks the merge if a critical finding isn't resolved. A full-repository baseline scan, run weekly or on every release branch, catches drift — new CWE patterns added to the rule set, or vulnerable code paths that only became reachable after an unrelated change elsewhere in the codebase. Skipping any one of these three stages recreates the exact backlog-at-release problem static analysis exists to prevent.
How Safeguard Helps
Safeguard runs static and composition analysis together, then uses reachability analysis to determine which flagged code paths are actually exploitable given your application's real call graph — cutting through the 30-50% false-positive noise that makes legacy SAST tools hard to act on. Griffin AI, Safeguard's in-house model, triages every finding, explains the exploit path in plain language, and drafts an auto-fix pull request so engineers can merge a validated remediation instead of researching one from scratch. Because Safeguard ingests and generates SBOMs natively, reachability scoring extends across your first-party code and your open-source dependencies in a single pipeline, so a finding in a transitive dependency gets the same exploitability context as a bug in your own repo. The result is a static analysis program that surfaces the handful of findings that matter on a given day instead of a backlog that grows every sprint.