flawopen.com/Teardowns/cve-2026-87913-aws-security-agent-mcp-s3-bucket-ownership
CVE-2026-87913 : fuite S3 du MCP AWS
Un bucket prévisible pouvait recevoir des archives privées dans un autre compte. Passez en 0.2.0 et vérifiez le propriétaire.[1], [2], [4]
Imaginez un coursier qui vérifie qu’un bâtiment existe à une adresse, mais pas qui en est propriétaire. Quelqu’un d’autre peut réserver l’adresse en premier et recevoir le colis. S3 doit confirmer le propriétaire attendu lors du contrôle et de l’envoi.[2], [1]
Concepts Clés et Termes
Serveur MCP- Service local proposant des outils à un assistant IA ; ils utilisent les droits du processus serveur.[3]
Bucket S3- Conteneur Amazon S3 à nom global ; le nom ne révèle pas le compte AWS propriétaire.[2], [3]
Correspondances de référentiels
- Référence CWE pour la faiblesse décrite dans ce guide : CWE-283 CWE-341
- OWASP GenAI 2025 — LLM06:2025 Agence excessive
Analyse de Cause Racine
Le serveur MCP AWS Security Agent déduit le nom du bucket d’entrée d’analyse de l’identifiant du compte AWS client et de la région : security-agent-scans-<account-id>-<region>. AWS et le mainteneur indiquent que la version vulnérable vérifiait l’existence du bucket, pas son appartenance au client. Les noms S3 sont globaux et les identifiants de compte publics. Un tiers ayant enregistré le nom prévisible en premier pouvait recevoir l’archive privée envoyée par le serveur ; elle peut contenir du code, des identifiants et l’état d’infrastructure. C’est un défaut de propriété de ressource cloud et de nom prévisible, pas une injection de prompt dans le modèle IA. Les versions 0.1.0 à 0.1.5 sont touchées ; la 0.2.0 ajoute ExpectedBucketOwner aux opérations S3 et échoue si le propriétaire diffère. La mise à niveau ne libère pas un nom déjà enregistré : vérifiez le propriétaire réel et ne relancez pas les analyses si le bucket appartient à un tiers.
Le nom du bucket ne prouve pas sa propriété
| Limite | Condition documentée | Action de l’opérateur |
|---|---|---|
| Versions concernées | awslabs.security-agent-mcp-server 0.1.0 à 0.1.5 sont concernées ; la version 0.2.0 ajoute la vérification du propriétaire. | Passez à la version 0.2.0 ou ultérieure et vérifiez la version du paquet en cours d’exécution. |
| Nom de bucket prévisible | Le nom du bucket d’analyse est dérivé de l’identifiant du compte et de la région ; un autre compte AWS peut le réserver. | Considérez un nom correspondant comme une adresse, pas comme une preuve de propriété. |
| Téléversement inter-comptes | Le serveur vulnérable pouvait accepter le bucket par son nom sans vérifier son propriétaire, puis y téléverser une archive d’analyse privée. | Vérifiez que le bucket appartient au compte attendu avant toute analyse ou tout téléversement. |
| Frontière de propriété corrigée | ExpectedBucketOwner demande à S3 de comparer le propriétaire lors de la vérification et du téléversement. | Mettez à niveau, vérifiez le propriétaire réel et arrêtez les analyses si le nom appartient à un tiers ; la mise à niveau ne transfère pas le bucket. |
Déroulement de l'Attaque Étape par Étape
Code Source : Vulnérable vs Sécurisé
Le code est schématique, pas une copie littérale. L’existence ne suffit pas : S3 doit comparer le compte propriétaire attendu lors du contrôle et de l’écriture. Obtenez ce compte depuis l’identité AWS authentifiée et interrompez l’opération en cas d’écart. Après mise à niveau, vérifiez séparément le propriétaire, car elle ne transfère ni ne libère un nom déjà enregistré. AWS documente ExpectedBucketOwner pour HeadBucket et PutObject : en cas de différence, la requête échoue avec un 403. Utilisez ce contrôle en échec fermé, mais examinez les erreurs d’accès refusé par une voie autorisée de vérification de propriété avant de conclure que le bucket appartient à un tiers.[2], [8], [9]
Extrait source: Exemple AWS SDK dérivé de l’avis ; il ne s’agit pas d’un diff littéral du code source.
# Forme vulnérable simplifiée : le nom est vérifié, mais pas son propriétaire.
s3.head_bucket(Bucket=bucket_name)
s3.put_object(
Bucket=bucket_name,
Key=object_key,
Body=archive_bytes,
)
# Associez chaque opération au compte censé posséder le bucket.
expected_owner = sts.get_caller_identity()["Account"]
s3.head_bucket(
Bucket=bucket_name,
ExpectedBucketOwner=expected_owner,
)
s3.put_object(
Bucket=bucket_name,
Key=object_key,
Body=archive_bytes,
ExpectedBucketOwner=expected_owner,
)
Liste de Contrôle de Sécurité pour l'Ingénierie
- ✓Passez en 0.2.0 ou ultérieur et vérifiez la version exécutée, y compris plugins, images CI et forks.[2], [4]
- ✓Avant le scan, confirmez que le bucket dérivé appartient au compte AWS attendu ; résoudre le nom ne prouve rien.[1], [2]
- ✓Fournissez le compte attendu via
ExpectedBucketOwnerà chaque opération S3, y compris à l’envoi.[8], [9] - ✓Échouez en cas d’écart. Si un tiers possède le nom, suspendez les scans et contactez AWS.[1]
- ✓Si possible, créez le bucket dans le compte client avant usage et appliquez le moindre privilège et le chiffrement.[3], [1]
- ✓Examinez les scans des versions touchées et renouvelez les identifiants si les archives pouvaient contenir des secrets.[2], [1]
Sources
- AWS Security Bulletin 2026-105-AWS — CVE-2026-87913
- Maintainer GHSA-3jxw-vj8m-8x77
- AWS Security Agent IDE integration and scan bucket workflow
- awslabs.security-agent-mcp-server 0.2.0 release
- NVD — CVE-2026-87913
- MITRE CWE-283 — Unverified Ownership
- MITRE CWE-341 — Predictable from Observable State
- Boto3 HeadBucket — ExpectedBucketOwner
- Boto3 PutObject — ExpectedBucketOwner
- Vulnérabilité liée dans le même paquet (CVE distinct) : injection d’arguments Git dans AWS MCP, CVE-2026-97662