Aller au contenu principal
Leçon 11 sur 20 · Outils API : Search, Files et Code Interpreter

Sandboxing et limitations de sécurité

Leçon 11 sur 20 Mis à jour le 2 novembre 2026 Développeur
Sur cette page
  1. Sandboxing et limitations de sécurité
  2. Architecture du sandbox
  3. Ce qui est disponible
  4. Ce qui est limité
  5. Sécurité des données
  6. Gérer les erreurs d’exécution
  7. Bonnes pratiques
  8. Points clés à retenir

Leçon corrigée le 2 novembre 2026 d’après la documentation d’OpenAI : l’outil Code Interpreter exige un paramètre container (ajouté à tous les exemples), le réseau du conteneur, fermé par défaut, peut désormais s’ouvrir vers une liste blanche de domaines, et les règles de vie du conteneur (mémoire, expiration, réutilisation) suivent le guide officiel. Les fichiers joints au message sont téléversés avec l’usage user_data, celui que recommande OpenAI pour les entrées du modèle. Sources : Code Interpreter · Accès réseau des conteneurs · API Containers · API Files.

Sandboxing et limitations de sécurité

Les limites du sandbox ne sont pas des défauts à contourner : ce sont les propriétés qui rendent l’exécution de code généré acceptable. Un environnement fermé au réseau, à durée de vie courte et sous plafond de ressources ne peut ni exfiltrer vos données, ni laisser traîner un état indéfiniment, ni consommer sans limite.

Les connaître à l’avance vous évite surtout de déboguer l’impossible. Les trois questions qui reviennent — pourquoi pip install échoue, pourquoi mon fichier a disparu entre deux appels, pourquoi mon traitement tombe sur un gros fichier — ont toutes leur réponse ci-dessous, et aucune n’est un bug.

Architecture du sandbox

Code Interpreter exécute le code dans un conteneur, une machine virtuelle isolée hébergée par OpenAI, aux propriétés suivantes :

  • Réseau fermé par défaut : aucune requête sortante, sauf liste blanche de domaines ouverte explicitement (voir plus bas)
  • Durée de vie courte : le conteneur expire après 20 minutes sans utilisation, et tout ce qu’il contient est alors effacé
  • Mémoire plafonnée : 1 Go par défaut, ou 4, 16 ou 64 Go à la demande (memory_limit), chaque palier ayant son tarif
from openai import OpenAI

client = OpenAI()

# Sans liste blanche, le téléchargement échouera : pas d'accès réseau
response = client.responses.create(
    model="gpt-5.6-terra",
    input="Telecharge le contenu de https://example.com avec requests",
    tools=[{"type": "code_interpreter", "container": {"type": "auto"}}]
)

# Le modèle expliquera que l'accès réseau n'est pas disponible
print(response.output_text)

Ce qui est disponible

Bibliothèques préinstallées

OpenAI ne publie pas de liste officielle des paquets du conteneur, et celle-ci évolue. Un relevé publié par un développeur sur le forum d’OpenAI en novembre 2025 en comptait 389, dont les bibliothèques attendues pour l’analyse : pandas, numpy, scipy et statsmodels pour les données, matplotlib, seaborn et plotly pour la visualisation, Pillow pour les images, sympy pour le calcul symbolique, openpyxl pour Excel. Plutôt que de le supposer, faites dresser l’inventaire par le modèle au début d’un projet :

response = client.responses.create(
    model="gpt-5.6-terra",
    input="Liste les paquets Python installés avec leur version, "
          "puis affiche la version de Python.",
    tools=[{"type": "code_interpreter", "container": {"type": "auto"}}]
)
print(response.output_text)

Les versions comptent autant que les noms : le même relevé montrait pandas 1.5.3, antérieure à pandas 2.0. Si votre traitement dépend d’une fonction récente, vérifiez qu’elle existe avant de bâtir dessus.

Système de fichiers

Le code lit et écrit des fichiers dans le conteneur. Ceux que le modèle crée sont cités dans sa réponse et se téléchargent avec les fonctions fichiers_generes et telecharger de la leçon 10 :

# Le modèle peut créer des fichiers dans le conteneur
response = client.responses.create(
    model="gpt-5.6-terra",
    input="Cree un fichier CSV avec 100 lignes de données de test "
          "(nom, âge, ville, salaire) et retourne-le.",
    tools=[{"type": "code_interpreter", "container": {"type": "auto"}}]
)

for ann in fichiers_generes(response):
    telecharger(client, ann, ann.filename)

Ce qui est limité

Accès réseau

Par défaut, le conteneur n’a aucun accès sortant : ni pip install, ni appel d’API, ni téléchargement. C’est la limite la plus structurante, et c’est voulu : un code généré ne peut rien envoyer nulle part. Ce dont votre traitement a besoin doit être présent dans le conteneur ou téléversé par vos soins — et si la donnée est en ligne, c’est souvent l’outil de recherche web qui ira la chercher.

# Sans liste blanche (cas par défaut), impossible :
# - requests.get(), urllib.request
# - socket, http.client
# - pip install (pas de téléchargement)
# - Accès a des API externes
# - Envoi d'emails

L’ouverture existe, mais elle se décide à deux niveaux. Un administrateur définit d’abord, dans le tableau de bord, la liste blanche de l’organisation ; chaque requête déclare ensuite une network_policy qui ne peut que la restreindre — une requête qui demande un domaine absent de la liste de l’organisation échoue.

response = client.responses.create(
    model="gpt-5.6-terra",
    input="Mets pandas à jour avec pip, puis affiche la version installée.",
    tools=[{
        "type": "code_interpreter",
        "container": {
            "type": "auto",
            "network_policy": {
                "type": "allowlist",
                "allowed_domains": ["pypi.org", "files.pythonhosted.org"],
            },
        },
    }],
)

Ouvrir des domaines a un prix, et OpenAI le dit sans détour : c’est une porte pour l’exfiltration de données par injection de prompt. N’autorisez que des domaines de confiance, qu’un attaquant ne peut pas utiliser pour recevoir des données — et méfiez-vous des hébergements partagés, où n’importe qui peut mettre en ligne un serveur qui enregistrera vos requêtes.

Persistance entre appels

L’absence de persistance surprend surtout quand on enchaîne les appels : le DataFrame chargé au premier n’existe plus au second. La règle exacte tient au mode auto : il crée un nouveau conteneur, sauf si le contexte du modèle contient déjà un appel Code Interpreter dont le conteneur est encore actif — il le réutilise alors. Deux appels indépendants travaillent donc chacun dans le leur, tandis qu’un appel chaîné au précédent (avec previous_response_id) retrouve le sien s’il n’a pas expiré. À l’intérieur d’un même appel, plusieurs exécutions de code partagent bien la même session.

# Premier appel : cree un fichier
response1 = client.responses.create(
    model="gpt-5.6-terra",
    input="Cree une variable x = 42 et sauvegarde-la dans un fichier",
    tools=[{"type": "code_interpreter", "container": {"type": "auto"}}]
)

# Deuxième appel, indépendant du premier : nouveau conteneur
response2 = client.responses.create(
    model="gpt-5.6-terra",
    input="Lis le fichier cree précédemment",
    tools=[{"type": "code_interpreter", "container": {"type": "auto"}}]
)
# -> Erreur : fichier introuvable

Pour conserver des résultats entre appels sans dépendre du contexte, faites-les travailler dans le même conteneur. Créez-le explicitement avec l’API des conteneurs et passez son identifiant à chaque appel : les fichiers produits par une étape restent disponibles pour la suivante. Par défaut, il expire après 20 minutes sans utilisation et ses données sont alors définitivement perdues : téléchargez ce que vous voulez garder, puis supprimez-le vous-même.

def pipeline_avec_persistance(etapes: list[str]) -> list:
    """Exécute des étapes successives dans un même conteneur."""
    conteneur = client.containers.create(name="pipeline")
    resultats = []

    for etape in etapes:
        response = client.responses.create(
            model="gpt-5.6-terra",
            input=etape,
            tools=[{"type": "code_interpreter", "container": conteneur.id}],
        )
        resultats.append(response.output_text)

    # Après avoir téléchargé les fichiers utiles (leçon 10)
    client.containers.delete(conteneur.id)
    return resultats

Ne renvoyez pas les fichiers générés comme input_file : leurs identifiants (cfile_…) désignent des fichiers du conteneur, pas de l’API Files.

Mémoire et traitements lourds

La documentation ne publie pas de durée maximale d’exécution ; la limite concrète est la mémoire du conteneur, choisie à sa création et valable pour toute sa vie. Pour un gros fichier, prenez un palier adapté et faites découper le travail. Au-delà — entraînement de modèle, calcul massif —, c’est votre propre infrastructure qu’il faut utiliser, le conteneur restant l’outil de l’analyse interactive.

# Pattern pour les traitements lourds : plus de mémoire, travail découpé
with open("transactions.csv", "rb") as f:
    fichier = client.files.create(file=f, purpose="user_data")

response = client.responses.create(
    model="gpt-5.6-terra",
    input=[{
        "role": "user",
        "content": [
            {"type": "input_text", "text": (
                "Traite ce fichier CSV de 500 000 lignes en lots de 50 000. "
                "Pour chaque lot, calcule les statistiques et accumule les résultats."
            )},
            {"type": "input_file", "file_id": fichier.id}
        ]
    }],
    tools=[{"type": "code_interpreter", "container": {"type": "auto", "memory_limit": "4g"}}],
    instructions="Si le traitement risque d'etre long, decoupe-le en etapes "
                "et affiche la progression."
)

Sécurité des données

Données sensibles

Les données copiées dans le conteneur sont effacées quand il expire ou qu’on le supprime. Ce n’est pas le cas d’un fichier téléversé par l’API Files : il y reste jusqu’à ce que vous le supprimiez, à moins de lui fixer une expiration (expires_after, entre une heure et trente jours). Et le raisonnement de conformité ne s’arrête pas là : vos données ont bien quitté votre infrastructure pour être traitées par un tiers. Pseudonymiser avant l’envoi coûte quelques lignes et réduit ce qui sort — car un identifiant client qui ne sort jamais ne peut poser aucun problème.

Une empreinte à clé (HMAC) donne des pseudonymes stables d’un envoi à l’autre, que personne ne peut relier aux valeurs d’origine sans la clé. Au sens du RGPD, le résultat reste une donnée personnelle pseudonymisée, pas anonyme : la clé doit rester chez vous.

import hashlib
import hmac
import os

import pandas as pd

CLE = os.environ["CLE_PSEUDONYMISATION"].encode()  # secret gardé hors du code


def pseudonyme(valeur) -> str:
    return hmac.new(CLE, str(valeur).encode(), hashlib.sha256).hexdigest()[:16]


def analyser_donnees_sensibles(fichier_path: str, colonnes_a_masquer: list[str]):
    """Pseudonymise les données avant envoi au Code Interpreter."""
    df = pd.read_csv(fichier_path)
    for col in colonnes_a_masquer:
        if col in df.columns:
            df[col] = df[col].map(pseudonyme)

    fichier_pseudo = "/tmp/donnees_pseudonymisees.csv"
    df.to_csv(fichier_pseudo, index=False)

    # Envoi avec expiration automatique au bout d'une heure
    with open(fichier_pseudo, "rb") as f:
        fichier = client.files.create(
            file=f,
            purpose="user_data",
            expires_after={"anchor": "created_at", "seconds": 3600},
        )

    response = client.responses.create(
        model="gpt-5.6-terra",
        input=[{
            "role": "user",
            "content": [
                {"type": "input_text", "text": "Analyse les tendances dans ces données"},
                {"type": "input_file", "file_id": fichier.id}
            ]
        }],
        tools=[{"type": "code_interpreter", "container": {"type": "auto"}}]
    )
    client.files.delete(fichier.id)  # sans attendre l'expiration
    return response.output_text

Code généré

L’isolation protège votre système, pas la justesse du résultat : le code tourne chez OpenAI, dans un conteneur jetable, et ne touche jamais vos machines. Le risque se déplace vers ce que vous faites de ses productions. Si vous récupérez le code pour l’exécuter chez vous, relisez-le comme du code tiers. Et si le conteneur a une liste blanche, gardez en tête qu’un fichier piégé peut contenir des instructions qui pousseront le modèle à envoyer des données vers ces domaines.

Gérer les erreurs d’exécution

Le code peut échouer dans le sandbox. Le modèle tente généralement de corriger :

response = client.responses.create(
    model="gpt-5.6-terra",
    input="Calcule la matrice inverse d'une matrice singuliere [[1,2],[2,4]]",
    tools=[{"type": "code_interpreter", "container": {"type": "auto"}}],
    instructions="Si le code produit une erreur, explique pourquoi "
                "et propose une alternative."
)

# Le modele execute le code, detecte l'erreur LinAlgError,
# puis explique que la matrice est singuliere et propose
# la pseudo-inverse de Moore-Penrose

Bonnes pratiques

# 1. Soyez spécifique dans vos instructions
# Mauvais :
input_vague = "Analyse ces données"

# Bon :
input_precis = ("Charge ce CSV avec pandas. "
               "Calcule la moyenne, médiane et écart-type de la colonne 'montant'. "
               "Identifie les valeurs supérieures a 3 écarts-types. "
               "Génère un boxplot.")

# 2. Demandez du code commente
instructions = "Commente chaque étape du code. Affiche les résultats intermédiaires."

# 3. Gérez les fichiers volumineux
instructions_lot = ("Si le fichier depasse 100 000 lignes, "
                   "travaille sur un échantillon représentatif de 10 000 lignes "
                   "et indique-le dans ta reponse.")

Points clés à retenir

  • Le conteneur est isolé : réseau fermé par défaut, mémoire plafonnée, expiration après 20 minutes d’inactivité
  • OpenAI ne publie pas la liste des paquets : faites-en dresser l’inventaire par le modèle
  • Une liste blanche de domaines s’ouvre à deux niveaux (organisation, puis requête) et expose à l’exfiltration : n’y mettez que des domaines de confiance
  • Pour enchaîner des étapes, réutilisez le même conteneur (client.containers.create, puis son identifiant à chaque appel), et supprimez-le à la fin
  • Pseudonymisez les données sensibles avant envoi et supprimez les fichiers téléversés après usage
  • Le modèle gère les erreurs d’exécution et tente de s’auto-corriger