Skip to main content

02 - SAST - Static Code Analysis and Vulnerability Detection

What is Static Code Analysis? SAST (Static Application Security Testing) is an analysis technique that examines source code without execution...

What do you think about this article?

At a Glance

What is Static Code Analysis? SAST (Static Application Security Testing) is an analysis technique that examines source code without execution...

SAST: What is Static Code Analysis

SAST (Static Application Security Testing) is an analysis technique that examines source code without executing it, looking for patterns that indicate security vulnerabilities. Unlike dynamic testing that requires a running application, SAST operates directly on the code, allowing problems to be identified in the earliest stages of development.

SAST analyzes code looking for vulnerabilities such as SQL injection, cross-site scripting (XSS), buffer overflow, hardcoded credentials, insecure deserialization, and many others. SAST tools build a model of the code (AST - Abstract Syntax Tree) and apply security rules to identify problematic patterns.

In this article, we will explore the main SAST tools, their integration into CI/CD pipelines, and strategies for managing one of the most common problems: false positives.

What You'll Learn

  • How SAST works and the difference with DAST and IAST
  • Configuring SonarQube, Semgrep, and CodeQL in the CI/CD pipeline
  • Writing custom rules for Semgrep
  • Managing false positives and prioritizing findings
  • Integrating SAST in the IDE for immediate feedback
  • Quality Gates and blocking thresholds for deployment

SAST vs DAST vs IAST: The Differences

To choose the right tools, it's essential to understand the differences between the three main security testing approaches:

Security Testing Approaches Comparison

Feature SAST DAST IAST
Analysis Source code (white-box) Running application (black-box) Runtime with agent (grey-box)
When During development, in CI In staging/pre-production During functional tests
Coverage All code, even unreachable Only HTTP-reachable parts Code executed during tests
False Positives Medium-high Low Very low
Speed Fast (minutes) Slow (hours) Depends on tests

The optimal approach is to use all three complementarily: SAST for quick feedback during development, DAST to validate runtime security, and IAST for precise correlation during testing.

SonarQube: Complete Code Quality Analysis

SonarQube is the most widely used SAST platform, used by over 400,000 organizations. Beyond security, it analyzes code quality, code smells, duplications, and test coverage. The Community edition is open source and covers 30+ programming languages.

Setup with Docker Compose

The quickest way to start SonarQube locally or in a staging environment is through Docker Compose:


# docker-compose.sonarqube.yml
version: "3.8"
services:
  sonarqube:
    image: sonarqube:lts-community
    container_name: sonarqube
    ports:
      - "9000:9000"
    environment:
      - SONAR_JDBC_URL=jdbc:postgresql://db:5432/sonarqube
      - SONAR_JDBC_USERNAME=sonar
      - SONAR_JDBC_PASSWORD=sonar_password
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_logs:/opt/sonarqube/logs
      - sonarqube_extensions:/opt/sonarqube/extensions
    depends_on:
      - db

  db:
    image: postgres:15
    container_name: sonarqube-db
    environment:
      - POSTGRES_USER=sonar
      - POSTGRES_PASSWORD=sonar_password
      - POSTGRES_DB=sonarqube
    volumes:
      - postgresql_data:/var/lib/postgresql/data

volumes:
  sonarqube_data:
  sonarqube_logs:
  sonarqube_extensions:
  postgresql_data:
      

Integration in GitHub Actions

Integrating SonarQube in the CI/CD pipeline with GitHub Actions allows automatic analysis on every push or pull request:


# .github/workflows/sonarqube.yml
name: SonarQube Analysis
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  sonarqube:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: SonarQube Scan
        uses: SonarSource/sonarqube-scan-action@v3
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

      - name: SonarQube Quality Gate
        uses: SonarSource/sonarqube-quality-gate-action@v1
        timeout-minutes: 5
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
      

Semgrep: Lightweight and Customizable Static Analysis

Semgrep is an open source SAST tool created by Return Security (now Semgrep Inc.) that stands out for its simplicity in creating custom rules. Unlike SonarQube which requires a server, Semgrep can be run as a simple command-line tool.

Semgrep's power lies in its pattern matching language that allows writing security rules intuitively, almost like writing the code you want to find.

Writing Custom Semgrep Rules

Here is an example of a Semgrep rule to detect SQL injection in Python applications:


# .semgrep/sql-injection.yml
rules:
  - id: python-sql-injection
    patterns:
      - pattern: |
          cursor.execute($QUERY)
      - pattern-not: |
          cursor.execute($QUERY, $PARAMS)
      - metavariable-pattern:
          metavariable: $QUERY
          patterns:
            - pattern: |
                f"..."
    message: >
      Possible SQL injection: the SQL query uses f-string
      instead of prepared parameters. Use cursor.execute(query, params)
      with %s placeholders to prevent injection.
    severity: ERROR
    languages: [python]
    metadata:
      cwe:
        - "CWE-89: Improper Neutralization of Special Elements"
      owasp:
        - "A03:2021 - Injection"
      confidence: HIGH
      

CI/CD Integration

Semgrep integrates easily into any CI/CD pipeline. Here is the configuration for GitHub Actions:


# .github/workflows/semgrep.yml
name: Semgrep Security Scan
on:
  push:
    branches: [main]
  pull_request:

jobs:
  semgrep:
    runs-on: ubuntu-latest
    container:
      image: semgrep/semgrep
    steps:
      - uses: actions/checkout@v4

      - name: Run Semgrep
        run: |
          semgrep scan \
            --config auto \
            --config .semgrep/ \
            --sarif --output semgrep-results.sarif \
            --error \
            --severity ERROR

      - name: Upload SARIF
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: semgrep-results.sarif
      

CodeQL: GitHub's Semantic Analysis

CodeQL is the analysis engine developed by GitHub that treats code as queryable data. Unlike Semgrep which uses pattern matching, CodeQL builds a relational database of the code and allows writing complex queries to find vulnerabilities.

CodeQL excels at taint tracking analysis: the ability to follow data flow from user input (source) to sensitive operations (sink), verifying whether data is sanitized along the path.

CodeQL: Key Advantages

  • Free for public repositories on GitHub
  • Deep semantic analysis with taint tracking
  • Extensive rule community maintained by GitHub Security Lab
  • Native integration with GitHub Advanced Security
  • Support for custom queries in the QL language

Managing False Positives

One of the major problems with SAST tools is the false positive rate: alerts that flag vulnerabilities that don't actually exist. A false positive rate that's too high erodes team trust in the tools and leads to alert fatigue, where developers start ignoring all alerts.

Strategies to Reduce False Positives

  • Rule tuning: disable rules not relevant to the application context
  • Targeted exclusions: exclude generated files, tests, vendor code
  • Baseline: establish a baseline and focus only on new findings
  • Prioritization: focus first on CRITICAL and HIGH severity
  • Suppression comments: mark false positives with documented comments

# Example of suppression in Python code
import hashlib

# This MD5 usage is for checksum, not security
# nosemgrep: python-weak-hashing
file_hash = hashlib.md5(file_content).hexdigest()  # noqa: S303

# Example of SonarQube suppression
password = get_env("DB_PASSWORD")  # NOSONAR - password from env var, not hardcoded
      

Quality Gates: When to Block Deployment

A Quality Gate defines the minimum quality and security thresholds that code must meet to be released. It's the mechanism that transforms SAST from an informational tool to a blocking gate in the pipeline.

Recommended Quality Gate

Metric Threshold Action
CRITICAL Vulnerabilities 0 Block deploy
HIGH Vulnerabilities 0 (new code) Block deploy
MEDIUM Vulnerabilities Max 5 (new code) Warning, review required
Security Hotspots 100% reviewed Block if not reviewed
Code Coverage Min 80% (new code) Warning

SAST in the IDE: Immediate Feedback

The most effective shift-left is bringing SAST analysis directly into the developer's IDE. This allows identifying and fixing vulnerabilities while writing code, even before committing.

  • SonarLint: plugin for IntelliJ, VS Code, Eclipse. Connected to SonarQube to synchronize rules
  • Semgrep VS Code Extension: highlights findings directly in the editor
  • GitHub Copilot: suggests contextual security fixes

IDE integration reduces the feedback loop from minutes (CI/CD) to seconds, drastically increasing the likelihood that the developer fixes the issue immediately.

SAST Best Practices

After implementing SAST in several enterprise projects, here are the best practices we recommend:

  1. Start in non-blocking mode: for the first 2-4 sprints, SAST generates reports only without blocking deploys. This allows the team to familiarize with the tools
  2. Establish a baseline: record the number of existing findings and focus on progressive reduction
  3. Focus on new code: apply strict thresholds only to new code, to avoid blocking the team on legacy technical debt
  4. Custom rules for context: create Semgrep/CodeQL rules specific to application patterns
  5. Weekly finding review: dedicate 1-2 weekly hours to SAST finding triage with the Security Champion
  6. Metrics and trends: track MTTR, false positive rate, and vulnerability density over time

Conclusions

SAST is the first line of defense in the DevSecOps paradigm. Identifying vulnerabilities in source code before it's executed saves time, money, and risk. The key to success is balancing coverage and usability: too many rules generate alert fatigue, too few let critical vulnerabilities through.

In the next article, we'll explore DAST (Dynamic Application Security Testing), the natural complement to SAST that analyzes running applications to find runtime vulnerabilities like XSS, CSRF, and misconfiguration.

Frequently asked questions

What is the main difference between Static Application Security Testing (SAST) and dynamic testing?

Unlike dynamic testing, which requires a running application, SAST examines source code without executing it to identify security vulnerabilities.

How does SonarQube analyze code beyond just security?

It analyzes code quality, detects code smells, identifies duplications, and measures test coverage in addition to its security analysis capabilities.

What is unique about Semgrep's approach to writing custom rules for static analysis?

Its pattern matching language allows writing security rules intuitively, almost like writing the code you want to find.

Why is it essential to balance coverage and usability when implementing SAST in a development pipeline?

Too many rules can generate alert fatigue, while too few may let critical vulnerabilities through.

Sources and further reading

Try These Tools

Free developer tools related to this topic.

Commenti

Caricamento commenti...

Sign in to comment

Discuss this article in the community

Join the Telegram group to discuss with other developers, ask questions and share your experiences.

Did you like this article?

Explore other content on the blog or discover my projects