Aller au contenu

Semgrep : analyse statique du code pour la sécurité

Mise à jour :

En 2022, un développeur découvre une injection SQL dans une application critique. Le code vulnérable existait depuis trois ans, relu par des dizaines de personnes. Un simple scan Semgrep aurait détecté le problème en quelques secondes. L’outil n’a pas besoin de comprendre la logique métier — il reconnaît les patterns dangereux.

Qu’est-ce que Semgrep ?

Semgrep est un outil d’analyse statique de code (SAST). Concrètement, il lit votre code source — sans l’exécuter — et cherche des patterns (modèles) qui correspondent à des vulnérabilités connues, des bugs ou des mauvaises pratiques.

Imaginez un correcteur orthographique, mais pour la sécurité du code. Au lieu de chercher des fautes d’orthographe, Semgrep cherche des constructions dangereuses comme :

# Semgrep détecte ce pattern dangereux
query = "SELECT * FROM users WHERE id = " + user_input
cursor.execute(query) # ⚠️ Injection SQL possible !

Le nom “Semgrep” vient de “semantic grep” : c’est comme la commande grep qui cherche du texte, mais en comprenant la structure du code. Semgrep sait qu’une variable est une variable, qu’une fonction est une fonction, etc.

Pourquoi utiliser Semgrep plutôt qu’un autre outil ?

Plusieurs scanners SAST existent sur le marché. Voici ce qui distingue Semgrep :

AspectSemgrepScanners traditionnels
RèglesFichiers YAML lisibles par un humainFormats propriétaires, boîte noire
VitesseTrès rapide (quelques secondes)Souvent plusieurs minutes
Langages30+ supportés nativementVariable selon l’outil
Faux positifsRelativement peuSouvent nombreux
LicenceOpen source (LGPL 2.1)Souvent commercial
PersonnalisationÉcrire ses règles en 5 minutesComplexe ou impossible

Ce que Semgrep sait détecter

Semgrep est particulièrement efficace pour trouver :

Vulnérabilités de sécurité :

  • Injections SQL : quand des données utilisateur sont insérées directement dans des requêtes de base de données
  • Cross-Site Scripting (XSS) : quand des données utilisateur sont affichées sans être échappées dans une page web
  • Command injection : quand des données utilisateur sont passées à des commandes système
  • Path traversal : quand un attaquant peut accéder à des fichiers en dehors du répertoire prévu

Problèmes cryptographiques :

  • Utilisation d’algorithmes obsolètes (MD5, SHA1 pour les mots de passe)
  • Clés de chiffrement ou mots de passe en dur dans le code
  • Générateurs de nombres aléatoires non sécurisés

Mauvaises pratiques :

  • Utilisation de eval() ou équivalent
  • Désactivation de la vérification SSL
  • Permissions trop larges
  • Code qui ne gère pas les erreurs correctement

Installation

Semgrep s’installe en une seule commande. Choisissez la méthode qui correspond à votre environnement.

Si vous avez Python installé (version 3.8 ou supérieure), c’est la méthode la plus simple :

Terminal window
pip install semgrep

Cette commande télécharge Semgrep et toutes ses dépendances. L’installation prend généralement moins d’une minute.

Pour vérifier que tout fonctionne :

Terminal window
semgrep --version

Vous devriez voir quelque chose comme semgrep 1.145.2.

Premier scan : découvrir Semgrep

Maintenant que Semgrep est installé, lançons un premier scan pour voir comment il fonctionne.

Le mode automatique

La façon la plus simple de démarrer est d’utiliser le mode auto. Semgrep détecte automatiquement les langages présents dans votre projet et applique les règles appropriées :

Terminal window
cd /chemin/vers/mon-projet
semgrep scan --config=auto .

Que fait cette commande ?

  1. Semgrep parcourt tous les fichiers du répertoire courant (.)
  2. Il identifie les langages (Python, JavaScript, Go, etc.)
  3. Il télécharge les règles adaptées depuis le registre Semgrep
  4. Il analyse chaque fichier et affiche les problèmes trouvés

Lors du premier scan, Semgrep affiche un résumé détaillé :

┌──── ○○○ ────┐
│ Semgrep CLI │
└─────────────┘
Scanning 35 files (only git-tracked) with 327 Code rules:
CODE RULES
Language Rules Files Origin Rules
───────────────────────────── ───────────────────
<multilang> 2 35 Community 327
python 151 15
json 1 2
SUPPLY CHAIN RULES
💎 Sign in with `semgrep login` and run
`semgrep ci` to find dependency vulnerabilities and
advanced cross-file findings.
PROGRESS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00
┌──────────────┐
│ Scan Summary │
└──────────────┘
✅ Scan completed successfully.
• Findings: 0 (0 blocking)
• Rules run: 154
• Targets scanned: 35

Ce résumé indique que vous utilisez Semgrep OSS (la version open source gratuite). Les fonctionnalités Supply Chain et cross-file nécessitent un compte — nous y reviendrons en fin de guide.

Le premier scan peut prendre quelques secondes supplémentaires car Semgrep télécharge les règles. Les scans suivants seront plus rapides grâce au cache.

Comprendre les résultats

Quand Semgrep trouve un problème, il affiche un rapport détaillé. Voici un exemple réel de sortie sur un projet Python :

┌──────────────────┐
│ 1 Code Finding │
└──────────────────┘
src/utils/sitemap_utils.py
❯❱ python.lang.security.use-defused-xml.use-defused-xml
The Python documentation recommends using `defusedxml`
instead of `xml` because the native Python `xml` library
is vulnerable to XML External Entity (XXE) attacks.
These attacks can leak confidential data and "XML bombs"
can cause denial of service.
3┆ from xml.etree import ElementTree
Severity: ERROR
Details: https://semgrep.dev/r/python.lang.security...

Décortiquons ce rapport :

ÉlémentSignification
python.lang.security.use-defused-xml.use-defused-xmlIdentifiant unique de la règle qui a déclenché l’alerte
Message explicatifCe que Semgrep a trouvé et pourquoi c’est un problème
3┆Le numéro de la ligne concernée dans votre fichier
Code affichéL’extrait de code problématique
Severity: ERRORNiveau de gravité (INFO, WARNING, ERROR)
Details: ...Lien vers la documentation de la règle

Les niveaux de sévérité

Semgrep utilise trois niveaux de sévérité :

NiveauSignificationAction recommandée
ERRORProblème critique, probablement une vraie vulnérabilitéCorriger immédiatement
WARNINGProblème potentiel, à investiguerAnalyser et corriger si confirmé
INFOInformation, bonne pratique non respectéeAmélioration suggérée

Scanner avec des règles spécifiques

Le mode auto est pratique pour débuter, mais vous voudrez souvent utiliser des packs de règles spécifiques selon votre objectif.

Qu’est-ce qu’un pack de règles ?

Un pack est un ensemble de règles regroupées par thème. Semgrep fournit des packs maintenus par la communauté et l’équipe Semgrep. Les packs commencent par p/ (pour “pack”).

Les packs les plus utiles

Pour la sécurité :

Terminal window
# OWASP Top 10 : les 10 vulnérabilités web les plus courantes
semgrep scan --config=p/owasp-top-ten .
# Audit de sécurité complet : règles plus exhaustives
semgrep scan --config=p/security-audit .
# Détection de secrets (mots de passe, clés API)
semgrep scan --config=p/secrets .

Par langage :

Terminal window
# Python : sécurité + qualité de code
semgrep scan --config=p/python .
# JavaScript/TypeScript
semgrep scan --config=p/javascript .
# Go
semgrep scan --config=p/golang .
# Java
semgrep scan --config=p/java .

Pour la CI/CD :

Terminal window
# Pack optimisé pour les pipelines (rapide, peu de faux positifs)
semgrep scan --config=p/ci .

Combiner plusieurs packs

Vous pouvez appliquer plusieurs packs en même temps :

Terminal window
semgrep scan --config=p/security-audit --config=p/secrets .

Cette commande applique les règles de sécurité générales ET les règles de détection de secrets.

Le registre de règles

Semgrep dispose d’un registre public contenant plus de 2000 règles écrites par la communauté et l’équipe Semgrep.

Explorer le registre

Rendez-vous sur semgrep.dev/explore pour parcourir les règles disponibles. Vous pouvez :

  • Filtrer par langage (Python, JavaScript, Go, etc.)
  • Filtrer par catégorie (sécurité, qualité, performance)
  • Rechercher par mot-clé (sql injection, xss, etc.)
  • Voir le code source de chaque règle

Utiliser une règle spécifique

Si vous trouvez une règle intéressante, vous pouvez l’utiliser directement par son identifiant. Sur la page de la règle dans le registre, cliquez sur “Run Locally” pour obtenir la commande exacte :

Terminal window
# Utiliser une règle spécifique du registre (préfixe r/)
semgrep scan --config="r/python.lang.security.audit.dangerous-system-call" .

Écrire ses propres règles

L’une des forces de Semgrep est la facilité avec laquelle on peut écrire des règles personnalisées. Les règles sont des fichiers YAML lisibles.

Anatomie d’une règle

Voici une règle simple qui détecte l’utilisation de eval() en Python :

rules:
- id: dangerous-eval-usage
patterns:
- pattern: eval($X)
message: |
Utilisation de eval() détectée. La fonction eval() exécute du code
Python arbitraire. Si l'argument provient d'une entrée utilisateur,
un attaquant pourrait exécuter n'importe quel code sur le serveur.
Alternatives sécurisées :
- ast.literal_eval() pour parser des structures de données simples
- json.loads() pour du JSON
- Un parser dédié pour votre format de données
severity: WARNING
languages:
- python
metadata:
category: security
cwe: "CWE-95: Improper Neutralization of Directives"
references:
- https://owasp.org/www-community/attacks/Code_Injection

Explication de chaque champ :

ChampObligatoireDescription
idOuiIdentifiant unique de la règle
patternsOuiCe que Semgrep doit chercher dans le code
pattern-Le pattern à matcher (ici eval($X))
$X-Variable qui capture n’importe quel argument
messageOuiExplication affichée quand la règle matche
severityOuiINFO, WARNING ou ERROR
languagesOuiListe des langages concernés
metadataNonInformations supplémentaires (CWE, références)

Utiliser une règle personnalisée

Enregistrez votre règle dans un fichier, par exemple rules/custom.yaml, puis :

Terminal window
semgrep scan --config=rules/custom.yaml .

Vous pouvez aussi combiner règles personnalisées et packs :

Terminal window
semgrep scan --config=rules/custom.yaml --config=p/security-audit .

Exemple : détecter les injections SQL

Voici une règle plus avancée pour détecter les injections SQL en Python :

rules:
- id: sql-injection-python
patterns:
- pattern-either:
# String formatting avec %
- pattern: cursor.execute($QUERY % ...)
# String formatting avec .format()
- pattern: cursor.execute($QUERY.format(...))
# f-strings
- pattern: cursor.execute(f"...")
# Concaténation de strings
- pattern: cursor.execute($QUERY + ...)
# Exclure les requêtes paramétrées (qui sont sécurisées)
- pattern-not: cursor.execute($QUERY, ...)
- pattern-not: cursor.execute($QUERY, $PARAMS)
message: |
Possible injection SQL détectée. La requête SQL est construite par
concaténation ou formatage de strings, ce qui permet à un attaquant
d'injecter du code SQL malveillant.
❌ Vulnérable :
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
✅ Sécurisé (requête paramétrée) :
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
severity: ERROR
languages:
- python
metadata:
category: security
cwe: "CWE-89: SQL Injection"

Cette règle utilise plusieurs opérateurs de patterns :

OpérateurCe qu’il fait
pattern-eitherMatche si l’un des patterns est présent
pattern-notExclut les cas qui matchent ce pattern
patternPattern simple à matcher

Tester une règle avant de l’utiliser

Semgrep fournit un playground en ligne pour tester vos règles : semgrep.dev/playground

Vous pouvez y coller votre règle YAML et du code de test pour vérifier qu’elle détecte bien ce que vous voulez (et ne génère pas de faux positifs).

Intégration dans le pipeline CI/CD

Le vrai pouvoir de Semgrep apparaît quand il s’exécute automatiquement à chaque modification de code. Voici comment l’intégrer dans les pipelines les plus courants.

GitHub Actions

Créez le fichier .github/workflows/semgrep.yml :

name: Semgrep Security Scan
on:
# Scanner à chaque pull request
pull_request: {}
# Scanner les pushs sur main
push:
branches:
- main
jobs:
semgrep:
name: Analyse de sécurité
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep
steps:
# Récupérer le code
- name: Checkout du code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Lancer le scan
- name: Scan Semgrep
run: |
semgrep --config=p/security-audit \
--error \
--json \
-o semgrep-results.json \
.
# Sauvegarder les résultats même si le scan échoue
- name: Upload des résultats
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always()
with:
name: semgrep-results
path: semgrep-results.json

Explication des options :

  • --config=p/security-audit : utilise le pack de sécurité
  • --error : fait échouer le workflow si des problèmes sont trouvés
  • --json -o semgrep-results.json : génère un rapport JSON
  • if: always() : sauvegarde les résultats même si le scan a échoué

GitLab CI

Ajoutez ce job dans votre .gitlab-ci.yml :

semgrep:
stage: test
image: returntocorp/semgrep
script:
- semgrep --config=p/security-audit --error --json -o semgrep.json .
artifacts:
paths:
- semgrep.json
when: always
expire_in: 1 week
rules:
# Scanner les merge requests
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# Scanner la branche par défaut
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Pre-commit : scanner avant chaque commit

Pour détecter les problèmes encore plus tôt, vous pouvez configurer Semgrep comme hook pre-commit. Ainsi, le code est scanné avant d’être commité.

Créez ou modifiez .pre-commit-config.yaml :

repos:
- repo: https://github.com/returntocorp/semgrep
rev: v1.51.0
hooks:
- id: semgrep
args: ['--config', 'p/security-audit', '--error']

Puis installez le hook :

Terminal window
pip install pre-commit
pre-commit install

Désormais, chaque git commit déclenchera un scan Semgrep. Si des problèmes sont trouvés, le commit sera bloqué.

Gérer les faux positifs

Comme tout outil d’analyse statique, Semgrep peut parfois signaler du code qui n’est pas réellement vulnérable. C’est un faux positif. Voici comment les gérer.

Ignorer une occurrence spécifique

Si Semgrep signale une ligne qui est en fait sûre, vous pouvez l’ignorer avec un commentaire nosemgrep :

# L'entrée est validée en amont, cette utilisation est sûre
result = eval(validated_expression) # nosemgrep: dangerous-eval-usage

Vous pouvez aussi ignorer toutes les règles sur une ligne :

result = eval(validated_expression) # nosemgrep

Bonne pratique : ajoutez toujours un commentaire expliquant pourquoi vous ignorez l’alerte. Cela aide les futurs relecteurs à comprendre votre décision.

Exclure des fichiers ou dossiers

Certains fichiers ne devraient pas être scannés : tests, code généré, dépendances vendorisées, etc. Créez un fichier .semgrepignore à la racine du projet :

# Fichiers de tests (souvent avec du code volontairement vulnérable)
tests/
*_test.py
test_*.py
spec/
# Code généré automatiquement
generated/
*.pb.go
*.generated.ts
# Dépendances vendorisées
vendor/
node_modules/
third_party/
# Fichiers de configuration
*.config.js

Le format est similaire à .gitignore.

Exclure via la ligne de commande

Pour exclure des chemins ponctuellement sans modifier .semgrepignore :

Terminal window
semgrep scan --config=p/security-audit \
--exclude="tests/*" \
--exclude="vendor/*" \
--exclude="*.test.js" \
.

Stratégie de déploiement progressive

Activer Semgrep en mode bloquant du jour au lendemain sur un projet existant va générer beaucoup d’alertes et frustrer les équipes. Voici une approche progressive qui fonctionne.

  1. Phase 1 : Observer (1-2 semaines)

    Lancez Semgrep sans bloquer, juste pour voir l’état actuel :

    Terminal window
    semgrep scan --config=p/security-audit . > rapport-initial.txt

    Analysez les résultats. Combien d’alertes ? Combien de vrais problèmes vs faux positifs ? Cela vous donne une baseline.

  2. Phase 2 : Alerter (2-4 semaines)

    Intégrez Semgrep en CI/CD mais sans bloquer. Affichez les résultats dans les logs ou envoyez-les sur Slack :

    Terminal window
    semgrep scan --config=p/security-audit --json . | \
    jq '.results | length'
    # Résultat : 1

    L’équipe commence à voir les alertes et à s’y habituer.

  3. Phase 3 : Bloquer les critiques

    Faites échouer le pipeline uniquement sur les erreurs critiques :

    Terminal window
    semgrep scan --config=p/security-audit --severity=ERROR --error .

    Les WARNING et INFO sont toujours affichés mais ne bloquent pas.

  4. Phase 4 : Bloquer tout

    Une fois que l’équipe est à l’aise et que les faux positifs sont gérés :

    Terminal window
    semgrep scan --config=p/security-audit --error .

    Tous les nouveaux problèmes bloquent le pipeline. Les anciens problèmes sont soit corrigés, soit marqués comme ignorés avec une justification.

Formats de sortie

Semgrep peut générer ses résultats dans différents formats selon vos besoins.

Texte (défaut)

Format lisible par un humain, idéal pour le terminal :

Terminal window
semgrep scan --config=p/security-audit .

JSON

Format structuré pour traitement automatisé (scripts, dashboards) :

Terminal window
semgrep scan --config=p/security-audit --json -o results.json .

Le fichier JSON contient tous les détails : fichier, ligne, règle, message, sévérité, etc.

SARIF

Format standard pour les outils de sécurité, supporté nativement par GitHub Code Scanning et GitLab SAST :

Terminal window
semgrep scan --config=p/security-audit --sarif -o results.sarif .

Pour l’intégrer à GitHub Code Scanning :

- name: Scan Semgrep
run: semgrep scan --config=p/security-audit --sarif -o semgrep.sarif .
- name: Upload vers GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: semgrep.sarif

Les résultats apparaîtront dans l’onglet Security de votre repository GitHub.

JUnit XML

Format compatible avec les outils CI classiques (Jenkins, etc.) :

Terminal window
semgrep scan --config=p/security-audit --junit-xml -o results.xml .

Semgrep Cloud (version payante)

Tout ce que nous avons vu jusqu’ici concerne la version open source gratuite de Semgrep. Elle couvre la grande majorité des besoins.

Semgrep AppSec Platform (anciennement Semgrep App / Semgrep Cloud) est la version payante qui ajoute des fonctionnalités entreprise. Elle inclut plusieurs produits :

  • Semgrep Code : SAST avancé avec analyse inter-fichiers
  • Semgrep Supply Chain : SCA pour analyser les dépendances
  • Semgrep Secrets : détection et validation de secrets

Ce que vous avez gratuitement

La version open source inclut :

  • Le scanner CLI complet, sans limitation
  • Accès aux 2000+ règles du registre communautaire
  • Création de règles personnalisées illimitées
  • Intégration CI/CD (GitHub, GitLab, Jenkins, etc.)
  • Tous les formats de sortie (JSON, SARIF, JUnit)
  • Support communautaire (GitHub Issues, Slack)

Pour la plupart des équipes, c’est suffisant.

Ce qu’ajoute Semgrep Cloud

FonctionnalitéDescriptionUtile pour
Dashboard centraliséVue unifiée des findings de tous vos reposÉquipes avec beaucoup de projets
Gestion des findingsTriage, assignation, workflow de remédiationSuivi des corrections
Règles ProRègles exclusives plus précises et complètesMoins de faux positifs
HistoriqueTendances, métriques dans le tempsReporting direction
IntégrationsJira, Slack, webhooksWorkflow d’équipe
SSO/SAMLAuthentification entrepriseConformité
Support dédiéAide technique prioritaireGrandes équipes

Tarification (décembre 2024)

PlanPrixInclus
Community EditionGratuitOSS SAST, règles communautaires, jusqu’à 10 contributeurs
Teams - Code (SAST)$40/mois/contributeurPro Engine, règles Pro, analyse cross-file
Teams - Supply Chain (SCA)$40/mois/contributeurAnalyse des dépendances, SBOM, licences
Teams - Secrets$20/mois/contributeurDétection et validation de secrets
EnterpriseSur devisTout Teams + account manager, onboarding, roadmap

Quand passer à la version payante ?

Semgrep Cloud devient pertinent quand :

  • Vous gérez plusieurs dizaines de repositories
  • Vous avez besoin de reporting centralisé pour la direction ou l’audit
  • Vos processus de conformité exigent un historique et des preuves
  • Vous voulez réduire les faux positifs avec les règles Pro
  • Votre équipe a besoin d’un workflow de remédiation structuré

Pour une équipe de quelques développeurs sur quelques projets, la version gratuite suffit amplement.

Limites de Semgrep

Comme tout outil, Semgrep a des limites qu’il faut connaître :

Ce que Semgrep ne fait pas :

  • Analyse dynamique : Semgrep ne détecte pas les failles qui apparaissent uniquement à l’exécution (utilisez le DAST pour ça)
  • Flow analysis complexe : certaines failles qui nécessitent de suivre les données à travers de nombreuses fonctions peuvent échapper à Semgrep
  • Failles de configuration : les problèmes dans les fichiers de config serveur ou cloud ne sont pas détectés (sauf pour les fichiers IaC supportés)
  • Analyse des dépendances : Semgrep ne scanne pas les vulnérabilités dans vos dépendances (utilisez le SCA pour ça)

Couverture variable selon les langages :

Les langages les plus populaires (Python, JavaScript, Go, Java) ont beaucoup de règles. Les langages moins courants peuvent avoir une couverture plus limitée.

Nécessite une maintenance :

Les règles personnalisées doivent être maintenues quand le code évolue. Les règles du registre sont maintenues par la communauté et l’équipe Semgrep.

Pour aller plus loin

Autres guides de ce site

Ressources officielles