Un utilisateur accède aux ressources d'un niveau de privilège supérieur en manipulant les paramètres de contrôle d'accès dans la requête.
TL;DR
L'escalade verticale de privilèges via IDOR survient quand un utilisateur à un niveau de privilège inférieur accède à des endpoints, fonctions ou données restreints aux utilisateurs d'un niveau de privilège supérieur — administrateurs, gestionnaires, opérateurs ou comptes de service internes. L'attaque franchit une frontière de rôle : l'attaquant n'accède pas simplement aux données d'un pair (IDOR horizontal) mais invoque des capacités ou accède à des objets que le modèle d'autorisation réserve explicitement aux rôles élevés.
Dans le contexte de la sécurité API, ce sous-type est classifié comme BFLA — Broken Function Level Authorization — et occupe la position API5:2023 de l'OWASP API Security Top 10 (CWE-285 : Autorisation incorrecte). La cause racine est identique à l'IDOR horizontal : l'authentification confirme l'identité mais l'autorisation n'impose pas la contrainte de rôle au niveau de la couche API. Les contrôles admin sont implémentés dans l'UI (l'élément de menu est caché), mais les routes API sous-jacentes manquent de middleware d'enforcement de rôle.
La plage CVSS pour l'escalade verticale est systématiquement plus haute que l'IDOR horizontal : 7,5–9,1. Parce que les endpoints admin exposent souvent la gestion des utilisateurs, la configuration système, les données financières et les contrôles d'infrastructure, une escalade verticale réussie aboutit typiquement à une compromission à l'échelle du système plutôt qu'aux données d'un seul utilisateur. CVE-2025-27507 dans la plateforme d'identité ZITADEL — CVSS 9,0, Critique — démontre l'endpoint : un utilisateur normal appelant un endpoint admin de configuration LDAP a atteint la prise de contrôle totale de compte pour chaque utilisateur LDAP de l'instance entière.
Trois vecteurs d'attaque distincts produisent l'escalade verticale de privilèges :
Le pattern le plus courant : les routes API admin existent et sont appelables par des utilisateurs normaux authentifiés car la vérification de rôle a été implémentée dans l'UI mais pas dans le middleware API.
GET /api/admin/utilisateurs HTTP/1.1
Host: cible.com
Authorization: Bearer <token_utilisateur_normal>Attendu : 403 Forbidden. Si le serveur retourne 200 OK avec une liste de tous les utilisateurs, l'IDOR vertical est confirmé. Les endpoints admin protégés uniquement par la visibilité de l'UI sont systématiquement découverts via fuzzing de liste de mots ou revue de documentation API.
Plusieurs frameworks implémentent l'override de méthode HTTP pour la compatibilité client legacy. Une requête POST avec le bon en-tête est traitée comme DELETE, PUT ou PATCH — et la vérification d'autorisation s'applique à la méthode déclarée, pas à la méthode effective :
POST /api/utilisateurs/1338 HTTP/1.1
Host: cible.com
Authorization: Bearer <token_utilisateur_normal>
X-HTTP-Method-Override: DELETEEn-têtes d'override connus, tous devant être testés :
X-HTTP-Method-Override # Rails, Django REST Framework, Spring
X-HTTP-Method # ASP.NET, Express plus ancien
X-Method-Override # Laravel, middleware personnalisé
X-Original-Method # Proxy Nginx / Java EE
_method # Paramètre de requête — Rails, Rack : POST /users/1?_method=DELETELes APIs versionnées ajoutent fréquemment un middleware d'autorisation aux versions plus récentes tandis que les versions plus anciennes restent déployées pour la compatibilité ascendante. L'endpoint v1 peut gérer la même logique métier avec le contrôleur v2 mais sans la couche d'autorisation ajoutée ultérieurement :
GET /api/v2/admin/utilisateurs → 403 Forbidden (middleware d'autorisation présent)
GET /api/v1/admin/utilisateurs → 200 OK (route legacy manque le middleware)| Variante | Technique | Impact |
|---|---|---|
| Endpoint admin direct | Appeler /admin/* avec un token utilisateur normal | Gestion des utilisateurs, configuration système |
| Override de méthode | POST + X-HTTP-Method-Override: DELETE | Opérations destructives sur n'importe quelle ressource |
| Rétrogradation de version | Gap de middleware /api/v1/ vs /api/v2/ | Contournement de fonction admin |
| Injection de paramètre de rôle | PATCH /users/me avec {"role": "admin"} | Escalade de privilèges permanente |
| Référence d'objet admin | GET rapport admin ID découvert via recon | Données internes sensibles |
| Accès niveau fonction | Invoquer des actions admin (bannir utilisateur, réinitialiser mot de passe) | Prise de contrôle de compte, destruction de données |
CVE-2025-27507 — Plateforme d'identité ZITADEL (CVSS 9,0, Critique, 2025) — Découvert par Amit Laish (GE Vernova). L'Admin API de ZITADEL exposait 12 endpoints HTTP — incluant /idps/ldap et /idps/ldap/{id} — qui imposaient des permissions IAM au niveau organisation au lieu des permissions requises au niveau système. Un mauvais scope dans les définitions de service gRPC signifiait que des utilisateurs non-admin authentifiés pouvaient appeler ces endpoints avec leur token bearer standard. La chaîne d'attaque : appeler l'endpoint de configuration LDAP → rediriger l'authentification LDAP vers un serveur malveillant → intercepter les credentials LDAP à la prochaine connexion → atteindre la prise de contrôle totale pour tous les utilisateurs LDAP authentifiés sur l'instance. Affectait huit branches de versions à travers ZITADEL 2.x. Advisory : GHSA-f3gh-529w-v32x.
HackerOne #415081 — PayPal (10 500 $, IDOR Vertical) — IDOR sur l'API de gestion des utilisateurs business PayPal /businessmanage/users/api/v1/users permettait la manipulation de paramètre pour accorder des droits de création de compte secondaire sur des comptes business victimes. Un utilisateur PayPal authentifié normal effectuait une opération administrative — ajouter un utilisateur secondaire à un autre compte — restreinte au propriétaire du compte. La prime reflète l'impact business : prise de contrôle de compte sur des comptes business PayPal.
CVE-2024-7297 — Escalade verticale par Mass Assignment Langflow (CVSS 8,8, juillet 2024) — Les versions Langflow antérieures à 1.0.13 acceptaient {"is_superuser": true} dans une requête PATCH /api/v1/users/<USER_ID> de n'importe quel utilisateur authentifié. Le serveur appliquait le champ sans validation, accordant immédiatement un accès super-admin à tous les flux, credentials et infrastructure. Découvert par Tenable Research (TRA-2024-26).
CVE-2026-29056 — Invitation utilisateur Kanboard (Élevé) — La méthode UserInviteController::register() passait tous les paramètres POST directement à UserModel::create() sans filtrer le champ role. Un destinataire d'invitation email pouvait s'inscrire avec role=app-admin via le flux d'inscription par invitation. Le contrôleur de paramètres de compte standard filtrait correctement les champs — seul le chemin d'invitation était vulnérable, démontrant le pattern d'inconsistance entre chemins de code qui crée l'IDOR vertical.
Construire une matrice de privilèges pour l'application, puis tester chaque combinaison systématiquement :
| Endpoint | Non authentifié | Utilisateur Normal | Admin | Attendu |
|---|---|---|---|---|
GET /api/utilisateurs/moi | 401 | 200 | 200 | Les deux rôles OK |
GET /api/admin/utilisateurs | 401 | 403 | 200 | Normal doit être bloqué |
DELETE /api/utilisateurs/1338 | 401 | 403 | 200 | Normal doit être bloqué |
POST /api/admin/reinitialiser-mdp | 401 | 403 | 200 | Normal doit être bloqué |
GET /api/rapports/financier | 401 | 403 | 200 | Normal doit être bloqué |
Toute cellule dans la colonne "Utilisateur Normal" qui retourne 200 quand le résultat attendu est 403 est un BFLA confirmé.
# Découvrir les endpoints admin via liste de mots
ffuf -u https://cible.com/api/FUZZ \
-w /usr/share/wordlists/seclists/Discovery/Web-Content/api-endpoints.txt \
-H "Authorization: Bearer $TOKEN_UTILISATEUR_NORMAL" \
-mc 200 -fs 0
# Tester l'override de méthode HTTP sur les endpoints découverts
curl -X POST https://cible.com/api/utilisateurs/1338 \
-H "Authorization: Bearer $TOKEN_UTILISATEUR_NORMAL" \
-H "X-HTTP-Method-Override: DELETE" -v
# Balayage de rétrogradation de version API
for version in v1 v2 v3 v4; do
echo "Test /api/$version/admin/utilisateurs :"
curl -s -H "Authorization: Bearer $TOKEN_UTILISATEUR_NORMAL" \
"https://cible.com/api/$version/admin/utilisateurs" | head -c 200
doneBreachVex teste l'IDOR vertical en sondant les URLs correspondant aux patterns admin (motifs tels que admin, manage, settings, internal, backoffice, system, config, moderation, staff, superuser) avec un token utilisateur normal, avec un repli sur une liste de chemins admin sélectionnée quand le recon ne trouve aucun endpoint admin. Les faux positifs sont supprimés par une garde sur les assets statiques qui bloque les fichiers .html/.css/.js, une barrière soft-404 qui élimine les pages d'erreur personnalisées retournées en HTTP 200, et une exigence de marqueur de contenu admin (admin, dashboard, user management) sur les sondes de liste de mots.
BreachVex sonde aussi PUT/DELETE/PATCH sur les endpoints API en GET uniquement, en utilisant OPTIONS pour découvrir d'abord les méthodes déclarées.
Le contrôle d'accès dans le frontend n'est pas du contrôle d'accès. Cacher un élément de menu admin, désactiver un bouton ou griser un élément de l'UI n'a aucune valeur sécuritaire — n'importe quel client peut émettre des requêtes HTTP brutes. La seule frontière de sécurité est la couche API. Chaque endpoint admin doit imposer des vérifications de rôle dans le middleware côté serveur, indépendamment de ce que n'importe quelle UI client présente.
# FastAPI — décorateur d'enforcement de rôle
from functools import wraps
from fastapi import HTTPException, Depends
def exiger_admin(user: User = Depends(get_current_user)):
if user.role != "admin":
raise HTTPException(status_code=403, detail="Accès admin requis")
return user
# Appliqué à chaque route admin — ne peut pas être omis à la définition de route
@router.get("/api/admin/utilisateurs")
async def lister_tous_utilisateurs(admin: User = Depends(exiger_admin)):
return await db.users.find_all()
@router.delete("/api/admin/utilisateurs/{user_id}")
async def supprimer_utilisateur(user_id: int, admin: User = Depends(exiger_admin)):
await db.users.delete(id=user_id)// Express — middleware de rôle appliqué au niveau routeur
const adminRouter = express.Router();
// Un seul middleware appliqué à toutes les routes de ce routeur
adminRouter.use((req, res, next) => {
if (!req.user || req.user.role !== 'admin') {
return res.status(403).json({ erreur: 'Interdit' });
}
next();
});
adminRouter.get('/utilisateurs', handlerListerTousUtilisateurs);
adminRouter.delete('/utilisateurs/:id', handlerSupprimerUtilisateur);
// Monté avec chemin restreint — chaque route sous /api/admin est protégée
app.use('/api/admin', authentifier, adminRouter);# Django REST Framework — désactiver l'override de méthode globalement
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [...],
# Ne pas inclure le middleware d'override de méthode sauf si explicitement requis
}
# Si l'override de méthode est nécessaire pour des clients legacy spécifiques, restreindre par route :
# Appliquer X-HTTP-Method-Override uniquement aux endpoints qui en ont légitimement besoin# FastAPI — dépendance d'autorisation partagée appliquée à toutes les versions
admin_requis = Depends(exiger_admin)
# Appliquer la même dépendance aux routes admin v1 et v2
@router_v1.get("/admin/utilisateurs", dependencies=[admin_requis])
@router_v2.get("/admin/utilisateurs", dependencies=[admin_requis])
async def lister_utilisateurs():
return await db.users.find_all()
# Les deux versions imposent une autorisation identiqueL'escalade verticale de privilèges via IDOR survient quand un utilisateur normal accède à des endpoints, fonctions ou données restreints aux rôles de niveau supérieur — admin, gestionnaire, opérateur — en référençant directement des objets admin ou en appelant des fonctions de niveau admin sans le rôle approprié. Contrairement à l'escalade horizontale (accès entre pairs), l'escalade verticale implique un franchissement de frontière de rôle.
BFLA (Broken Function Level Authorization) est OWASP API5:2023 — il survient quand un utilisateur invoque une fonction ou méthode HTTP qu'il n'a pas le privilège d'appeler. BOLA (API1:2023) concerne l'accès à l'objet d'un pair. BFLA est vertical : l'attaquant appelle DELETE /admin/users avec un token utilisateur normal. BOLA est horizontal : l'attaquant appelle GET /api/commandes/{id_pair} avec son propre token.
CVE-2025-27507 (CVSS 9,0) dans la plateforme d'identité ZITADEL permettait à des utilisateurs non-admin authentifiés d'appeler 12 endpoints gRPC de l'Admin API — incluant la modification de la configuration LDAP — en raison d'un mauvais scope de permissions IAM. Les attaquants redirigeaient l'authentification LDAP vers un serveur malveillant, interceptant les credentials et atteignant la prise de contrôle totale de compte pour tous les utilisateurs LDAP de l'instance.
Les en-têtes d'override de méthode HTTP (X-HTTP-Method-Override, X-HTTP-Method, paramètre _method) permettent aux clients de spécifier une méthode HTTP alternative. Rails, Django REST Framework, Spring et Express implémentent tous cela pour la compatibilité client legacy. Si le serveur traite un POST avec X-HTTP-Method-Override: DELETE comme un DELETE, un utilisateur normal peut effectuer des opérations destructives qu'il serait bloqué à faire directement.
Une API versionnée peut ajouter un middleware d'autorisation en v2 tandis que la v1 reste accessible sans ce middleware. Un attaquant obtenant 403 sur GET /api/v2/admin/users peut obtenir 200 sur GET /api/v1/admin/users. Les deux versions atteignent les mêmes handlers sous-jacents mais seule la v2 dispose de la couche d'autorisation. C'est un pattern courant dans le code legacy.
Le rapport HackerOne #415081 sur le programme PayPal impliquait un IDOR sur l'API de gestion des utilisateurs business. Il permettait à des utilisateurs normaux d'effectuer des actions administratives — ajouter des utilisateurs secondaires à d'autres comptes — en manipulant des identifiants dans le corps de la requête. Prime : 10 500 $ pour l'escalade de privilèges via référence directe à un objet.
Chaque endpoint admin doit imposer des vérifications de rôle au niveau de la couche API — pas de la couche UI. Le middleware doit vérifier que le rôle de session est 'admin' ou équivalent avant qu'un handler s'exécute. Défense en profondeur : liste d'autorisation d'IP au niveau réseau pour les routes admin, sous-domaine API admin séparé avec CSP plus stricte, et journalisation d'audit pour toutes les actions admin.
Une matrice de privilèges documente quels rôles peuvent appeler quels endpoints et méthodes. Les tests BFLA exécutent chaque combinaison rôle/endpoint et valident les réponses contre la matrice. Sans la matrice, la couverture est incomplète — un testeur pourrait confirmer que les utilisateurs normaux ne peuvent pas lister les utilisateurs mais rater qu'ils peuvent les supprimer.