SAST Tools & Static Code Analysis: The Complete Developer Guide

Written by the Rafter Team

Static Application Security Testing (SAST) tools analyze your source code for vulnerabilities without executing it. They catch SQL injection, cross-site scripting, hardcoded secrets, insecure configurations, and dozens of other flaws before your code leaves the development environment. For developers shipping code daily, SAST is the fastest way to find security issues—before attackers do.
The market for static code analysis tools has exploded. Semgrep, SonarQube, CodeQL, Snyk Code, Checkmarx—each tool makes bold claims about detection rates and developer experience. But choosing the wrong SAST tool wastes engineering time on false positives, misses critical vulnerabilities, or creates pipeline bottlenecks that slow your entire team. This guide cuts through the noise with a practical, developer-focused breakdown of how SAST works, which tools actually deliver, and how to integrate static analysis into your workflow without friction.
SAST catches bugs that unit tests miss. A test verifies that code works correctly—SAST verifies that code works safely. SQL injection, path traversal, and insecure deserialization don't cause test failures, but they cause breaches. If you're only running tests, you're only checking half the picture.
Try Rafter free — connect your GitHub repo and get your first SAST scan in 30 seconds to 2 minutes.
How Static Code Analysis Works
Static analysis examines source code, bytecode, or binaries without running the application. Think of it as a code reviewer that reads every line, traces every data flow, and checks every pattern against a database of known vulnerability signatures—at machine speed.
The Analysis Pipeline
Every SAST tool follows roughly the same pipeline:
-
Parsing: The tool parses your source code into an Abstract Syntax Tree (AST)—a structured representation of your code's logic, variables, and control flow.
-
Semantic analysis: The tool resolves types, scopes, and function signatures. It understands that
getUserInput()returns a string and thatdb.query()accepts SQL. -
Taint tracking: This is where the real security analysis happens. The tool traces data from sources (user input, HTTP parameters, file reads) through propagators (string concatenation, variable assignment) to sinks (database queries, HTML output, system commands). If untrusted data reaches a dangerous sink without sanitization, the tool flags a vulnerability.
-
Pattern matching: Beyond taint tracking, SAST tools match code against known-bad patterns: hardcoded credentials, insecure cryptographic algorithms, missing authentication checks, debug endpoints left in production code.
-
Reporting: Results are deduplicated, ranked by severity, and mapped to CWE (Common Weakness Enumeration) categories for standardized vulnerability classification.
What SAST Catches (and What It Misses)
SAST excels at finding:
- Injection flaws: SQL injection, XSS, command injection, LDAP injection—any pattern where untrusted input flows into a dangerous operation
- Hardcoded secrets: API keys, passwords, tokens, and credentials embedded in source code
- Insecure configurations: Weak cryptographic algorithms, disabled security headers, permissive CORS policies
- Code quality issues with security implications: Buffer overflows, null pointer dereferences, use-after-free, race conditions
- Known vulnerable patterns: Deserialization of untrusted data, XML External Entity (XXE) processing, path traversal
SAST struggles with:
- Business logic flaws: A SAST tool can't tell that your discount code should only apply once, or that users shouldn't be able to transfer money to themselves
- Authentication and authorization logic: While SAST can find missing auth checks, it can't validate that your authorization model is correct
- Runtime-dependent vulnerabilities: Issues that only manifest under specific configurations, environment variables, or deployment conditions
- Third-party API misuse: SAST typically doesn't model the security semantics of every external API you call
This is why SAST works best as part of a layered security strategy. Combine it with Dynamic Application Security Testing (DAST), Software Composition Analysis (SCA) for dependency vulnerabilities, and manual penetration testing for business logic review.
Comparing Top SAST Tools for Developers
The static code analysis tools market splits into three tiers: open-source tools that are free but require configuration, developer-focused commercial tools that prioritize experience, and enterprise platforms that optimize for compliance reporting.
Open-Source SAST Tools
Semgrep
Semgrep has become the default choice for teams that want lightweight, fast static analysis. It uses a pattern-matching approach where rules look like the code they're trying to find—making it easy for developers to write custom rules without learning a specialized query language.
# Example Semgrep rule: detect SQL injection in Python
rules:
- id: sql-injection-python
pattern: |
cursor.execute($QUERY % ...)
message: "Possible SQL injection via string formatting"
severity: ERROR
languages: [python]
Strengths: Fast scan times (seconds, not minutes), 2,000+ community rules, easy custom rule authoring, CI/CD-friendly CLI, supports 30+ languages.
Limitations: Pattern-matching approach means less sophisticated taint tracking than dataflow-based tools. Complex multi-file vulnerability chains may be missed. The open-source version (Semgrep OSS) has fewer rules than the commercial Semgrep Code product.
Best for: Teams that want fast feedback in CI/CD, projects using multiple languages, teams with security engineers who want to write custom rules.
CodeQL (GitHub)
CodeQL treats code as data. You write queries in a SQL-like language (QL) that run against a database representation of your codebase. This enables deep semantic analysis—CodeQL can trace data flows across function boundaries, modules, and even some library abstractions.
// Example CodeQL query: find SQL injection in JavaScript
import javascript
from Http::RequestExpr source, DatabaseQuery sink
where source.flowsTo(sink.getAnArgument())
select sink, "SQL injection from $@.", source, "user input"
Strengths: Deep dataflow analysis, free for public repositories on GitHub, integrated into GitHub Advanced Security, strong academic foundations (developed at Semmle/Oxford).
Limitations: Slow build times (requires creating a CodeQL database), limited language support compared to Semgrep (C/C++, C#, Go, Java/Kotlin, JavaScript/TypeScript, Python, Ruby, Swift), steep learning curve for writing custom queries, free tier limited to public repos.
Best for: Open-source projects on GitHub, teams that need deep dataflow analysis, organizations already using GitHub Advanced Security.
Bandit (Python), ESLint Security Plugins (JavaScript), Brakeman (Ruby)
Language-specific SAST tools offer targeted analysis for their ecosystems:
- Bandit scans Python code for common security issues:
eval()usage, hardcoded passwords, insecure SSL settings, dangerous imports - ESLint with security plugins (
eslint-plugin-security,eslint-plugin-no-unsanitized) catches DOM-based XSS, prototype pollution, and unsafe regular expressions in JavaScript - Brakeman analyzes Ruby on Rails applications for SQL injection, XSS, mass assignment, and other Rails-specific vulnerabilities
Best for: Single-language projects or as a complement to a broader SAST tool.
Commercial SAST Tools
Snyk Code
Snyk Code uses a machine-learning-assisted approach to static analysis. It combines symbolic AI (traditional rule-based analysis) with a model trained on millions of code patterns to reduce false positives and provide contextual fix suggestions.
Strengths: Low false positive rates (Snyk claims 2-3x fewer than traditional SAST), fast scan times, inline fix suggestions in IDE, good developer experience, integrates with Snyk's SCA and container scanning.
Limitations: Commercial pricing can be significant at scale, ML-based approach can be opaque (harder to understand why something was flagged), limited custom rule support compared to Semgrep.
Best for: Development teams that prioritize developer experience and want a unified vulnerability management platform across code, dependencies, and containers.
SonarQube / SonarCloud
SonarQube is the incumbent in code quality and security analysis. It combines SAST with code quality metrics (code smells, technical debt, test coverage) in a single platform.
Strengths: Broad language support (30+), mature platform with extensive documentation, good quality gate integration for CI/CD, SonarCloud offers free tier for open-source, established in enterprise environments.
Limitations: Security analysis is secondary to code quality (detection depth may lag dedicated SAST tools), self-hosted SonarQube requires infrastructure management, can generate significant false positives on security rules, Developer Edition required for branch analysis.
Best for: Teams that want combined code quality and security analysis, organizations already invested in the SonarQube ecosystem.
Checkmarx SAST
Checkmarx is the enterprise gold standard for SAST. It offers the deepest dataflow analysis, the broadest compliance reporting, and the most comprehensive language support—but at enterprise pricing and complexity.
Strengths: Deep dataflow analysis across complex codebases, extensive compliance reporting (SOC 2, PCI DSS, HIPAA), broad language support, incremental scanning for faster CI/CD integration.
Limitations: Enterprise pricing (typically $50K+/year), complex configuration and tuning required, slower scan times than lightweight tools, steep learning curve.
Best for: Large enterprises with compliance requirements, organizations with dedicated application security teams.
SAST Tool Comparison Matrix
| Feature | Semgrep | CodeQL | Snyk Code | SonarQube | Checkmarx |
|---|---|---|---|---|---|
| Pricing | Free (OSS) / Commercial | Free (public repos) | Freemium | Free (CE) / Commercial | Enterprise |
| Languages | 30+ | 8 | 15+ | 30+ | 30+ |
| Scan Speed | Seconds | Minutes | Seconds | Minutes | Minutes-Hours |
| Custom Rules | Easy (code-like syntax) | QL (steep learning curve) | Limited | XML/Java | CxQL |
| CI/CD Integration | Native CLI | GitHub Actions | Native CLI | Plugin-based | API/Plugin |
| False Positive Rate | Medium | Low-Medium | Low | Medium-High | Medium |
| Taint Tracking | Basic (OSS) / Advanced (Pro) | Advanced | Advanced (ML-assisted) | Basic | Advanced |
| IDE Integration | VS Code, IntelliJ | VS Code (limited) | VS Code, IntelliJ, more | VS Code, IntelliJ | VS Code, IntelliJ, Eclipse |
| Best For | Fast CI/CD scanning | Deep analysis on GitHub | Developer experience | Code quality + security | Enterprise compliance |
Integrating SAST Into Your Development Workflow
The worst way to adopt SAST is to dump 10,000 findings on your team after scanning a mature codebase. Developers will ignore the results, disable the scanner, and you'll have wasted everyone's time. Here's how to integrate static analysis effectively.
Start With a Baseline Scan
Run your chosen SAST tool against the existing codebase and triage the results:
- Critical and High severity: Fix these immediately. SQL injection, hardcoded production credentials, and command injection in user-facing code are not technical debt—they're active risk.
- Medium severity: Create tickets and prioritize alongside feature work.
- Low severity and informational: Suppress or track for later. These are real issues but low-impact.
# Example: Baseline scan with Semgrep
semgrep scan --config=p/security-audit --json > baseline-results.json
# Count findings by severity
cat baseline-results.json | jq '.results | group_by(.extra.severity) | map({severity: .[0].extra.severity, count: length})'
Gate New Code, Not Legacy Code
Configure your SAST tool to only fail on new findings. This prevents the baseline from blocking your entire pipeline while ensuring no new vulnerabilities slip through:
# GitHub Actions: Semgrep with baseline
name: SAST Scan
on: [pull_request]
jobs:
semgrep:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Semgrep
uses: semgrep/semgrep-action@v1
with:
config: p/default
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
Most SAST tools support differential scanning natively. Semgrep uses --baseline-commit, CodeQL compares against the base branch, and Snyk Code filters by new findings in PR checks.
IDE Integration: Shift Left to the Developer's Editor
The fastest feedback loop is the developer's editor. Configure your SAST tool to run in your IDE so vulnerabilities appear as you write code—not after you push:
- Semgrep: VS Code extension with real-time scanning
- Snyk Code: VS Code, IntelliJ, and other JetBrains IDEs
- SonarLint: Connects to SonarQube/SonarCloud for consistent rule sets
- ESLint security plugins: Native ESLint integration in any JavaScript-capable editor
IDE integration catches approximately 60% of issues before code is even committed. It's the highest-ROI security investment you can make in developer tooling.
CI/CD Pipeline Integration
For teams shipping through CI/CD pipelines, SAST should run on every pull request. Here's a practical integration pattern:
# GitHub Actions: Multi-tool security scanning
name: Security Gates
on:
pull_request:
branches: [main, develop]
jobs:
sast-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: SAST Scan
run: |
# Run your SAST tool
semgrep scan --config=auto --error --json > sast-results.json
- name: Check for Critical Findings
run: |
CRITICAL=$(cat sast-results.json | jq '[.results[] | select(.extra.severity == "ERROR")] | length')
if [ "$CRITICAL" -gt 0 ]; then
echo "::error::Found $CRITICAL critical security findings"
exit 1
fi
Pipeline best practices:
- Fail on Critical/High only: Block PRs for serious vulnerabilities but don't break the pipeline for informational findings
- Cache scan results: SAST tools that build code databases (CodeQL, Checkmarx) benefit significantly from caching
- Set time limits: A SAST scan that takes 30 minutes will get disabled. Target under 5 minutes for PR checks
- Report inline: Use tools that post findings as PR comments so developers see issues in context
For a deeper dive on pipeline security, see our guide on CI/CD Security Best Practices.
Handling False Positives
Every SAST tool produces false positives. The question is how you manage them without training developers to ignore all findings:
1. Inline suppressions with justification:
# nosemgrep: sql-injection-python
# Reason: query uses parameterized input from ORM, not user input
cursor.execute(query)
2. Centralized suppression files:
# .semgrepignore or equivalent
# Suppress test files (they intentionally contain vulnerable patterns)
tests/security/
fixtures/vulnerable-samples/
3. Rule tuning: Disable rules that consistently produce false positives for your codebase. Every false positive erodes developer trust, and a distrusted tool is a useless tool.
4. Triage workflows: Assign a security champion on each team to review new findings weekly. Categorize as true positive, false positive, or accepted risk—and document the decision.
SAST for AI-Generated Code
AI coding assistants have made SAST more important, not less. Tools like Cursor, GitHub Copilot, and Lovable generate functional code fast—but they optimize for "it works," not "it's secure." Research from Veracode found that 45% of AI-generated code contains security flaws.
Why AI-Generated Code Needs Static Analysis
AI assistants produce predictable vulnerability patterns:
- Hardcoded secrets: The model generates working code with real-looking API keys and database URLs embedded inline
- Missing input validation: AI builds the happy path—user input flows directly to database queries, file operations, and API calls
- Insecure defaults: AI uses the simplest configuration that works, which often means disabled security features (no HTTPS enforcement, no CSP headers, no rate limiting)
- Outdated patterns: Models trained on older code produce deprecated cryptographic functions, insecure deserialization patterns, and abandoned libraries with known CVEs
Static analysis catches all of these patterns automatically. For teams using AI coding tools, SAST is the safety net that prevents generated code from shipping with generated vulnerabilities.
// ✗ Vulnerable: Typical AI-generated database query
app.get('/users/:id', (req, res) => {
const query = `SELECT * FROM users WHERE id = ${req.params.id}`;
db.query(query, (err, results) => {
res.json(results);
});
});
// ✓ Secure: Parameterized query (what SAST will push you toward)
app.get('/users/:id', (req, res) => {
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [req.params.id], (err, results) => {
res.json(results);
});
});
For a comprehensive breakdown of AI-generated code risks, see our Vibe Coding Security Guide.
Scanning AI-Generated Code With Rafter
Rafter is built specifically for scanning modern applications, including AI-generated codebases. It combines static analysis with contextual understanding of frameworks like Next.js, Supabase, and common vibe-coding stacks to surface vulnerabilities that generic SAST tools miss.
Unlike traditional SAST tools that require complex configuration, Rafter connects to your GitHub repository and starts scanning immediately. It understands framework-specific security patterns—like missing Supabase Row-Level Security policies or exposed Next.js API routes—that general-purpose tools ignore.
Rafter's SAST engine is optimized for the patterns that AI coding tools produce. It catches hardcoded secrets, missing auth, open database policies, and insecure API routes across your entire codebase in seconds. Try it free.
Building a SAST Strategy: From Zero to Full Coverage
If you're starting from scratch, here's a phased approach to adopting static code analysis tools that won't overwhelm your team.
Phase 1: Quick Wins (Week 1)
- Install a lightweight SAST tool (Semgrep or Snyk Code) and run a baseline scan
- Enable IDE integration for real-time feedback while coding
- Fix critical findings: Hardcoded secrets, SQL injection, command injection
- Set up secrets scanning: This alone prevents the most common and damaging vulnerability class
Phase 2: CI/CD Integration (Week 2-3)
- Add SAST to your PR pipeline with differential scanning (new findings only)
- Configure severity-based gating: Block on Critical/High, warn on Medium
- Set up automated PR comments so developers see findings in context
- Integrate with automated security scanning for continuous protection
Phase 3: Coverage Expansion (Month 2)
- Add language-specific tools (Bandit for Python, Brakeman for Ruby) alongside your primary SAST tool
- Write custom rules for your application's specific patterns (internal API usage, framework conventions)
- Establish a triage workflow with security champions on each team
- Track metrics: Finding density per PR, mean time to remediate, false positive rate
Phase 4: Maturity (Month 3+)
- Combine SAST with DAST for runtime vulnerability detection
- Add SCA (Software Composition Analysis) for dependency vulnerability scanning
- Implement security scorecards per service or repository
- Automate compliance reporting if required (SOC 2, PCI DSS, HIPAA)
Common Pitfalls to Avoid
1. Scanning everything at once. The fastest way to kill SAST adoption is to scan your entire monorepo and present 5,000 findings to a team that's never seen a SAST report. Start with critical paths, expand incrementally.
2. Blocking the pipeline on every finding. If a low-severity code quality issue prevents a hotfix from deploying, developers will disable the scanner. Gate on critical security issues only.
3. Ignoring false positives. Every unaddressed false positive teaches developers to ignore the tool. Invest time in tuning rules and suppressing known false positives with documented justifications.
4. Treating SAST as a silver bullet. SAST finds code-level vulnerabilities. It doesn't find business logic flaws, configuration errors in your cloud infrastructure, or vulnerabilities in your third-party dependencies. Use it as one layer in a defense-in-depth strategy.
5. Choosing tools by feature count. The best SAST tool is the one your team actually uses. A fast, developer-friendly tool with 80% detection coverage beats a comprehensive enterprise tool that nobody runs because it takes 45 minutes per scan.
6. Not updating rules. New vulnerability patterns emerge constantly. Ensure your SAST rules are updated regularly—most tools provide automatic rule updates through managed rulesets.
SAST vs. Other Security Testing Methods
Understanding where SAST fits in the broader security testing landscape helps you build effective coverage without redundant tooling.
| Method | When It Runs | What It Finds | What It Misses |
|---|---|---|---|
| SAST | Before deployment (code-level) | Code vulnerabilities, secrets, insecure patterns | Runtime behavior, business logic, config issues |
| DAST | After deployment (runtime) | Runtime vulnerabilities, auth issues, header misconfigs | Source code issues, requires running application |
| SCA | Build time (dependency-level) | Known CVEs in dependencies, license issues | Custom code vulnerabilities |
| IAST | During testing (instrumented runtime) | Runtime data flow + code context | Requires test coverage, agent overhead |
| Penetration Testing | Periodic (manual) | Business logic, complex attack chains, creative exploits | Expensive, point-in-time, doesn't scale |
The strongest security posture combines SAST (catch code issues early), SCA (catch dependency issues at build), and DAST (catch runtime issues post-deploy). Add penetration testing quarterly for business logic review.
For a detailed comparison of security testing tools, see our Security Tool Comparisons guide.
Your Next Steps
Static code analysis tools are the most accessible security investment a development team can make. They require no security expertise to get started, they integrate into workflows developers already use, and they catch the vulnerability classes responsible for the vast majority of breaches.
Here's your action plan:
- Pick a SAST tool. For most teams, start with Semgrep (open-source, fast, low friction) or Snyk Code (best developer experience, low false positives).
- Run a baseline scan. Fix critical findings immediately, triage the rest.
- Add to CI/CD. Gate pull requests on new critical/high findings.
- Enable IDE integration. Catch issues before they're even committed.
- Scan with Rafter. Connect your GitHub repo and get framework-aware security analysis across your entire codebase. Start scanning for free.
Security vulnerabilities in production are expensive. Security vulnerabilities caught in a developer's editor cost nothing. SAST closes that gap.
Start scanning your code — Rafter runs SAST, SCA, and secrets detection in a single scan, free to get started.