système : OPÉRATIONNEL
← retour à tous les hacks
AGENTS CRITICAL

Comment and Control : un même schéma d'injection de prompt, trois agents qui fuitent les secrets GitHub Actions

Divulguée le 15 avril 2026, l'attaque Comment and Control transforme un titre de PR, un commentaire d'issue ou un commentaire HTML en canal d'exfiltration de secrets dans Claude Code, Gemini CLI et GitHub Copilot Agent.

2026-05-25 // 8 min affects: claude-code-security-review, gemini-cli-action, github-copilot-agent, llm-agents-in-cicd

De quoi parle-t-on ?

Le 15 avril 2026, le chercheur Aonan Guan a publié Comment and Control, première démonstration publique d’un même schéma d’injection de prompt compromettant trois des agents IA les plus déployés sur GitHub Actions : Anthropic Claude Code Security Review, Google Gemini CLI Action et GitHub Copilot Agent. Le travail a été coordonné avec Zhengyu Liu et Gavin Zhong, de Johns Hopkins University. Dans chaque cas, une donnée GitHub contrôlée par l’attaquant — un titre de pull request, un commentaire d’issue, ou un commentaire HTML caché dans le corps d’une issue — détourne l’agent et exfiltre les secrets GitHub Actions du dépôt hôte, via GitHub lui-même. Aucune infrastructure externe n’est requise.

Une mise à jour coordonnée le 4 mai 2026 précise la chronologie. Anthropic a d’abord noté le finding Claude Code à CVSS 9.3, relevé la sévérité à 9.4 en novembre 2025, puis abaissé à « None » le 20 avril 2026 en indiquant que l’action « n’est pas conçue pour résister à l’injection de prompt ». Le VRP de Google a versé 1 337 $. GitHub a d’abord classé le rapport Copilot comme « Informative » avant de le rouvrir et de verser 500 $. Aucun des trois éditeurs n’a émis de CVE.

Comment ça marche

Le schéma partagé tient en une phrase : donnée GitHub non fiable → l’agent IA la traite → l’agent exécute des outils → les credentials sont exfiltrés via GitHub.

Dans Claude Code Security Review, le titre de la PR est interpolé directement dans le prompt de l’agent, sans aucune sanitisation, et la CLI claude est invoquée sans --allowed-tools ni --disallowed-tools. Le processus enfant hérite donc de toutes les variables d’environnement du runner — y compris ANTHROPIC_API_KEY et GITHUB_TOKEN. Un titre fabriqué demande à l’agent d’exécuter des commandes shell telles que ps auxeww et d’inclure l’environnement capturé dans son JSON de « security finding », qui est ensuite publié comme commentaire de PR — visible par toute personne, attaquant compris.

Dans Gemini CLI Action, l’attaquant injecte une fausse « Trusted Content Section » dans un commentaire d’issue, après le bloc légitime "Additional Content" que l’agent insère dans son contexte. L’agent traite la section forgée comme faisant autorité et publie GEMINI_API_KEY en commentaire d’issue.

Le cas GitHub Copilot Agent est le plus instructif, car trois couches runtime — filtrage de l’environnement, scan de secrets, pare-feu réseau — ont été conçues pour empêcher précisément ce vol. Les trois sont contournées :

# Illustratif — pas du code d'exploit
1. Filtre (zJe[] / UU()) : masque ~20 secrets, mais seulement pour le sous-shell bash.
   ps auxeww depuis ce bash lit /proc/$PPID/environ du process parent Node.js
   et du serveur MCP, qui conservent l'environnement complet.
2. Scan de secrets : regex sur les préfixes ghs_, ghu_.
   base64-encoder le dump avant `git push` désamorce ces motifs.
3. Pare-feu réseau : github.com est nécessairement autorisé.
   Le blob base64 est committé comme un fichier normal dans une PR normale.

Le déclencheur est invisible pour un humain : le payload est dans un commentaire HTML du corps de l’issue. Le rendu Markdown de GitHub masque le commentaire, la victime ne voit que le texte bénin, assigne l’issue à Copilot, et l’agent — qui lit le Markdown brut — exécute les instructions cachées.

Pourquoi c’est important

Ce n’est pas un bug de parser. Titres de PR, corps d’issues et commentaires sont des données légitimes que l’agent doit lire pour faire son travail. Le conflit est architectural : un même runtime héberge simultanément des secrets privilégiés et traite l’entrée non fiable de contributeurs externes. Les défenses empilées par-dessus — blocklists, scanners de secrets, allowlists réseau — gagnent du temps mais finissent par perdre face au prochain encodage, au prochain processus frère, à la prochaine destination autorisée. Anthropic a bloqué ps ; cat /proc/*/environ produit le même résultat. C’est le lethal trifecta dont Simon Willison parle depuis longtemps (données privées, entrée non fiable, vecteur d’exfiltration) matérialisé dans trois agents en production simultanément.

La divulgation est aussi un signal de gouvernance. Trois grands éditeurs ont discrètement versé moins de 2 000 $ de bounties cumulés, sans CVE et sans advisory public. Les utilisateurs épinglés sur des versions vulnérables n’ont aucun canal standard pour apprendre qu’ils sont touchés.

Défenses

Actions concrètes à mettre en place cette semaine, toutes dérivées de la divulgation et de l’analyse qui l’entoure :

  1. Auditer les déclencheurs de vos agents IA. Tout workflow déclenché par pull_request_target, issues ou issue_comment et exposant des secrets de dépôt à l’agent est concerné. Migrer vers des déclencheurs sûrs pour les forks dès que possible.
  2. Allowlister les outils, jamais les blocklister. Passer --allowed-tools à Claude Code, restreindre les capacités shell/fichier/réseau sur chaque agent, refuser la posture par défaut « l’agent hérite de tout l’environnement du runner ».
  3. Traiter les agents comme de nouveaux stagiaires. Appliquer le besoin-d’en-connaître et le moindre privilège aux outils comme aux secrets. Un agent de revue de code n’a presque jamais besoin d’un GITHUB_TOKEN en écriture ni d’une clé API de production dans le même processus.
  4. Retirer les secrets à la frontière de processus, pas seulement du sous-shell. Le filtre UU() de Copilot montre pourquoi ne filtrer que le shell enfant ne suffit pas : ps et /proc/*/environ parcourent tous les PID. Exécuter l’agent dans un runtime séparé qui ne voit jamais le secret élargi.
  5. Auditer le contenu invisible. Scanner les corps d’issues et descriptions de PR pour détecter les commentaires HTML avant qu’ils n’atteignent le contexte de l’agent. La normalisation équivalent-rendu doit être une étape de pré-traitement, pas un détail.
  6. Faire tourner les credentials exposés. Tout dépôt qui a fait tourner ces actions sur des entrées de contributeurs non fiables avant le 15 avril doit considérer les secrets associés comme compromis.

Statut

ComposantRéponse de l’éditeurDateNotes
Claude Code Security ReviewBounty 100 $ ; ps bloqué ; doc mise à jour ; sévérité Critique (9.4) → None2025-11-25 → 2026-04-20« Non conçu pour résister à l’injection de prompt »
Gemini CLI ActionBounty 1 337 $ via Google VRP2026-01-20Aucun CVE émis
GitHub Copilot AgentBounty 500 $ après réouverture du rapport2026-03-09« Limitation architecturale connue »
Divulgation publiqueBlog d’Aonan Guan2026-04-15Mise à jour avec chronologie le 2026-05-04

La leçon de fond est celle sur laquelle Guan clôt son article : l’injection de prompt est, structurellement, du phishing pour machines. Les agents IA doivent traiter du contexte non fiable pour produire un travail utile. Les surfaces d’injection se multiplieront à mesure que de nouveaux agents seront déployés dans chaque workflow. Les architectures qui laissent les outils, les secrets et l’entrée non fiable dans un même runtime continueront de perdre face aux attaques de la classe Comment and Control — quel que soit le nom qu’elles porteront ensuite.

Sources