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/codeqlrepo - SonarQube Rules: Built-in + marketplace plugins
Next, we'll integrate SAST into GitHub Actions for automated scanning. :::