SAST reads your code without ever running it.
Modern SAST tools trace where untrusted data (a "source") flows through the code, and flag it if it reaches a dangerous operation (a "sink") with no sanitization in between — taint analysis.
semgrep
# pre-built ruleset against the whole repo semgrep --config=p/security-audit --error . # a custom rule catching hardcoded AWS keys rules: - id: hardcoded-aws-access-key languages: [python] severity: ERROR patterns: - pattern-regex: 'AKIA[0-9A-Z]{16}'
Source → sink, tainted
Source
request.getParameter('id')
→
Sink
raw SQL, no sanitization
Real limitations
- False positives — pattern matching lacks full context
- Blind to runtime/config issues
- Rules are per-language, coverage varies
- No visibility into a dependency's own internals
SAST is cheap and early but structurally blind to anything only visible at runtime — that exact gap is what DAST fills next.