Static Application Security Testing (SAST)

SAST Tools: Semgrep, CodeQL, SonarQube

3 min read

Choosing the right SAST tool depends on your stack, budget, and security maturity. Let's compare the top three options.

Tool Comparison

Feature Semgrep CodeQL SonarQube
License OSS + Commercial Free for OSS Community + Commercial
Languages 30+ languages 10+ languages 30+ languages
Speed Very fast Slower (compiles) Medium
Custom Rules YAML (easy) QL language (complex) XML/Java (moderate)
CI Integration Excellent GitHub native Excellent
Best For Fast adoption, custom rules Deep analysis, GitHub users Code quality + security

Semgrep: Fast and Flexible

Semgrep is known for speed and simple rule syntax.

Installation

# Install via pip
pip install semgrep

# Or via Homebrew
brew install semgrep

Basic Usage

# Run with auto-config (community rules)
semgrep --config auto .

# Run specific rulesets
semgrep --config p/security-audit --config p/secrets .

# Scan specific languages
semgrep --config auto --lang python .

Custom Rule Example

# .semgrep/rules/no-exec.yaml
rules:
  - id: dangerous-exec
    patterns:
      - pattern: exec($X)
    message: "Avoid exec() - potential code injection"
    severity: ERROR
    languages: [python]

Semgrep in CI

# GitHub Actions
- name: Semgrep Scan
  uses: returntocorp/semgrep-action@v1
  with:
    config: >-
      p/security-audit
      p/secrets
      p/python

CodeQL: Deep Semantic Analysis

CodeQL (by GitHub) provides the deepest analysis but requires compilation.

Setup with GitHub

# .github/workflows/codeql.yml
name: CodeQL Analysis
on: [push, pull_request]

jobs:
  analyze:
    runs-on: ubuntu-latest
    permissions:
      security-events: write

    steps:
      - uses: actions/checkout@v4

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: javascript, python

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v3

Custom CodeQL Query

// find-sql-injection.ql
import python
import semmle.python.security.dataflow.SqlInjection

from SqlInjection::Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "SQL injection from $@.", source.getNode(), "user input"

SonarQube: Security + Quality

SonarQube combines security scanning with code quality metrics.

Docker Setup

# Run SonarQube locally
docker run -d --name sonarqube \
  -p 9000:9000 \
  sonarqube:community

Scanner Configuration

# sonar-project.properties
sonar.projectKey=my-project
sonar.sources=src
sonar.host.url=http://localhost:9000
sonar.token=your-token-here

# Security-specific settings
sonar.security.hotspots.inheritedRules=true

CI Integration

# GitHub Actions with SonarCloud
- name: SonarCloud Scan
  uses: SonarSource/sonarcloud-github-action@master
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

Choosing the Right Tool

Scenario Recommendation
Startup, fast setup Semgrep
GitHub-native, OSS project CodeQL
Enterprise, code quality focus SonarQube
Multiple tools Semgrep (fast) + CodeQL (deep)

Rule Sources

Don't reinvent the wheel—use community rules:

  • Semgrep Registry: semgrep.dev/r - 3000+ rules
  • CodeQL Queries: Built-in + github/codeql repo
  • SonarQube Rules: Built-in + marketplace plugins

Next, we'll integrate SAST into GitHub Actions for automated scanning. :::

Quiz

Module 2: Static Application Security Testing (SAST)

Take Quiz
FREE WEEKLY NEWSLETTER

Stay on the Nerd Track

One email per week — courses, deep dives, tools, and AI experiments.

No spam. Unsubscribe anytime.