Post

SAST - Static Application Security Testing, AST Modeling, Taint Analysis, and Semgrep Rules

Comprehensive technical walkthrough of TryHackMe SAST covering white-box manual review vs automated analysis, Abstract Syntax Tree modeling, dataflow taint tracking with Psalm, and IDE integration with Semgrep.

SAST - Static Application Security Testing, AST Modeling, Taint Analysis, and Semgrep Rules

Overview

SAST is the second room in Section 3 (Security in the Pipeline) of TryHackMe’s DevSecOps Learning Path. Static Application Security Testing (SAST) serves as the primary automated white-box testing methodology in modern engineering pipelines, inspecting uncompiled and unexecuted source code for architectural flaws and vulnerable coding patterns.

While manual code review provides high contextual nuance for complex business logic, it scales poorly across massive enterprise codebases. Automated SAST engines solve this scalability challenge by parsing code into Abstract Syntax Trees (ASTs) and evaluating data paths from user input sources to sensitive execution sinks.

This walkthrough investigates manual security code auditing, examines how SAST parsers construct abstract models, details five foundational static analysis techniques (semantic, dataflow, control flow, structural, and configuration), demonstrates taint analysis with Psalm, and audits an open-source application (ReciPHP) using Semgrep in VS Code.


1. Code Review Economics: Manual vs Automated

Catching security defects during development costs an order of magnitude less than fixing them in staging or emergency post-deployment patches.

graph TD
    subgraph ReviewModels["Code Review Methodologies"]
        M[Manual Code Review]
        A[Automated SAST Scanners]
    end

    M -->|Pros| M1[Contextual awareness: Business logic flaws]
    M -->|Pros| M2[High precision: Low false-positive rate]
    M -->|Cons| M3[Slow: Human fatigue on large codebases]
    M -->|Cons| M4[Expensive: High engineer-hour cost]

    A -->|Pros| A1[Instant speed: Milliseconds per commit]
    A -->|Pros| A2[Deterministic: Never misses configured rules]
    A -->|Pros| A3[Zero execution: Runs pre-compilation]
    A -->|Cons| A4[High false positives / false negatives]
    A -->|Cons| A5[Blind to complex multi-step workflow logic]

The Hybrid Review Strategy

Neither approach replaces the other:

  • Automated SAST: Implemented early as developer IDE linters and CI/CD pull request gates to eliminate low-hanging fruit (e.g., hardcoded credentials, raw SQL concatenation, insecure crypto keys).
  • Manual Code Review: Conducted periodically by AppSec engineers during architecture design changes or major milestone releases to evaluate authorization models, financial process logic, and contextual bypasses.

2. Anatomy of a Manual Code Review (Task 3)

To understand automated scanners, engineers must understand how human reviewers audit source code manually.

Step 1: Identifying Dangerous Sinks

Reviewers search for sensitive functions that interact with operating system commands, databases, or file systems:

Vulnerability ClassVulnerable Sinks (PHP / MySQL)
SQL Injection (SQLi)mysqli_query(), mysql_query(), mysqli_prepare(), query(), prepare()
Local File Inclusion (LFI)include(), include_once(), require(), require_once()
Command Injectionexec(), passthru(), shell_exec(), system(), popen()
Cross-Site Scripting (XSS)echo, print, printf(), vprintf()

Searching recursively for SQL sinks in /simple-webapp/html/:

1
2
grep -rn 'mysqli_query(' /home/ubuntu/Desktop/simple-webapp/html/
# Output: db.php:18: $result = mysqli_query($conn, $query);

Step 2: Contextual Tracing and Input Flow

In db.php, mysqli_query() is wrapped in db_query():

1
2
3
4
function db_query($conn, $query){
    $result = mysqli_query($conn, $query);
    return $result;
}

Because db_query() accepts $query without sanitization, we trace all calls to db_query() across the project:

1
2
3
4
grep -rn 'db_query(' /home/ubuntu/Desktop/simple-webapp/html/
# hidden-panel.php:7:  $result  = db_query($conn, $sql);
# hidden-panel.php:20: $result2 = db_query($conn, $sql2);
# hidden-panel.php:23: $result3 = db_query($conn, $sql3);

Evaluating Filter Bypass Mechanics

  1. Call 1 (hidden-panel.php:7): Unsanitized SQLi
    1
    2
    
    $sql = "SELECT id, firstname, lastname FROM MyGuests WHERE id=".$_GET['guest_id'];
    $result = db_query($conn, $sql);
    

    Direct concatenation of $_GET['guest_id'] allows complete SQL injection.

  2. Call 2 (hidden-panel.php:20): Secure Sanitization
    1
    2
    
    $sql2 = "SELECT id, logtext FROM logs WHERE id='".preg_replace('/[^a-z0-9A-Z"]/', "", $_GET['log_id']). "'";
    $result2 = db_query($conn, $sql2);
    

    preg_replace strips all characters except alphanumeric characters and double quotes. Because the query encloses the value in single quotes ('), double quotes cannot break string encapsulation. Not vulnerable.

  3. Call 3 (hidden-panel.php:23): Incomplete Filter Bypass
    1
    2
    
    $sql3 = "SELECT id, name FROM asciiart WHERE id=".preg_replace("/[^0-9]/", "", $_GET['art_id'], 1);
    $result3 = db_query($conn, $sql3);
    

    The fourth argument to preg_replace specifies the replacement limit, here set to 1. Only the first non-numeric character is removed. Subsequent characters pass untouched, permitting SQL injection payload delivery.

Bonus Audit: LFI via include()

Auditing file inclusion functions across the codebase:

  • Total include() statements: 9 instances.
  • Vulnerable line: view.php:22:
    1
    
    include('./gallery-files/'.$_GET['img']);
    

    Unsanitized concatenation of user-supplied $_GET['img'] allows path traversal (../../../../etc/passwd).


3. How SAST Engines Work: ASTs and Analysis Models

SAST engines translate source code into a standardized model before running vulnerability checks:

flowchart TD
    SRC[Raw Source Code] --> PARSE[Parser & Lexer]
    PARSE --> AST[Abstract Syntax Tree: AST]
    
    subgraph Techniques["Core SAST Analysis Techniques"]
        AST --> T1[Semantic Analysis: Pattern / Sink Search]
        AST --> T2[Dataflow Taint Tracking: Source to Sink]
        AST --> T3[Control Flow Analysis: Execution Order & Logic]
        AST --> T4[Structural Analysis: AST Node Validation]
        AST --> T5[Configuration Analysis: Config Security]
    end

    Techniques --> REPORT[Consolidated SAST Report]

The 5 Core Analysis Techniques

  1. Semantic Analysis: Evaluates local syntax patterns directly, similar to advanced regex grepping. Flags direct string concatenation inside dangerous functions like mysqli_query($db, "SELECT * FROM users WHERE user=" . $_GET['user']).
  2. Dataflow Analysis (Taint Tracking): Traces data propagation from user-controlled inputs (sources) through variable assignments and operations to dangerous functions (sinks). If tainted data reaches a sink without passing through an approved sanitization function, a vulnerability is raised.
  3. Control Flow Analysis: Inspects execution order and conditions to detect uninitialized variables, dead code segments, race conditions, and unhandled null exceptions.
  4. Structural Analysis: Validates compliance with programming best practices and structural patterns, such as identifying weak cryptographic parameters (e.g., RSA key length of 1024 bits) or empty exception handlers.
  5. Configuration Analysis: Scans server and runtime configuration manifests (php.ini, web.config, Dockerfiles, Kubernetes YAMLs) for hazardous settings, such as allow_url_include = On.

4. Practical Taint Analysis with Psalm (Task 5)

Psalm (PHP Static Analysis Linting Machine) analyzes PHP applications for type errors and security vulnerabilities.

Running Basic Structural Checks

Executing Psalm in /home/ubuntu/Desktop/simple-webapp/:

1
./vendor/bin/psalm --no-cache

Psalm flags structural logic flaws, such as assignment inside a comparison statement:

1
2
3
ERROR: TypeDoesNotContainType - html/hidden-panel.php:10:5
Operand of type 0 is always falsy
if ($result->num_rows = 0) {

Executing Taint Analysis

Enabling taint tracking traces untrusted inputs:

1
./vendor/bin/psalm --no-cache --taint-analysis

Psalm detects the LFI flaw in view.php:22 and traces the first SQLi in hidden-panel.php:6. However, because db_query() wraps mysqli_query(), Psalm only reports the flaw at the inner wrapper on line 18 of db.php, masking the secondary SQLi vulnerabilities.

Annotating Code to Specialize Taint Tracking

To help the SAST engine recognize custom functions as sinks and track each call site independently, we annotate db_query() in db.php:

1
2
3
4
5
6
7
8
/**
 * @psalm-taint-sink sql $query
 * @psalm-taint-specialize
 */
function db_query($conn, $query){
    $result = mysqli_query($conn, $query);
    return $result;
}
  • @psalm-taint-sink sql $query: Declares $query as a terminal sink for SQL injection payloads.
  • @psalm-taint-specialize: Directs Psalm to treat every invocation of db_query() as a separate taint flow depending on the caller inputs.

Re-running Psalm with these annotations reports 9 distinct security issues, successfully separating the distinct call sites.

SAST Result Discrepancies

QueryManual AuditPsalm SAST OutputResult Classification
$sqlVulnerableVulnerableTrue Positive (Accurate detection)
$sql2Not VulnerableVulnerableFalse Positive (Scanner missed single-quote context)
$sql3VulnerableNot VulnerableFalse Negative (Scanner failed to model regex limit)

5. SAST in the Development Lifecycle: VS Code & Semgrep (Task 6)

Integrating SAST into developer workflows ensures code is audited before it leaves the developer workstation.

flowchart LR
    subgraph IDE["Developer IDE: VS Code"]
        CODE[Developer writes code] --> LINT[Inline Real-time Linters]
        LINT --> FAST[Structural & Type Errors: Psalm / Semgrep]
    end

    subgraph CI["CI/CD Pipeline"]
        PR[Pull / Merge Request] --> GATE[Pipeline Security Gate]
        GATE --> DEEP[Comprehensive Taint & Dataflow Scans]
    end

Auditing ReciPHP with Semgrep

In Task 6, we open the ReciPHP workspace in VS Code. Semgrep runs in the background against predefined rules:

  • Total Problems Detected across Project: 27 issues.
  • Problems in showrecipe.inc.php: 8 issues.
  • Rule Identifiers in showrecipe.inc.php:
    1. tainted-sql-string: Flags user parameters passed directly to database queries (SQL Injection).
    2. echoed-request: Flags raw $_GET or $_POST variables printed directly to the HTML response without sanitization.
  • Vulnerability for echoed-request: Cross-site Scripting (XSS).

6. Question, Answer, and Flag Summary

Task #Task TitleQuestion / ChallengeAnswer / Flag
Task 1IntroductionClick and continue learning!No answer needed
Task 2Code ReviewAre automated code reviews a substitute for manual reviewing? (yea/nay)nay
Task 2Code ReviewWhat type of code review will run faster? (Manual/Automated)Automated
Task 2Code ReviewWhat type of code review will be more thorough? (Manual/Automated)Manual
Task 3Manual Code ReviewWhich of the mentioned functions is used in the project?include()
Task 3Manual Code ReviewHow many instances of the function found in question 2 exist in your project’s code?9
Task 3Manual Code ReviewWhat file contains the vulnerable instance?view.php
Task 3Manual Code ReviewWhat line in the file found on the previous question is vulnerable to LFI?22
Task 4Automated Code ReviewDoes SAST require a running instance of the application for analysis? (yea/nay)nay
Task 4Automated Code ReviewWhat kind of analysis would likely flag dead code segments?structural analysis
Task 4Automated Code ReviewWhat kind of analysis would likely detect flaws in configuration files?configuration analysis
Task 4Automated Code ReviewWhat kind of analysis is similar to grepping the code in search of flaws?semantic analysis
Task 5Rechecking our Application with SAST ToolsWhat type of error occurs when the tool reports a vulnerability not present in code?False positive
Task 5Rechecking our Application with SAST ToolsHow many errors are reported after annotating code and re-running Psalm?9
Task 6SAST in the Development CycleHow many problems in total are detected by Semgrep in this project?27
Task 6SAST in the Development CycleHow many problems are detected in the showrecipe.inc.php file?8
Task 6SAST in the Development CycleWhat other problem identifier is reported by Semgrep in this file?echoed-request
Task 6SAST in the Development CycleWhat type of vulnerability is associated with the problem identifier on the previous question?Cross-site Scripting
Task 7ConclusionClick and continue learning!No answer needed

You can find me online at:

My signature image

This post is licensed under CC BY 4.0 by the author.