Parameter

Static application security testing (SAST)

Also known as

  • Static code analysis for security
  • Source code security analysis

Static application security testing (SAST) is automated analysis of source code, bytecode or binaries, without running the application, that traces untrusted input to dangerous operations such as SQL queries, shell commands and HTML output, and reports the file and line where an injection or similar flaw could occur.

Last reviewed

How does SAST work?

A SAST tool parses code into a model it can query, usually an abstract syntax tree plus a data flow graph, then looks for paths where attacker-controlled data reaches a dangerous operation without passing through a check. No server, database or running build is required, which is why SAST can run on every pull request.

Most security-relevant SAST findings come from taint analysis, which has three parts:

  • Sources: where untrusted data enters. Request parameters, headers, cookies, request bodies, file uploads, message queue payloads.
  • Sinks: operations that are dangerous with untrusted data. cursor.execute(), subprocess.run(..., shell=True), eval(), template rendering without escaping, outbound HTTP clients.
  • Sanitizers: functions that make data safe for a specific sink. Bound query parameters for SQL, shlex.quote() for shell arguments, HTML escaping for templates.

The tool reports a finding when it can trace a path from a source to a sink that does not cross a sanitizer. Simpler rules skip data flow entirely and match syntax: md5( used on a password field, verify=False on a TLS client, a hardcoded key.

How far the tool can follow data matters. CodeQL's documentation distinguishes local data flow, within a single function, from global data flow, which crosses functions and object properties and costs more to compute. Semgrep's open-source engine tracks taint within a function by default; cross-function and cross-file tracking are in its commercial tier. A tool that only follows data inside one function misses a source in the controller and a sink in a helper module.

What does a SAST finding look like?

Here is a tiny Flask handler with a planted flaw:

# app/reports.py
from flask import request
from app.db import get_cursor

@app.get("/reports")
def list_reports():
    sort = request.args.get("sort", "created_at")      # source
    query = "SELECT id, name FROM reports ORDER BY " + sort
    cur = get_cursor()
    cur.execute(query)                                   # sink
    return {"reports": cur.fetchall()}

A taint rule that catches it, written in Semgrep's syntax as an example of the approach:

rules:
  - id: flask-sqli-from-request
    mode: taint
    languages: [python]
    severity: ERROR
    message: Request data flows into a SQL query built with string concatenation
    pattern-sources:
      - pattern: flask.request.args.get(...)
    pattern-sanitizers:
      - pattern: int(...)
    pattern-sinks:
      - pattern: $CUR.execute($QUERY, ...)
        focus-metavariable: $QUERY

The tool reports something like:

app/reports.py:10  flask-sqli-from-request
  sort = request.args.get("sort", "created_at")    line 7 (source)
  query = "SELECT ... ORDER BY " + sort            line 8 (propagates)
  cur.execute(query)                               line 10 (sink)

The fix here is an allowlist, because ORDER BY columns cannot be bound as query parameters: map sort to one of {"created_at", "name"} and reject anything else. A SAST tool will not know that an allowlist lookup is a sanitizer unless the rule says so, which leads to the next problem. The SQL injection page covers the injection side in depth.

What is SAST good at?

SAST is good at breadth and at pointing to the exact line. The OWASP Source Code Analysis Tools page lists its strengths: it scales across large codebases, runs repeatedly in CI, and reports file, line and code snippet. It is strongest on bugs with a clear source-to-sink shape:

  • SQL, command, LDAP and template injection
  • Cross-site scripting through unescaped output
  • Path traversal from input into file operations
  • Server-side request forgery from input into an HTTP client
  • Weak crypto, insecure defaults and hardcoded credentials

Why does SAST produce false positives?

A false positive is a reported path that cannot be exploited, and SAST produces them because it reasons about code without knowing runtime facts. OWASP names "high numbers of false positives" as a known weakness. The usual causes:

  1. Unknown sanitizers. A custom validate_sort() function that the rule does not recognize.
  2. Unreachable paths. A source that only admins can reach, or a sink behind a feature flag that is always off.
  3. Type facts the tool misses. A parameter the framework has already coerced to an integer.
  4. Over-approximation. When the tool cannot resolve which function a dynamic call hits, it assumes the worst.

The opposite failure, false negatives, is quieter and worse. OWASP lists authentication problems, access control issues and insecure use of cryptography as areas SAST struggles with, and configuration issues are invisible to it because "they are not represented in the code." A missing requireOwner() check is not a source-to-sink path, so an authorization bug like broken object level authorization produces no finding at all.

To keep SAST useful: tune rules to your frameworks, register your own sanitizers, gate merges only on high-confidence rules, and baseline existing findings so developers only see what their change introduced. Tool accuracy varies widely. The OWASP Benchmark project is a Java and Python test suite of deliberately exploitable and deliberately safe cases that teams use to measure a tool's true and false positive rates before buying or tuning it.

SAST vs DAST vs SCA vs IAST

These four categories look at different things, so they find different bugs.

SASTDASTSCAIAST
Looks atYour source or bytecodeThe running app over HTTPThird-party dependenciesThe running app from inside, via an agent
Needs a deployed appNoYesNoYes, plus test traffic
FindsInjection, unsafe APIs, hardcoded secretsRuntime and config flaws, injection confirmed by responseKnown CVEs in packages and versionsInjection with the exact code path observed
MissesAuthorization, logic, configCode paths it cannot reach, logic, authorizationBugs in your own codeCode not exercised by tests
Points to a line of codeYesNoThe manifest entryYes

Dynamic application security testing confirms what is exploitable from the outside. Software composition analysis answers a different question, whether a package version has a published vulnerability, and reachability analysis narrows that to vulnerabilities your code actually calls. IAST instruments the application runtime and watches tainted data during functional tests, so its coverage is only as good as the test suite. None of the four finds a flaw that requires understanding what the application is supposed to allow.

Written by Parameter · Last reviewed

[ related terms ]

Related terms.

Dynamic application security testing (DAST)

Dynamic application security testing (DAST) is automated testing of a running web application or API from the outside: a scanner crawls the app, sends modified requests to each input, and flags responses that show injection, cross-site scripting, misconfiguration or exposed data, without access to source code.

Secure code review

Secure code review is the examination of source code, usually a pull request diff, specifically to find security flaws such as missing authorization checks, injection, unsafe deserialization and leaked secrets, by a person, a static analysis tool, an AI reviewer, or a combination, before the change reaches production.

Shift-left security

Shift-left security is the practice of moving security checks earlier in software development, into design, the developer's editor and the pull request, so threat models, static analysis, dependency checks and secrets scanning catch flaws before code merges, while a fix is still a small edit to the author's own change.

SQL injection (SQLi)

SQL injection (SQLi) is a vulnerability where user input is concatenated into a database query, letting an attacker change the query's logic to read rows they should not see, bypass login checks, modify or delete data, and sometimes run commands on the database server.

Reachability analysis

Reachability analysis is a technique for triaging dependency vulnerabilities that checks whether your application can actually execute the vulnerable function in a library, by tracing a call path from your own code to it, so teams fix the findings that are reachable and deprioritize ones where the flawed code is present but never runs.