Security Testing
Advanced 22 min read Security Testing

SAST, DAST & Dependency Scanning

SAST reads your source without running it, DAST probes the live application through HTTP, and dependency scanning checks the libraries in your build for known vulnerabilities. Learn when each runs, how they complement each other, and how to wire them into CI as a gating security test.

SASTDASTdependency scanningsemgrepOWASP ZAPCI gateNVDtaint analysisnpm audit
Introduction

What is this?

SAST (Static Application Security Testing) analyzes source code without executing it, DAST (Dynamic Application Security Testing) probes a running application through its HTTP interface, and dependency scanning matches resolved library versions against vulnerability databases like the NVD. Together they form the automation core of application security, each covering a blind spot the other tools cannot see.

Motivation

Why do you need it?

  • SAST finds flaws at the commit stage — seconds after they are written — when they are cheapest to fix.
  • DAST validates real behavior through the HTTP surface, catching runtime and configuration issues SAST misses.
  • Dependency scanning flags known CVEs in libraries that neither SAST nor DAST can reliably detect.
  • Automated gates in CI prevent vulnerable code from ever reaching an environment.
  • The tools produce the evidence trail that audits and compliance reviews ask for.
Think about it

Mental model

Imagine

A proofreader, a health inspector and a supplier audit

Think of

SAST, DAST and dependency scanning

The proofreader checks the manuscript (code) for mistakes; the inspector visits the kitchen while it runs (the live app); the audit reviews where your ingredients come from (libraries). Each catches what the other two cannot see.

Mechanics

How it works

  • SAST parses the source and applies rules — pattern matching and taint analysis — to flag risky patterns like SQL concatenation or unsafe deserialization.
  • DAST crawls and fuzzes a running instance, sending attack payloads and observing responses for errors, anomalies and confirmed signals.
  • Dependency scanning compares the resolved lockfile versions against vulnerability databases such as the NVD and OSV.
  • Findings are triaged by severity and context, deduplicated, and routed to the owning team.
  • CI gates fail the build on critical and high findings, while lower-risk findings flow into the backlog as tracked items.

Where each tool sits in a CI/CD pipeline.

Developer commits
SAST on the diff
Build + dependency scan
Deploy to staging
DAST against staging
Gate & report
Reference

Key commands

semgrep scan --config .semgrep/ --json -o sast-report.json

Run your custom SAST rules and write machine-readable results.

npm audit --json | jq -r '.metadata.vulnerabilities.severity'

Check known-vulnerability severities in the resolved dependency set.

{"info":0,"low":1,"moderate":0,"high":2,"critical":0}
grype dir:. -o table

Scan a directory (or with grype image: a container image) against a CVE database.

docker run -t ghcr.io/zaproxy/zaproxy zap-baseline.py -t http://localhost:8080 -r report.html

Run an OWASP ZAP baseline DAST scan against a local target and export an HTML report.

curl -sI http://localhost:8080/

Confirm the target is reachable before starting a DAST pass.

HTTP/1.1 200 OK
jq -r '.results[] | [.check_id, .extra.severity] | @tsv' sast-report.json | sort -u

Summarize SAST findings by rule and severity for the triage step.

Hands-on

Examples

A Semgrep rule that blocks SQL concatenation at commit time

A Semgrep rule that blocks SQL concatenation at commit time
# .semgrep/sqli.yaml — catch SQL built by concatenation or join
rules:
- id: node-sql-concat
languages: [javascript]
message: Possible SQL injection. Use parameterized queries.
severity: ERROR
metadata:
cwe: ["CWE-89"]
owasp: ["A03"]
patterns:
- pattern-either:
- pattern: $DB.query($X + $Y)
- pattern: $DB.query($X + $V)
- pattern: $DB.query($X.concat($V))
# Run it in CI:
# semgrep scan --config .semgrep/ --severity ERROR
# curl -sI https://staging.example.com/ | grep -i content-security-policy
# npm audit --json | jq -r '.metadata.vulnerabilities.severity'

The rule uses pattern-either to match three shapes of string-built queries, tags the finding with CWE-89 and OWASP A03 so it can be triaged and aggregated, and runs at ERROR severity so the CI gate fails. The comments show the companion checks: a DAST header assertion and a dependency audit command, because a single tool alone would leave the other two attack surfaces uncovered.

Real world

In production

  • A merge gate fails the build when SAST reports a critical or high finding on the changed lines.
  • Dependency scanning runs on every build and weekly against the full lockfile, alerting on newly published CVEs.
  • DAST baseline scans run against every staging deploy; authenticated full scans run on release candidates.
  • Findings route to the owning team with CWE/OWASP mappings so they are prioritized and fixed like defects.
Guidelines

Best practices

  • Start SAST in diff mode to reduce noise, then widen scope as rules are tuned.
  • Tune and baseline false positives instead of silently ignoring findings.
  • Scan the locked, resolved dependency set (lockfile), not just the manifest.
  • Give DAST valid test credentials so authenticated surfaces are actually exercised.
  • Treat the tools as a tripwire, not the whole program — pair them with code review and manual testing.
Watch out

Common mistakes

  • Treating a clean SAST run as proof that an application is secure.
  • Running DAST without credentials, so the authenticated half of the app is never scanned.
  • Auto-suppressing findings to keep the gate green.
  • Scanning manifests instead of lockfiles, missing the real resolved versions.
Root cause analysis

Common issues

Error
SAST flags an internal helper as unsafe
Root cause

A false positive from coarse taint analysis.

Fix

Add a source/sink annotation or a path-sensitivity rule, and document the decision in the rule's metadata.

Error
DAST baseline reports nothing on an app that is clearly vulnerable
Root cause

The scan ran unauthenticated or the payloads were blocked.

Fix

Run an authenticated scan and confirm the target's WAF permits the tool's user-agent and request rate.

Error
npm audit reports a high-severity advisory with no fix
Root cause

No patched version of the affected package exists yet.

Fix

Pin the affected component, apply a workaround such as a configuration flag, and track the advisory for the fix release.

When things break

Debugging tips

  • Reduce a SAST hit to a minimal reproducer to tell a false positive from a real flaw.
  • Cross-check a DAST alert against SAST and dependency results for the same code path.
  • When a tool misses a real bug, write a custom rule or a regression test and commit it with the fix.
Interviews

Interview checkpoint

Practice

Hands-on lab

Automated Security Gate: SAST + DAST + Dependencies
50 min · advanced
In progress
Objectives
  • Write and run a custom Semgrep rule that flags SQL concatenation
  • Run a dependency scan and interpret the severity summary
  • Run an OWASP ZAP baseline scan against a local target
  • Combine the three results into a single CI gate decision

Automated Security Gate: SAST + DAST + Dependencies

50 min · advanced

0/5 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

Which tool analyzes source code without executing the application?

2

A clean SAST report guarantees the application has no vulnerabilities.

3

A dependency with a known critical CVE has no patched version. Which response is most appropriate?

Quick reference

Cheat sheet

AppSec toolchain
semgrep scan --config .semgrep/SAST rules in CI
zap-baseline.py -t <url>DAST baseline scan
npm audit --jsonnpm dependency scan
grype dir:.Image/dir CVE scan
osv-scanner -r .OSV database scan
jq -r '.results[].extra.severity'Triage SAST output
Go deeper

Official documentation