Un SAST (Static Application Security Testing) est un scanner automatisé qui analyse le code source sans l'exécuter pour détecter les vulnérabilités de sécurité. Il fonctionne en parsant le code en AST (Abstract Syntax Tree), applique des règles de pattern matching ou de taint analysis (source-to-sink), et signale les findings mappés sur CWE, OWASP et CVSS. Les outils leaders 2026 sont Semgrep (r2c) en stack open source dominante, GitHub CodeQL pour analyse sémantique avancée, SonarQube pour qualité et sécurité basique, Snyk Code, Checkmarx SAST, Veracode en premium. Le SAST détecte 30 à 50 % des vulnérabilités selon OWASP Benchmark Project 2024, principalement les patterns syntaxiques (SQL injection, XSS, secrets hardcodés, crypto faible) mais ne peut pas détecter la logique métier défaillante, les chaînes multi-step et les vulnérabilités runtime. Les taux de faux positifs réels vont de 10 % (Semgrep tuné) à 50 % (Checkmarx non-tuné). L'intégration CI/CD est devenue la norme en 2026 : scan sur chaque PR, blocage sur severity HIGH ou CRITICAL, ingestion SARIF dans GitHub Security tab ou GitLab Ultimate. Cet article détaille la définition précise, les 3 techniques d'analyse (pattern matching, semantic, taint), la comparaison SAST vs SCA vs DAST vs IAST, les outils, comment écrire une règle custom, l'intégration pipeline, les limites et la checklist d'implémentation. Sources : OWASP Benchmark Project 2024, Semgrep docs, GitHub CodeQL docs, NIST SP 800-218.
1. Définition précise et positionnement dans le SDLC
SAST est l'acronyme de Static Application Security Testing : analyse statique de sécurité, par opposition au dynamique (DAST qui teste l'application en cours d'exécution).
Caractéristiques fondamentales
- Statique : n'exécute pas le code, analyse uniquement le texte source.
- White-box : accès complet au code source, vue exhaustive de l'arbre syntaxique.
- Scan réplicable : pour le même commit, les mêmes findings sortent.
- Rapide : un scan complet d'un projet moyen (100 kLoC) prend 1-10 minutes selon l'outil.
- Early detection : détection possible dès l'IDE (plugins) ou dès la PR.
Positionnement dans le SDLC
| Phase SDLC | Modalité SAST |
|---|---|
| IDE / Edition | Plugin temps réel (Semgrep VS Code, Snyk IDE) |
| Pre-commit hook | git-hooks (pre-commit + Semgrep light rules) |
| Pull Request | GitHub Actions ou GitLab CI (blocking ou warning) |
| Nightly CI | Scan complet avec règles étendues |
| Release gate | Block si finding critique non triagé |
| Pentest | Données SAST utilisées comme baseline |
Le SAST est la première ligne de défense du shift-left : il intercepte les vulnérabilités les moins coûteuses à corriger (avant merge) et libère les équipes AppSec pour les analyses manuelles à valeur ajoutée.
2. Comment ça marche vraiment : 3 techniques d'analyse
Tous les SAST ne sont pas équivalents. Trois techniques d'analyse coexistent, avec des trade-offs précision/rapidité/complexité distincts.
2.1 Pattern matching syntaxique (AST matching)
La plus simple et la plus rapide. L'outil parse le code en AST, cherche des patterns littéraux (à des métavariables près) dans la structure arborescente.
Exemple conceptuel : détecter eval(user_input) en Python.
Forces
- Rapide (scan de millions de lignes en minutes).
- Facile à customiser (règles YAML déclaratives).
- Peu de faux positifs sur patterns évidents.
Limites
- Incapable de suivre le flux de données à travers plusieurs fonctions.
- Ne détecte pas les renommages de variables ou wrappers intermédiaires.
Outils : Semgrep (r2c) est la référence, Bandit pour Python, Brakeman pour Ruby on Rails.
2.2 Analyse sémantique (data flow analysis)
L'outil construit un CFG (Control Flow Graph) et un DFG (Data Flow Graph), suit les données à travers les fonctions, comprend les types et les dépendances. Permet de détecter des vulnérabilités même quand les patterns ne sont pas évidents syntaxiquement.
Forces
- Détecte les vulnérabilités inter-procédurales (source dans fonction A, sink dans fonction B).
- Comprend les wrappers et les renommages.
- Réduction drastique des faux négatifs.
Limites
- Plus lent (30-60 min pour un projet moyen).
- Coût mémoire important.
- Complexité de configuration initiale.
Outils : GitHub CodeQL est la référence open source (gratuit pour repos publics), SonarQube en mode étendu, Checkmarx SAST en premium.
2.3 Taint analysis (source-to-sink)
Spécialisation de l'analyse sémantique orientée sécurité. L'outil définit des sources (points d'entrée de données non fiables : requête HTTP, input user, fichier) et des sinks (fonctions dangereuses : eval, exec, requête SQL, render HTML). Il trace les flux sources → sinks et signale tout chemin non-sanitizé.
Forces
- Modèle conceptuel direct des vulnérabilités web classiques (injection, XSS, SSRF).
- Faible taux de faux positifs si sources/sinks bien définis.
- Explicabilité : chaque finding est accompagné du chemin complet source → sink.
Limites
- Nécessite une base de règles source/sink maintenue.
- Les sanitizers custom peuvent ne pas être reconnus (faux positifs ou faux négatifs).
Outils : CodeQL, Semgrep Pro (mode taint), Snyk Code (basé sur DeepCode acquis 2020).
# Exemple Semgrep taint mode : SQL injection Python
rules:
- id: python-sql-injection-taint
mode: taint
pattern-sources:
- patterns:
- pattern-either:
- pattern: $REQ.args.get(...)
- pattern: $REQ.form.get(...)
- pattern: $REQ.json.get(...)
pattern-sinks:
- patterns:
- pattern-either:
- pattern: $CONN.execute($QUERY, ...)
- pattern: $CONN.query($QUERY, ...)
pattern-sanitizers:
- pattern: sqlalchemy.text($X).bindparams(...)
message: "SQL injection risk: tainted flow from HTTP input to SQL execute"
languages: [python]
severity: ERROR
metadata:
cwe: "CWE-89"
owasp: "A03:2021-Injection"3. Positionnement vs SCA, DAST, IAST
Comparatif concret des 4 paradigmes en 2026.
| Paradigme | Analyse | Cible | Détecte | Taux couverture |
|---|---|---|---|---|
| SAST | Code source statique | Code custom de l'équipe | Injection, XSS, secrets, crypto | 30-50 % vulns |
| SCA | Manifestes de dépendances | Dépendances tierces | CVE connues dans libs | 80-90 % CVE libs |
| DAST | App en exécution (HTTP/API) | Surface externe testée | Config, auth, logique runtime | 20-40 % vulns |
| IAST | Agent runtime dans l'app | Code en exécution instrumenté | SAST + contexte runtime | 40-60 % vulns |
| RASP | Agent runtime bloquant | Protection temps réel | Attaques en cours d'exécution | Protection, pas détection |
Cas d'usage complémentaires
- SAST + SCA = base obligatoire 2026. Ces deux paradigmes couvrent l'essentiel au coût le plus bas.
- DAST en complément pour la surface externe et la validation runtime.
- IAST réservé aux éditeurs premium avec équipe AppSec dédiée (Contrast Security, Jeddak).
- RASP marginal en France 2026, utilisé en runtime protection sur systèmes legacy difficiles à patcher.
Règle pragmatique d'adoption
- Année 1 : SAST Semgrep OSS + SCA Trivy. Zéro budget.
- Année 2 : ajouter DAST OWASP ZAP en nightly. Toujours zéro budget.
- Année 3+ : selon maturité, basculer premium si SLA ou reporting audit requis.
4. Outils SAST leaders 2026
Panorama des outils réellement utilisés en France 2026, classés par adoption.
4.1 Stack open source dominante
| Outil | Éditeur | Licence | Points forts | Langages |
|---|---|---|---|---|
| Semgrep OSS | r2c (GitLab acquisition 2024) | LGPL | Rapide, DSL YAML lisible, registry 2500+ rules | 30+ langages |
| GitHub CodeQL | GitHub (Microsoft) | GPL pour public repos | Analyse sémantique profonde, queries type langage | 12 langages majeurs |
| SonarQube Community | Sonar | LGPL | Qualité + sécurité, UI dashboard | 30+ langages |
| Bandit | PyCQA | Apache 2.0 | Python-spécifique, léger | Python uniquement |
| Brakeman | Brakeman team | MIT | Ruby on Rails-spécifique | Rails uniquement |
| GoSec | SecureGo | Apache 2.0 | Go-spécifique, règles CIS | Go uniquement |
4.2 Stack premium
| Outil | Éditeur | Positionnement | Prix indicatif 2026 |
|---|---|---|---|
| Semgrep Pro | r2c/GitLab | Semgrep + règles propriétaires + taint mode avancé | ≈ 40 $/dev/mois |
| Snyk Code | Snyk | SAST ML-based (ex DeepCode), intégration Snyk suite | 60-100 $/user/mois |
| Checkmarx SAST | Checkmarx | Enterprise historique, reporting audit | 80-200 k€/an |
| Veracode | Veracode | Enterprise SaaS, dominant banque | 100-300 k€/an |
| Fortify Static Code Analyzer | OpenText (ex Micro Focus) | Legacy enterprise, grands comptes | 100-250 k€/an |
| GitLab Ultimate SAST | GitLab | Intégré GitLab CI, basé Semgrep et autres | ≈ 99 $/user/mois |
4.3 Recommandations par contexte
- Startup tech (0-50 devs) : Semgrep OSS + CodeQL GitHub Actions. Budget zéro.
- Scale-up (50-300 devs) : Semgrep Pro ou Snyk Code. Budget 30-150 k€/an.
- ETI généraliste (300-1000 devs) : Checkmarx ou Veracode pour reporting audit, ou Semgrep Pro Enterprise. Budget 100-300 k€/an.
- Banque / OIV (1000+ devs, compliance forte) : Checkmarx ou Veracode obligatoires pour audit trail, intégration SARIF multi-outils. Budget 300-800 k€/an.
5. Écrire une règle SAST custom : exemple Semgrep
La capacité à écrire des règles custom est ce qui différencie un programme AppSec mature d'une simple implémentation outil. Exemple concret : détecter un usage dangereux spécifique à une stack interne.
5.1 Scénario
Une entreprise utilise un ORM custom InternalDb où la méthode .raw(query) accepte une string SQL directement. Les développeurs doivent toujours passer par .query(template, params) pour avoir la paramétrisation.
5.2 Règle Semgrep
# .semgrep/rules/internal-db-raw-sql.yaml
rules:
- id: internal-db-raw-sql-usage
patterns:
- pattern: $DB.raw($QUERY)
- pattern-not: $DB.raw("...") # Autorise les strings statiques literal
message: |
Utilisation de InternalDb.raw() avec une query construite
dynamiquement. Utiliser InternalDb.query(template, params) pour
bénéficier de la paramétrisation automatique et prévenir les
SQL injection.
languages: [typescript, javascript]
severity: ERROR
metadata:
cwe: "CWE-89"
owasp: "A03:2021-Injection"
confidence: HIGH
fix: $DB.query($QUERY, [])5.3 Test de la règle
Semgrep supporte les tests unitaires de règles via fichiers *.test.ts ou équivalent :
// internal-db-raw-sql.test.ts
// Cas positif : doit matcher
const db = new InternalDb();
const userId = req.params.id;
// ruleid: internal-db-raw-sql-usage
db.raw(`SELECT * FROM users WHERE id = ${userId}`);
// Cas négatif : ne doit pas matcher (string literal statique autorisée)
db.raw("SELECT NOW()");
// Cas négatif : ne doit pas matcher (usage correct)
db.query("SELECT * FROM users WHERE id = ?", [userId]);Commande de test : semgrep --test .semgrep/rules/.
5.4 Déploiement
- Commit dans
.semgrep/rules/. - Pipeline GitHub Actions
semgrep-actionqui inclut le dossier.semgrep. - Findings remontés en SARIF dans GitHub Security tab.
- Documentation interne partagée avec les devs (raison de la règle, exemples corrects et incorrects).
6. Intégration CI/CD : pipeline de référence 2026
Exemple GitHub Actions complet combinant Semgrep + SCA Trivy + secrets gitleaks, avec ingestion SARIF.
# .github/workflows/security.yml
name: security
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
security-events: write # obligatoire pour upload-sarif
jobs:
sast-semgrep:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Semgrep scan
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/owasp-top-ten
p/cwe-top-25
p/secrets
.semgrep/rules/
generateSarif: "1"
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: semgrep.sarif
codeql:
runs-on: ubuntu-latest
strategy:
matrix:
language: [javascript, python]
steps:
- uses: actions/checkout@v4
- uses: github/codeql-action/init@v3
with:
languages: matrix.language
queries: security-extended
- uses: github/codeql-action/analyze@v3
sca-trivy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Trivy SCA
uses: aquasecurity/trivy-action@master
with:
scan-type: fs
severity: HIGH,CRITICAL
exit-code: "1"
format: sarif
output: trivy-results.sarif
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-results.sarif
secrets-gitleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2Pattern d'échec bloquant vs warning
- Bloquant (fail pipeline) : CVSS ≥ 7.0, secrets hardcodés détectés, CVE critique sur dépendance production.
- Warning (log only) : severity MEDIUM, CVE LOW ou MEDIUM, code smells qualité.
7. Les 5 limites structurelles du SAST
Comprendre les limites évite les illusions de couverture sécurité.
7.1 Business logic invisible
Un SAST ne sait pas détecter :
- Un IDOR (Insecure Direct Object Reference) :
GET /api/orders/123accessible à un user non propriétaire. - Un bypass d'autorisation métier : workflow e-commerce qui permet d'appliquer un coupon plusieurs fois.
- Une condition race : transfert bancaire simultané avec solde insuffisant.
Raison : le SAST voit la syntaxe, pas la sémantique métier. Il ne sait pas que orders/:id devrait être filtré par user_id.
7.2 Vulnérabilités runtime et configuration
- Variables d'environnement en prod vs dev.
- Headers HTTP manquants (CSP, HSTS, X-Content-Type-Options).
- CORS ouvert à
*via variable externe. - Mauvaise config reverse-proxy (nginx, Cloudflare).
Ces problèmes apparaissent uniquement au runtime, invisibles au scan statique.
7.3 Frameworks et abstractions opaques
Si votre code utilise un framework custom ou un DSL interne, le SAST ne comprend pas les contrats implicites. Exemple : un décorateur @secure custom qui sanitize des inputs sera invisible pour Semgrep sans règle spécifique.
7.4 Taux de faux positifs sous-estimé
Chiffres réels observés en production France 2024-2026 selon études OWASP Benchmark et retours cabinets :
- Semgrep OSS default rules : 15-30 % FP.
- Semgrep avec tuning 6 mois : 5-12 % FP.
- CodeQL security-extended : 20-35 % FP.
- SonarQube Developer : 25-40 % FP.
- Checkmarx non-tuné : 30-50 % FP.
Le coût de triage est significatif : 2-5 minutes par alerte en régime stable, 10-30 minutes en phase de découverte.
7.5 Dette technique et legacy code
Un scan sur une base de code legacy produit typiquement des milliers de findings. La tentation est de disable la règle ou de flood le backlog. Stratégie recommandée : scan initial sur main → baseline des findings existants → ne bloquer que les new findings introduits par PR, laisser une backlog épiclass pour legacy à résorber progressivement.
# Pseudo-logique baseline Semgrep
def should_block_pr(findings_on_pr, baseline_findings):
"""
Ne bloque que les findings nouveaux introduits par la PR.
Les findings pré-existants sont trackés mais non-bloquants.
"""
new_findings = [
f for f in findings_on_pr
if f.fingerprint not in baseline_findings
]
critical_new = [f for f in new_findings if f.severity >= 7.0]
return len(critical_new) > 08. Tuning des faux positifs et gestion des ignores
Un outil SAST mal tuné génère plus de bruit que de valeur. 4 pratiques de tuning éprouvées.
8.1 Ignorer une règle globalement quand non pertinente
Exemple : une règle détectant Math.random comme source non-cryptographique est sans intérêt si le codebase n'implémente pas de primitives crypto.
# .semgrep.yaml
rules:
- id: javascript.crypto.security.audit.math-random.math-random
paths:
exclude:
- "src/ui/**" # UI ne fait pas de crypto8.2 Annotations inline justifiées
Pour un cas ponctuel documenté :
// nosemgrep: javascript.express.security.audit.xss.direct-response-write
// Reason: output is already sanitized via DOMPurify at ingestion in processInput
res.write(sanitizedContent);Règle interne : jamais de nosemgrep sans commentaire explicite de raison + revue AppSec si la règle concerne CWE Top 25.
8.3 Custom rules pour remplacer les génériques
Si une règle générique produit 80 % de FP sur votre stack, écrire une règle custom plus précise qui matche uniquement les vrais cas problématiques.
8.4 Monitoring du taux d'ignore
KPI à suivre mensuellement en équipe AppSec :
- Taux d'ignore par équipe (si >20 %, challenge).
- Délai moyen de triage (si >10 min en régime stable, retuner règles).
- Taux de faux positifs estimé (si >30 %, revue de règles ou outil).
9. Critères de choix d'outil SAST
Grille de décision structurée pour choisir l'outil adapté.
| Critère | Questions à se poser |
|---|---|
| Langages | Le outil supporte-t-il tous vos langages en profondeur ? |
| Taille de codebase | Temps de scan acceptable pour CI (moins de 10 min sur PR) ? |
| Faux positifs | Taux mesurable sur POC 2-4 semaines ? |
| Tuning et extensibilité | Règles custom faciles à écrire (YAML, QL) ? |
| Intégration CI | Natif GitHub/GitLab Actions ou scripts ? |
| Reporting et audit | Exports SARIF, PDF audit, intégration DefectDojo ? |
| SLA et support | Engagement de bug fixing et roadmap publique ? |
| Coût total | Licence + temps équipe AppSec + infra self-hosted ? |
| Souveraineté | Hébergement France/UE requis ? |
| Certifications | SOC 2, ISO 27001, HDS selon secteur ? |
10. Checklist d'implémentation SAST mature
20 contrôles pour évaluer la maturité d'un programme SAST.
checklist_sast_maturite = {
# Implémentation de base
"outil_choisi": "Semgrep / CodeQL / SonarQube / autre documenté",
"pipeline_integre": "Scan sur chaque PR + nightly sur main",
"sarif_ingestion": "Results ingestion GitHub Security ou GitLab Ultimate",
"seuil_bloquant": "Severity HIGH+ bloque la PR, MEDIUM warning",
# Règles et couverture
"regles_owasp_top10": "p/owasp-top-ten ou équivalent activé",
"regles_cwe_top25": "p/cwe-top-25 ou équivalent activé",
"regles_secrets": "Scan secrets intégré (entropy + regex)",
"regles_custom_stack": "Au moins 5 règles custom pour stack interne",
"taint_mode": "Taint analysis activée pour langages critiques",
# Qualité et tuning
"baseline_legacy": "Baseline des findings legacy, bloquant uniquement new",
"taux_fp_mesure": "Taux de faux positifs mesuré < 20 %",
"triage_moyen": "Temps de triage moyen < 5 min/finding en régime stable",
"ignores_audites": "Review mensuelle des ignores et nosemgrep",
# Équipe et culture
"security_champions": "1 security champion par équipe dev formé SAST",
"dashboard_equipes": "Dashboard findings par équipe mis à jour",
"formations_regulieres": "Formation SAST annuelle devs",
"retros_appsec": "Retro AppSec mensuelle avec devs et RSSI",
# Compliance et reporting
"traçabilite_pr": "Chaque finding tracé à une PR et un dev",
"export_audit": "Export SARIF disponible pour auditeurs externes",
"mapping_owasp": "Mapping OWASP et CWE dans les reports",
}
# Viser 80+ % des checks validés pour programme SAST maturePoints clés à retenir
- SAST = Static Application Security Testing, analyse le code source sans l'exécuter pour détecter les vulnérabilités via AST matching, analyse sémantique ou taint analysis.
- Outils leaders 2026 : Semgrep OSS (start-up à ETI), CodeQL (repos publics gratuits), SonarQube (qualité+sécu), Snyk Code / Checkmarx / Veracode (premium enterprise).
- Couverture 30-50 % des vulnérabilités selon OWASP Benchmark 2024 : patterns syntaxiques (injection, XSS, secrets, crypto), pas la logique métier ni le runtime.
- Faux positifs : 10 % (Semgrep tuné 6 mois) à 50 % (Checkmarx non-tuné). Temps de triage 2-5 min/finding en régime stable.
- Complémentaire : SAST + SCA en base obligatoire, DAST en complément surface externe, pentest pour la logique métier.
- Intégration CI/CD : scan sur chaque PR, seuil bloquant CVSS ≥ 7.0, ingestion SARIF dans GitHub Security ou GitLab Ultimate.
- Règles custom valorisent l'investissement : 2-6 h par règle pour capturer un pattern métier récurrent.
- Baseline legacy : ne bloquer que les new findings introduits par PR, gérer la dette existante hors bloquant.
- Stratégie d'adoption 2026 : Semgrep OSS année 1 (budget zéro), SCA Trivy + DAST ZAP année 2, basculer premium uniquement si SLA ou audit exigé.
Pour aller plus loin
- SAST vs DAST — comparatif approfondi des paradigmes SAST et DAST.
- Introduction OWASP Top 10 — catégories détectées majoritairement par SAST.
- Pourquoi apprendre le secure coding — complément humain au SAST automatisé.
- Gestion de session sécurisée — vulnérabilités session souvent non détectées par SAST.
- Roadmap AppSec Engineer — SAST dans le parcours AppSec global.






