SAST and DAST
Static application security testing (SAST) reads source or compiled code without running it and flags risky data flows, such as request input reaching a SQL query. Dynamic testing (DAST) sends requests to a running application from outside and reports how it responds.
Each sees what the other cannot. A static rule can trace request.args into cursor.execute on a route no test reaches; a dynamic scan shows what the deployed build, with its real configuration, returns. Neither knows your authorization rules, and OWASP warns that SAST produces many false positives and rarely finds access control or configuration flaws, so a finding counts once a request reproduces it.
- Who
- Developers triage results for their own code; AppSec writes project rules and owns the scanner setup
- When
- Static rules on every pull request; dynamic scans against a test deployment of each release candidate, before it ships
- How often
- SAST on every change plus a full scan nightly; an authenticated DAST scan nightly or on each release candidate
- You end up with
- Results tied to a commit and a deployed digest, a reproducing test for each confirmed finding, and a reviewed list of suppressions
Do this
Pick tools that understand your stack
Choose a static analyzer that supports your languages and frameworks, such as Semgrep, CodeQL, Bandit or gosec, and a dynamic scanner such as ZAP. OWASP's selection criteria include language support, accuracy measured by false positive and false negative rates, and output in SARIF, the OASIS standard format for analysis results. Run SAST on pull requests as part of CI security checks.
Write rules for your own sinks, with tests
Default rules do not know your wrappers, such as an internal
db.raw()helper. Add project rules for them, and keep each rule beside a test file annotatedruleid:where it must fire andok:where it must not. Runsemgrep --test(or your tool's equivalent) in CI, so a broken rule cannot silently report nothing.Scan a test deployment as a logged-in user
Point the dynamic scanner at a test environment running the release candidate, with synthetic data and a dedicated account for each role. Configure authentication: ZAP's documentation warns that without it the scanner cannot reach any protected functionality. Exclude logout and destructive routes from the scan.
Use passive scans in CI and active scans in test
ZAP's baseline scan spiders for about a minute and only observes responses, so it is designed to run in CI, even against production. The full scan sends real attacks and can run for a long time: run it, or any active scan, only against a test environment you own and can reset.
Prove the scan reached the protected pages
Before trusting a clean result, find a 200 response from a protected page under the scanner's user in the scan log, and record the deployed artifact digest with the results. A scan whose session expired, or that only ever saw the login page, reports nothing because it tested nothing.
Confirm each finding before fixing it
Connect the static path from source to sink with a request against the deployed build that shows the effect, such as rows belonging to another owner. Turn that request into a failing test, fix the code, and close the finding only when the test passes on the new build and a normal request still works. Track it with an owner, as Fix a finding describes.
Suppress one finding at a time, with a reason
For a false positive, suppress that rule at that location, such as
nosemgrep: <rule-id>on the line or a dismissal in code scanning, and record why the sink is safe. Never disable a whole rule or exclude a directory to reach zero. Review suppressions on a schedule: each needs a rule ID, a location, a reason and an owner.
Done when
Confirmed findings have a reproducing test, and suppressed false positives have a recorded reason.
Mark it in the gap checkCommon mistakes
- Trusting a clean DAST report from a scan that never logged in. It tested the login page, and every protected route went unscanned.
- Running default rules untuned on every repository. Developers learn to dismiss the tool, and real findings are dismissed with the noise; OWASP SAMM's tuning level asks you to filter irrelevant and low-probability warnings.
- Excluding directories or disabling rules to reach zero findings. The count falls because the scope shrank, not because the code got safer.
- Scanning a stale environment. A clean scan of the build from last week says nothing about today's commit, so record the deployed digest with every result.
- Reading a clean SAST and DAST run as proof of security. Neither knows your authorization rules or business logic, so cover those with abuse-case tests (Abuse cases) and review.
- Pointing an active scan at production. It sends real attack payloads to live systems and real data.
SAST, DAST or IAST?
Each looks at a different representation of the same software, so each finds different bugs. A common order is SAST on pull requests first, then DAST against a test deployment.
| Question | SAST | DAST | IAST |
|---|---|---|---|
| What it examines | Source or compiled code, without running it | The running application, over HTTP from outside | The running application, from an agent inside it while tests run |
| Finds well | Data flows from input to dangerous sinks: injection, XSS, unsafe deserialization, weak crypto calls | Runtime behavior: missing headers and cookie flags, reflected XSS, some injection, TLS problems | Vulnerable data flows observed during tests, with the request and stack that triggered them |
| Misses | Authorization and logic flaws, configuration, framework behavior its rules do not model | Pages it cannot reach or log in to, logic flaws, the root cause in code | Code your tests never execute; unsupported runtimes |
| Where it runs | Editor and pull request; full scan nightly | Test or staging deployment | Test environment, as an agent in the app |
| Examples | Semgrep, CodeQL, Bandit, gosec | ZAP, Nuclei | Mostly commercial agents for specific runtimes |
Tools and guides
- Workflow: Fix a finding
- Workflow: Test an application
- Fix cards: tested fixes by stack
- Combine static and dynamic tests around a verified finding
Use analysis tools to find evidence, then retain an application regression that demonstrates the failure and the fix.
- 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.
- 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.
Standards
- NIST SSDF 1.1
- PW.7 Analyze Human-Readable Code to Identify Vulnerabilities and Verify Compliance with Security RequirementsPW.8 Test Executable Code to Identify Vulnerabilities and Verify Compliance with Security Requirements
- OWASP SAMM 2
- Security Testing
Sources
- OWASP: Source Code Analysis Tools
- OWASP: Vulnerability Scanning Tools
- ZAP: Authentication
- ZAP: Baseline scan
- ZAP: Full scan
- Semgrep: Test rules
- Semgrep: Ignore files, folders and code
- OASIS: Static Analysis Results Interchange Format (SARIF). Version 2.1.0 Plus Errata 01 (28 August 2023).
- OWASP SAMM: Security Testing, Scalable Baseline stream
- NIST SP 800-218: Secure Software Development Framework (SSDF) Version 1.1. February 2022.