Skip to main content

SAST: The Complete Guide to Static Application Security Testing

RA
Rafsan Alhad Founder & Editorial Director
13 min read

What Is SAST? (The 30-Second Answer)

SAST stands for Static Application Security Testing. It is a method of finding security vulnerabilities by analyzing your application’s source code without running it — the tool reads your code the way a very thorough (and very fast) security reviewer would, looking for patterns that are known to be dangerous.

The word “static” is the key: unlike testing that requires a running app, SAST works on code at rest. That means it can run the moment you write code — in your editor, in a pull request, or in your CI pipeline — long before anything reaches production.

If you remember one sentence: SAST finds security bugs in your source code before your application ever runs.

What Does SAST Stand For?

  • Static — analyzes code without executing it
  • Application — targets your application (not the network, not the infrastructure)
  • Security — looks specifically for security weaknesses, not just bugs or style issues
  • Testing — it’s an automated testing technique, not a manual review

You’ll also see it called “static analysis” or “white-box testing” (because the tool can see inside the code, as opposed to black-box testing that only sees behavior from the outside).

How SAST Actually Works: The 4 Stages

Most guides wave their hands at this point. Here’s what actually happens when you run a SAST scan:

Stage 1: Parse — turning code into a model

The tool first parses your source code into an Abstract Syntax Tree (AST) — a structured representation of what your code means, not just what it looks like as text. This is why SAST is smarter than grep: it understands that query = "SELECT * FROM users WHERE id = " + user_id is string concatenation feeding a database call, regardless of variable names or formatting.

Good SAST tools parse per-language (Python, JavaScript, Java, Go, and so on), because each language has its own grammar and its own dangerous patterns.

Stage 2: Build the model — control flow and data flow

From the AST, the tool builds two maps of your program:

  • Control-flow graph: which statements can execute after which other statements (branches, loops, function calls).
  • Data-flow graph: where each piece of data comes from and where it goes.

The data-flow map is where the security magic lives. The tool marks sources (places untrusted data enters: HTTP request parameters, file reads, environment input) and sinks (dangerous operations: SQL queries, HTML rendering, shell commands, file writes). Then it asks: is there a path from a source to a sink without proper sanitization in between?

Stage 3: Taint analysis — following dirty data

This source-to-sink tracing is called taint analysis. Data from a source is “tainted”; if tainted data reaches a sink without passing through a recognized sanitizer (parameterized queries, output encoding, allowlist validation), the tool flags it.

This is also where false positives come from: the tool may not recognize your custom sanitization function, or it may trace a path that can’t actually happen at runtime. Modern tools reduce this with better framework awareness, but no SAST tool has a zero false-positive rate — anyone who tells you otherwise is selling something.

Stage 4: Report and triage

Findings come back with file, line number, the tainted data-flow path (source → sink), a severity rating, and ideally remediation guidance. Your job is then triage: confirm true positives, suppress false positives (and feed that back into the tool’s configuration), and assign fixes with sensible SLAs by severity.

A concrete trace: what taint analysis actually sees

To make Stage 3 less abstract, here’s what a taint engine reconstructs from a small Flask endpoint:

from flask import request
import sqlite3

@app.route("/search")
def search():
    q = request.args.get("q")          # SOURCE: tainted
    query = "SELECT * FROM docs WHERE title LIKE '%" + q + "%'"
    cursor.execute(query)               # SINK: tainted data reaches SQL
    return render_results(cursor.fetchall())

The tool’s internal trace looks like this:

  1. request.args.get("q") → marked tainted (untrusted input source)
  2. q concatenated into query → taint propagates through string operations
  3. query passed to cursor.execute() → sink reached with tainted data, no sanitizer on the path → flag: SQL injection

If step 2 had instead been cursor.execute("... LIKE %s", (q,)), the engine would see the value bound as a parameter (not interpolated into SQL text), the taint would be considered neutralized, and no finding would be raised. Understanding this trace is the key to triaging findings: when a tool flags something, walk the source-to-sink path it shows you and ask whether each step is real.

What SAST Can Find (With Real Examples)

SAST excels at pattern-based code flaws — vulnerabilities that have a recognizable shape in source code. Here are three classics, shown vulnerable and fixed:

Example 1: SQL injection (Python)

Vulnerable — user input concatenated directly into a query:

import sqlite3

def get_user(user_id):
    conn = sqlite3.connect("app.db")
    cursor = conn.cursor()
    # DANGEROUS: user_id flows straight into the SQL string
    cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
    return cursor.fetchone()

A SAST tool traces user_id (source: function argument, potentially attacker-controlled) into cursor.execute() (sink) with no sanitization, and flags it.

Fixed — parameterized query:

def get_user(user_id):
    conn = sqlite3.connect("app.db")
    cursor = conn.cursor()
    # SAFE: the database driver handles the value, never the SQL text
    cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
    return cursor.fetchone()

Example 2: Cross-site scripting / XSS (JavaScript)

Vulnerable — untrusted data rendered as HTML:

function showGreeting() {
    const name = new URLSearchParams(window.location.search).get("name");
    // DANGEROUS: attacker-controlled string rendered as HTML
    document.getElementById("welcome").innerHTML = "Hello, " + name;
}

Fixed — treat it as text, not markup:

function showGreeting() {
    const name = new URLSearchParams(window.location.search).get("name");
    // SAFE: textContent never interprets the string as HTML
    document.getElementById("welcome").textContent = "Hello, " + name;
}

Example 3: Hardcoded secret (any language)

Vulnerable:

STRIPE_API_KEY = "sk_live_51H7x9a2b8c4d6e0f..."  # DANGEROUS: secret in source code

Fixed:

import os
STRIPE_API_KEY = os.environ["STRIPE_API_KEY"]  # SAFE: secret lives outside the codebase

SAST reliably catches these shapes: injection flaws, XSS, hardcoded secrets, weak cryptography (MD5, DES), insecure deserialization patterns, path traversal, and dangerous function usage. For a deeper catalog organized by risk category, see the OWASP Top 10 — most of its items have a SAST-detectable component.

What SAST Can NOT Find (Honest Blind Spots)

This is the section vendor guides skip. SAST is powerful, but it has real limits, and planning around them is what separates teams that benefit from SAST from teams that drown in it:

  1. Business-logic flaws. If your discount code logic lets users stack 90%-off coupons, no scanner will flag it — the code does exactly what it was written to do. Only humans (or very targeted tests) catch logic bugs.
  2. Broken authentication/authorization design. SAST can spot a missing auth check on an endpoint pattern, but it can’t tell you your role model is wrong. Access-control logic needs manual secure code review.
  3. Runtime misconfigurations. Open S3 buckets, overly permissive CORS, missing security headers — these live in deployment config and running behavior, not in source code. That’s DAST territory.
  4. Vulnerable dependencies. If your code is clean but the library you import has a known CVE, SAST won’t see it — it analyzes your code. You need SCA (Software Composition Analysis) for that.
  5. Anything requiring runtime context. Race conditions, timing attacks, and environment-specific issues are largely invisible to static analysis.

The takeaway: SAST is one instrument, not the orchestra. A serious AppSec program pairs it with SCA, DAST, and human review. Our SAST vs DAST and SAST vs SCA comparisons go deep on how these fit together.

SAST vs DAST vs SCA vs IAST: The 60-Second Map

SAST DAST SCA IAST
Analyzes Your source code A running app Your dependencies Running app + code (instrumented)
Needs Source code A deployed, runnable app Manifests/lockfiles Agent inside the runtime
Best at Injection, XSS, secrets, crypto misuse Auth flaws, runtime config, server errors Known CVEs in libraries Confirming exploitability with code context
Blind to Runtime behavior, logic flaws Source-level issues in dead code paths Your own code’s bugs Requires staging-like environment
When As you code / PR / CI Staging / pre-prod CI / continuously Staging with realistic traffic

Rule of thumb: SAST first (cheapest, earliest), add SCA immediately after (your dependencies are probably your biggest CVE surface), add DAST before release, consider IAST when you have the maturity to run it. Each technique covers the others’ blind spots — none replaces the rest.

How to Choose a SAST Tool

Not all SAST tools are equal. Evaluate on these five axes:

  1. Language and framework coverage. The tool must understand your stack — including the frameworks, not just the language. A Python scanner that doesn’t know Django or Flask idioms will miss framework-specific sinks.
  2. Accuracy (precision and recall). Ask about false-positive rates on real codebases, not demos. A tool that cries wolf on every PR gets ignored — or worse, disabled.
  3. Developer workflow fit. IDE plugins, PR comments, incremental scans on changed files. If the tool only does slow full-codebase nightly scans, developers will route around it.
  4. Rule customization. You will need to write or tune rules for your frameworks and to suppress your project’s known false positives. A black box you can’t tune becomes shelfware.
  5. Cost and operations. Enterprise tools (Checkmarx, Fortify, Coverity) are powerful and expensive. Open-source tools (Semgrep at the top of the list) cover a remarkable amount of ground for free — we’ve compared 12 open-source SAST tools here, including a zero-install option.

For language-specific guidance, see our Java security scanning guide.

SAST by Language: Quick Pointers

SAST is not one-size-fits-all — each ecosystem has its own idioms, frameworks, and mature scanners. A short map:

  • Python: Bandit is the go-to lightweight scanner (flags exec, weak crypto, hardcoded passwords, risky subprocess usage). Semgrep’s Python rules go deeper with taint tracking across Django/Flask.
  • JavaScript/TypeScript: eslint with security plugins (e.g., eslint-plugin-security) catches the obvious; Semgrep adds real dataflow for Express/Fastify apps.
  • Java: SpotBugs with the FindSecBugs plugin is the classic free option; Semgrep and SonarQube cover Spring-specific patterns. See our Java security scanning guide for setup details.
  • Go: gosec inspects the AST for weak randomness, unsafe blocks, and command injection — fast enough to run on every commit.
  • PHP: Psalm and PHPStan with security-focused plugins; WordPress-heavy codebases benefit from rules tuned to WP APIs.

Whichever stack you run, the selection criteria in the previous section still apply: framework awareness matters more than raw rule count.

Putting SAST Into CI/CD (Shift Left in Practice)

SAST delivers its value when it runs automatically and early. The practical pattern:

  1. IDE / pre-commit: fastest feedback loop. Catch secrets and obvious injection before code is even committed.
  2. Pull request: scan changed files, comment findings inline on the PR. Block merging on critical-severity findings; warn on the rest.
  3. CI pipeline: full scan on merge to main. Gate releases on severity thresholds.
  4. Scheduled: weekly full-baseline scan to catch what incremental scans missed and to pick up new rules.

The cultural rule that makes or breaks this: never block developers on low-severity noise. Gate on critical/high, warn on the rest, and invest the saved goodwill in tuning rules. Our shift-left security playbook walks through the full implementation, including a working GitHub Actions pipeline.

SAST and Manual Code Review: Better Together

SAST automates the pattern half of code review — the injection shapes, the secret scans, the dangerous-function checks that humans are slow and inconsistent at. It does not replace the judgment half: business logic, authorization design, and “is this the right fix?” still need experienced reviewers.

The winning division of labor: let SAST clear the mechanical findings so human reviewers can spend their time on logic flaws and design. Our secure code review guide covers the methodology, checklists, and PR workflow for the human side.

Reading a SAST Report: Triage in Practice

Your first full scan will return more findings than you expect. Don’t panic — work the list like this:

  1. Sort by severity, then by confidence. Fix critical/high-confidence findings first; they’re the likeliest true positives.
  2. Walk one trace end-to-end. Pick a finding, follow its source-to-sink path in your code, and decide: real or false positive? This calibrates your trust in the tool.
  3. Suppress with reason, not with silence. When you mark a false positive, record why (custom sanitizer, dead code, defense in depth elsewhere) — future you will thank present you.
  4. Turn patterns into rules. If the same finding class appears ten times, that’s not ten bugs to fix individually — it’s a coding pattern to address once (training, a shared helper, or a custom rule).
  5. Re-scan after fixes. Confirm the finding is gone and nothing new appeared. SAST is a loop, not a one-time event.

Teams that triage this way typically see finding counts drop sharply after the first few cycles — not because the tool got dumber, but because the codebase got cleaner and the configuration got smarter.

SAST Adoption Checklist

Use this as your rollout plan:

  • [ ] Pick a tool covering your languages/frameworks (start with a free option to prove value)
  • [ ] Run a baseline scan; triage and record the initial true-positive set
  • [ ] Tune out the top false-positive patterns before rolling out widely
  • [ ] Integrate into PRs with inline comments (not just a PDF report nobody reads)
  • [ ] Set severity gates: block on critical, warn on the rest
  • [ ] Define SLAs: e.g., critical fixed in days, high in weeks
  • [ ] Add SCA alongside SAST — dependencies are a separate problem (why you need both)
  • [ ] Track metrics: findings per PR, mean time to remediate, false-positive rate trend
  • [ ] Feed recurring findings back into developer training and coding standards

Try SAST Right Now (Free)

Reading about SAST is useful; running it on your code is better. AutoSAST is a free SAST scanner: upload a ZIP of your project or point it at a GitHub repository, and it analyzes your code with Semgrep’s AST-based rules (covering OWASP Top 10 patterns) plus AI-generated remediation guidance for what it finds. No installation, no signup for the free tier.

A fair note on limits: like any SAST tool, it finds code-pattern vulnerabilities — it won’t audit your business logic or your dependencies (that’s SCA’s job). Use it as the automated half of your review process, alongside the human practices in this guide’s cluster.

Frequently Asked Questions

What does SAST stand for?

SAST stands for Static Application Security Testing — automated analysis of source code (without running it) to find security vulnerabilities.

What is SAST in simple terms?

SAST is like a spell-checker, but for security bugs: it reads your source code and highlights patterns that are known to be dangerous (like building SQL queries from user input), before your app ever runs.

What is the difference between SAST and DAST?

SAST analyzes source code statically (before the app runs); DAST tests a running application from the outside (simulating attacks). SAST finds code-level flaws early; DAST finds runtime and configuration issues. See our full SAST vs DAST comparison.

Can SAST find all vulnerabilities?

No. SAST is strong on code-pattern flaws (injection, XSS, hardcoded secrets, crypto misuse) but blind to business-logic flaws, broken access-control design, runtime misconfigurations, and vulnerable third-party libraries. Pair it with SCA, DAST, and manual review.

Is SAST the same as linting?

Related, not identical. Linters check style and common bugs; SAST uses deeper analysis (data-flow/taint tracking across functions and files) focused specifically on security. Some modern linters include security rules, which is SAST-lite — useful, but not a substitute for a real SAST pass.

When should you run SAST?

As early and as often as practical: in the IDE while coding, on every pull request, in CI on merge, plus a scheduled full scan. Findings get cheaper to fix the earlier they’re caught.

Is SAST enough on its own for application security?

No. A complete program combines SAST (your code), SCA (your dependencies), DAST (runtime behavior), and human secure code review (logic and design). Each covers the others’ blind spots.

Are there free SAST tools?

Yes. Semgrep is the standout open-source option, and there are solid choices per language (Bandit for Python, gosec for Go, Brakeman for Rails, SpotBugs with FindSecBugs for Java). We’ve ranked 12 free and open-source SAST tools, and AutoSAST offers Semgrep-based scanning with AI remediation through your browser, no install needed.

Interactive Utilities

Related Interactive Calculators & Tools

Browse 2,700+ Tools →
Security Free & Client-Side

AutoSAST — Free SAST & Code Security Scanner | NR Tech Studio

Free online SAST code security scanner. Audit ZIP archives & GitHub repos for OWASP Top 10:2021 flaws using Semgrep AST and instant AI fix patches.

Launch Tool →
Developer Free & Client-Side

Web API Security Audit & Header Generator

Interactive web API security audit checklist, security header generator, and API endpoint hardening toolkit.

Launch Tool →
Security Free & Client-Side

CSP Generator — Free Content Security Policy Header Generator (Online)

Generate a Content Security Policy (CSP) header online: visual directive builder, nonce & SHA-256/384/512 hash generator, CSP validator, and copy-paste presets for WordPress, nginx, Apache, IIS, Express & Laravel. Free, no signup, runs 100% in your browser.

Launch Tool →