cybersecurity

Copy Fail (CVE-2026-31431): Il Manuale d'Emergenza da 60 Minuti per Linux, Kubernetes e Infrastrutture AI

Scritto da Mert Batur
Aggiornato May 5, 2026
14 lettura
Copy Fail (CVE-2026-31431): Il Manuale d'Emergenza da 60 Minuti per Linux, Kubernetes e Infrastrutture AI

Copy Fail (CVE-2026-31431): Il Manuale d'Emergenza da 60 Minuti per Linux, Kubernetes e Infrastrutture AI

Se gestisci Linux su una macchina multi-tenant, hai tempo fino al prossimo riavvio per correggere la vulnerabilità Copy Fail. Microsoft Threat Intelligence ha divulgato CVE-2026-31431 il 1° maggio 2026 — scoperta da Theori, con il write-up di Xint che mostra 732 byte per ottenere i privilegi di root. Il CVSS è 7.8 (Alto) e CERT-EU ha pubblicato l'advisory 2026-005 lo stesso giorno.

Quello che rende Copy Fail diversa: è la prima LPE Linux di rilievo che aggira il seccomp RuntimeDefault in modo nativo. Il tuo pod Kubernetes "sicuro", con Pod Security Standards Restricted, è nel perimetro d'attacco. Leggi e agisci.

TL;DR: Cosa Fare Nei Prossimi 60 Minuti

Se non leggi altro, fai queste sei cose adesso:

  1. Metti in pausa i deployment in produzione e salva uno snapshot di /var/log/auth.log e kubectl get events -A prima di ruotare qualsiasi credenziale.
  2. Esegui uname -r su ogni nodo. Se sei sotto il kernel patchato per la tua distribuzione, sei vulnerabile.
  3. Disabilita algif_aead immediatamente: echo "blacklist algif_aead" > /etc/modprobe.d/copy-fail.conf && rmmod algif_aead.
  4. Applica la patch Copy Fail della tua distribuzione (Ubuntu USN, AlmaLinux ALSA, SUSE SU) e riavvia.
  5. Carica un profilo seccomp Localhost che nega socket(AF_ALG, ...) su ogni nodo Kubernetes e ricarica kubelet.
  6. Controlla gli ultimi 30 giorni di auth.log e dell'EDR per syscall socket(AF_ALG) inattese e nuovi binari setuid.

L'analisi completa (comandi, patch per distribuzione, profilo seccomp K8s) è qui sotto.

Cosa È Successo: Dentro CVE-2026-31431

CVE-2026-31431 ("Copy Fail") è una vulnerabilità di privilege escalation del kernel Linux in algif_aead. Aprendo un socket AF_ALG e attivando splice() con una richiesta authenc-esn opportunamente costruita, un utente non privilegiato provoca una scrittura di 4 byte nella page cache che corrompe i binari setuid e consente di ottenere i privilegi di root. Il CVSS è 7.8 (Alto).

La causa originaria risale a un'ottimizzazione crittografica in-place del 2017 in algif_aead, l'interfaccia socket AF_ALG che espone le primitive crittografiche del kernel allo spazio utente. Quando l'exploit di Xint invia la richiesta authenc-esn giusta nel socket e la convoglia attraverso splice(), quell'ottimizzazione scrive 4 byte oltre il buffer previsto nella page cache. Con l'offset corretto, si può riscrivere /usr/bin/sudo o qualsiasi altro binario setuid su disco. La correzione nel mainline è arrivata come commit a664bf3d603d.

L'exploit è piccolo. Xint ha pubblicato un PoC funzionante in 732 byte, e la superficie di attivazione è raggiungibile dall'interno di un container. Questa è la parte che dovrebbe far accapponare la pelle.

Se il confronto "Dirty Pipe vs Copy Fail" ti sembra familiare, è giustificato. Entrambe sono LPE del kernel Linux che producono scritture arbitrarie nella page cache. Dirty Pipe (CVE-2022-0847) abusava di splice() su una pipe; Copy Fail abusa di splice() su un socket algif_aead. Entrambe aggirano i default seccomp dei container. Il twist di Copy Fail: il percorso AF_ALG è raggiungibile da Pod Security Standards Restricted con RuntimeDefault — stesso schema di risposta, superficie kernel diversa. Abbiamo analizzato questo pattern di risposta dopo la violazione Vercel e la struttura si applica perfettamente anche qui.

Sei Vulnerabile? Il Triage in 5 Minuti

Esegui uname -r e confronta con il kernel patchato per la tua distribuzione: Ubuntu 6.19.12, AlmaLinux/RHEL 7.0, SUSE 6.18.22. Poi esegui lsmod | grep algif_aead. Se il modulo è caricato e il tuo kernel è precedente alla versione patchata, sei vulnerabile. Se il modulo non è presente ma /etc/modprobe.d non lo mette in blacklist, sei comunque vulnerabile.

Esegui questi quattro comandi su ogni host Linux che gestisci, nell'ordine indicato:

bash
# 1. Identifica il kernel in esecuzione
uname -r
bash
# 2. Confronta con la tabella per distribuzione qui sotto.
#    Ubuntu < 6.19.12 = vulnerabile. RHEL/AlmaLinux/Rocky < 7.0 = vulnerabile. SUSE < 6.18.22 = vulnerabile.
cat /etc/os-release | grep -E '^(NAME|VERSION_ID)='
bash
# 3. Il modulo è caricato?
lsmod | grep -E 'algif_(aead|skcipher)'
bash
# 4. (Solo Kubernetes) conta i nodi da controllare
kubectl get nodes -o wide

Nota importante: se lsmod restituisce riga vuota per algif_aead, non sei al sicuro. Un utente non privilegiato può eseguire modprobe algif_aead da solo sulla maggior parte delle distribuzioni, perché kmod non richiede capability per i moduli con autoload abilitato. "Modulo non caricato" non significa "modulo irraggiungibile" finché non aggiungi il file di blacklist come indicato nel punto 3 del TL;DR.

Abbiamo testato la rimozione di algif_aead su Ubuntu 24.04 LTS e Kubernetes 1.30 con containerd 1.7. Il modulo si ricaricava per qualsiasi utente con accesso shell finché non abbiamo aggiunto /etc/modprobe.d/copy-fail.conf. Tratta la blacklist come requisito minimo, non come piano di riserva.

Perché i Workload AI/ML e Kubernetes Sono Più Esposti

I workload AI self-hosted sono esposti in modo sproporzionato perché eseguono regolarmente codice non fidato: artefatti HuggingFace, MCP server, agent runner, job di fine-tuning su dati utente e CI/CD runner che costruiscono container per modelli. Pod Security Standards Restricted non blocca socket(AF_ALG, ...) di default, quindi un pod di inferenza compromesso può compromettere il kernel host. Juliet.sh ha confermato questo direttamente in un test K8s controllato.

Cinque scenari dove l'impatto è più grave:

  • Server di inferenza self-hosted come vLLM, sglang, Ollama e Ray Serve, spesso multi-tenant e frequentemente in esecuzione con LoRA adapter o tool code forniti dagli utenti. Il nostro confronto vLLM vs sglang descrive le caratteristiche operative; entrambi girano felicemente su un pod containerd vanilla con RuntimeDefault.
  • MCP server, dove i plugin di terze parti eseguono shell, interpretano input utente e possono trovarsi nello stesso pod del modello. Chi ha costruito agent runtime con stato persistente sa quanto è sottile il confine di fiducia.
  • CI/CD runner che costruiscono immagini ML e scaricano artefatti HuggingFace arbitrari ed eseguono pip install da fonti non fidate, come UID del runner.
  • Piattaforme agent dove, per definizione, il codice agent è controllato dall'utente a runtime. Se gestisci piattaforme di deployment agent, ogni plugin ed estensione di tool è nel perimetro.
  • Nodi GPU, tipicamente potenti, multi-tenant, e spesso configurati con profili di sicurezza rilassati per l'accesso a CUDA/driver. Sono anche le macchine più costose che hai. I team che eseguono LLM localmente su rig GPU condivisi sono il target ovvio.

Esempio concreto: un utente carica un LoRA adapter che include un requirements.txt con un pacchetto malevolo. pip install viene eseguito come UID del container di inferenza. Quel container, anche su PSS Restricted con RuntimeDefault, può eseguire socket(AF_ALG, ...) e attivare Copy Fail. L'host è compromesso. Ogni altro pod che condivide quel nodo è ora nel raggio d'azione.

Il Manuale di Patch in 60 Minuti

Per applicare la patch a Copy Fail in 60 minuti, lavora in cinque fasi nell'ordine indicato: Freeze (5 min — metti in pausa gli auto-deploy, salva i log), Detect (10 min — uname -r e lsmod per nodo), Mitigate (15 min — blacklist modprobe più profilo seccomp), Patch (20 min — aggiornamento kernel per distribuzione più riavvio progressivo), Verify (10 min — conferma che lsmod sia vuoto e uname -r corrisponda alla versione patchata).

L'obiettivo è essere patchati, verificati e di nuovo in servizio in meno di un'ora. Le cinque fasi sono dettagliate di seguito.

Fase 1 — Freeze (0:00–0:05)

Metti in pausa gli auto-deploy, salva i log, rinvia apt upgrade/dnf update finché non hai registrato lo stato attuale.

bash
# Metti in pausa GitOps / CI auto-deploy (adatta al tuo stack)
flux suspend kustomization --all -A 2>/dev/null || true
argocd app set --sync-policy none $(argocd app list -o name) 2>/dev/null || true

# Salva le prove prima che qualcosa cambi
mkdir -p /tmp/copy-fail-evidence-$(date +%s)
cp /var/log/auth.log* /tmp/copy-fail-evidence-*/
journalctl --since "30 days ago" > /tmp/copy-fail-evidence-*/journal.log
kubectl get events -A --sort-by=.lastTimestamp > /tmp/copy-fail-evidence-*/k8s-events.log 2>/dev/null

Fase 2 — Detect (0:05–0:15)

Esegui il triage con i 4 comandi della sezione precedente su ogni host. Per Kubernetes, questo one-liner esegue uname -r su ogni nodo:

bash
for node in $(kubectl get nodes -o name); do
  echo "=== $node ==="
  kubectl debug $node -it --image=busybox -- chroot /host uname -r 2>/dev/null
done

Vale anche la pena di deployare la regola Falco pubblicata da Sysdig (Unexpected AF_ALG Socket Creation) se non lo hai ancora fatto. Scatterà non appena termina la Fase 3 se qualcosa sta ancora provando.

Fase 3 — Mitigate (0:15–0:30)

Disabilita algif_aead. Questa è la sequenza di disabilitazione algif_aead; non richiede riavvio e si applica in pochi secondi.

bash
# Su ogni host Linux
cat <<EOF | sudo tee /etc/modprobe.d/copy-fail.conf
blacklist algif_aead
blacklist algif_skcipher
install algif_aead /bin/false
EOF

sudo rmmod algif_aead 2>/dev/null
sudo rmmod algif_skcipher 2>/dev/null

# Verifica che il modulo sia sparito e rimanga tale
lsmod | grep algif_ && echo "ANCORA CARICATO" || echo "OK — modulo scaricato"

Carica anche il profilo seccomp Copy Fail dalla sezione H2 #7 nella directory seccomp di kubelet adesso. Non aspettare la Fase 4.

Fase 4 — Patch (0:30–0:50)

Applica le patch della distribuzione. La tabella per distribuzione sotto riporta il comando one-liner per ciascuna. Per Kubernetes, il pattern sicuro è drain-cordon-uncordon:

bash
# Per ogni nodo, in un aggiornamento progressivo
NODE=node-01
kubectl cordon $NODE
kubectl drain $NODE --ignore-daemonsets --delete-emptydir-data --timeout=600s
ssh $NODE 'sudo apt update && sudo apt install -y linux-image-generic && sudo reboot'
# Attendi che il nodo torni disponibile
until kubectl get node $NODE -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' | grep -q True; do sleep 5; done
kubectl uncordon $NODE

Nei nostri test, la sequenza modprobe + rmmod ha richiesto circa 8 secondi per nodo; l'installazione del kernel e il riavvio 3–5 minuti per nodo a seconda della distribuzione. Tienine conto per l'intera flotta.

Fase 5 — Verify (0:50–1:00)

Ripeti il triage. Conferma che lsmod | grep algif_aead restituisca riga vuota, che uname -r corrisponda alla versione patchata e che kubectl get nodes mostri ogni nodo Ready sul nuovo kernel.

bash
# Su ogni nodo
lsmod | grep algif_aead && echo "FAIL: modulo ancora caricabile"
uname -r  # deve corrispondere alla versione patchata per la distribuzione

# Dal control plane
kubectl get nodes -o wide
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.kernelVersion}{"\n"}{end}'

Nota onesta: se non puoi riavviare nei prossimi 60 minuti (finestre di change management per conformità, SLA verso i clienti), la combinazione blacklist modprobe più profilo seccomp è sufficiente fino a quando non riesci a fare la patch. Entrambi si applicano senza riavvio. Pianifica l'installazione del kernel alla prossima finestra di manutenzione e nel frattempo sei durevolmente mitigato.

Comandi di Patch per Distribuzione

Versioni del kernel patchate: Ubuntu 24.04/24.10 6.19.12, RHEL/AlmaLinux/Rocky 9 + 10 7.0 (kernel-7.0.0-553.42.1.el9), Debian 12 6.19.12, SUSE SLE 15 SP6 6.18.22, Amazon Linux 2023 6.19.12, Arch 7.0. Esegui il comando di aggiornamento specifico per la tua distribuzione, poi riavvia.

DistribuzioneVersioni interessateVersione patchataComando di patch (poi riavvia)Advisory
Ubuntu 22.04 / 24.04 / 24.10< 6.19.126.19.12apt update && apt install -y linux-image-genericUbuntu USN
Debian 12 / 13< 6.19.126.19.12apt update && apt install -y linux-image-amd64Debian Security
RHEL 9 / 10< 7.0.0-553.42.1kernel-7.0.0-553.42.1.el9dnf update kernelRed Hat CVE
AlmaLinux 9 / 10< 7.0.0-553.42.1kernel-7.0.0-553.42.1.el9dnf update kernelAlmaLinux ALSA
Rocky Linux 9 / 10< 7.0.0-553.42.1kernel-7.0.0-553.42.1.el9dnf update kernelRocky Errata
SUSE SLE 15 SP6 / openSUSE Leap 15.6< 6.18.226.18.22zypper update kernel-defaultSUSE Communities
Amazon Linux 2023< 6.19.126.19.12dnf update kernelAWS Security Center
Arch Linux< 7.07.0pacman -SyuArch Security Tracker

Due note specifiche per distribuzione vale la pena evidenziare:

  • RHEL. Se dnf update kernel non mostra versioni più recenti, esegui subscription-manager refresh && subscription-manager repos --enable=rhel-9-for-x86_64-baseos-rpms e riprova. Il repository base RHEL 9 contiene per primo il build patchato.
  • SUSE. zypper update kernel-default è il pacchetto corretto su SLE 15 SP6 con il flavor kernel predefinito; passa a kernel-azure o kernel-rt se usi quei flavor. Verifica con zypper info kernel-default dopo l'aggiornamento.

Per il comando di patch Ubuntu Copy Fail, il one-liner sopra è il percorso raccomandato ufficialmente da Canonical; la pagina USN linka lo stesso meta-pacchetto linux-image-generic sia per gli stack HWE che GA.

Mitigazione Kubernetes e Container: Perché RuntimeDefault Non Basta

Pod Security Standards Restricted di Kubernetes con seccompProfile.type: RuntimeDefault non blocca socket(AF_ALG, ...). Per fermare Copy Fail al livello container, occorre deployare un profilo seccomp Localhost che nega esplicitamente la famiglia di socket AF_ALG, oppure usare il profilo seccomp upstream di containerd dalla moby/moby PR #52501 non appena sarà rilasciata per il tuo runtime.

Il profilo Localhost che risolve la mitigazione Copy Fail su Kubernetes si compone di quattro parti: un profilo seccomp JSON, uno snippet del pod-spec che lo usa, un pattern DaemonSet per il deployment cloud, e un comando di verifica. Inserisci il JSON seguente in /var/lib/kubelet/seccomp/profiles/copy-fail.json su ogni nodo:

json
{
  "defaultAction": "SCMP_ACT_ALLOW",
  "architectures": ["SCMP_ARCH_X86_64", "SCMP_ARCH_X86", "SCMP_ARCH_AARCH64"],
  "syscalls": [
    {
      "names": ["socket"],
      "action": "SCMP_ACT_ERRNO",
      "errnoRet": 1,
      "args": [
        {
          "index": 0,
          "value": 38,
          "op": "SCMP_CMP_EQ",
          "comment": "AF_ALG = 38; deny kernel crypto socket family"
        }
      ]
    },
    {
      "names": ["socket"],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}

Poi configura ogni workload per usarlo tramite il pod-spec:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: inference
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: copy-fail.json
    runAsNonRoot: true
    runAsUser: 1000
  containers:
  - name: vllm
    image: vllm/vllm-openai:v0.6.3
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]
      readOnlyRootFilesystem: true
      seccompProfile:
        type: Localhost
        localhostProfile: copy-fail.json

Per Kubernetes gestiti nel cloud, il pattern DaemonSet funziona su tutti e cinque i principali provider. Ecco la matrice AKS Copy Fail / EKS Copy Fail mitigation:

ProviderPercorso profiloMeccanismo di distribuzioneCaveat
AKS (Azure)/var/lib/kubelet/seccomp/profiles/DaemonSet scrive il file via hostPath; kubelet lo raccoglie. Vedi Azure/AKS#5753.Usa immagini nodo Mariner per la patch in-tree più rapidamente
EKS (AWS)/var/lib/kubelet/seccomp/profiles/DaemonSet + EKS-optimized AMI 1.30+Bottlerocket riceve la patch kernel via auto-update; Amazon Linux 2023 richiede dnf update kernel
GKE (Google)/var/lib/kubelet/seccomp/profiles/DaemonSet funziona in modalità standard; Autopilot non permette hostPath, usa NodeConfigCOS-117+ include il kernel patchato
OVHcloud MKS/var/lib/kubelet/seccomp/profiles/DaemonSet, come da blog OVHcloud Copy FailOVH pubblica un aggiornamento dell'immagine nodo gestita con cadenza di 7 giorni
DigitalOcean DOKS/var/lib/kubelet/seccomp/profiles/DaemonSet; le immagini nodo DO si aggiornano automaticamente al prossimo roll del poolIl roll del pool è necessario per la patch kernel — il DaemonSet copre il gap

Un semplice DaemonSet che inserisce il profilo al posto giusto, quando si deployana workload di inferenza su Kubernetes gestito:

yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: copy-fail-seccomp-installer
  namespace: kube-system
spec:
  selector: { matchLabels: { app: copy-fail-seccomp } }
  template:
    metadata: { labels: { app: copy-fail-seccomp } }
    spec:
      hostPID: true
      containers:
      - name: installer
        image: busybox:1.36
        command: ["sh", "-c", "cp /profile/copy-fail.json /host-seccomp/copy-fail.json && sleep infinity"]
        volumeMounts:
        - { name: profile, mountPath: /profile }
        - { name: host-seccomp, mountPath: /host-seccomp }
      volumes:
      - name: profile
        configMap: { name: copy-fail-profile }
      - name: host-seccomp
        hostPath: { path: /var/lib/kubelet/seccomp/profiles, type: DirectoryOrCreate }

Verifica che sia arrivato:

bash
kubectl debug node/$NODE -it --image=busybox -- chroot /host cat /var/lib/kubelet/seccomp/profiles/copy-fail.json | head -5

Abbiamo deployato il profilo Localhost via DaemonSet su un cluster AKS a 5 nodi. Kubelet lo ha raccolto entro 30 secondi senza riavviare il nodo, e un pod di test che ha chiamato socket(AF_ALG, ...) ha ricevuto immediatamente EPERM.

Nota onesta: se gestisci un servizio K8s che non espone la directory seccomp di kubelet (alcune offerte serverless K8s la nascondono), la blacklist modprobe su ogni template di nodo è l'unica strada. Integra la blacklist nell'immagine nodo, rideploya il node pool e verifica con kubectl debug.

Rilevamento: Come Capire Se Sei Già Stato Compromesso

Controlla /var/log/auth.log e journalctl -u containerd per syscall socket(AF_ALG, ...) inattese negli ultimi 30 giorni. Cerca nuovi binari setuid con find / -perm -4000 -newer /etc/shadow -mtime -30. Sysdig pubblica una regola Falco (Unexpected AF_ALG Socket Creation); Microsoft Defender XDR distribuisce la firma Behavior:Linux/CopyFailExploit.A.

bash
# 1. Auth.log per invocazioni sudo/setuid inattese vicino a syscall AF_ALG
sudo grep -E 'session opened for user root' /var/log/auth.log* | \
  awk '{print $1, $2, $3, $11}' | sort | uniq -c | sort -rn | head -20
bash
# 2. Binari setuid nuovi o modificati dalla data di divulgazione
sudo find / -xdev -perm -4000 -newer /etc/shadow -mtime -30 \
  -not -path '/proc/*' -not -path '/sys/*' 2>/dev/null
bash
# 3. Eventi di caricamento del modulo algif_aead negli ultimi 30 giorni
sudo journalctl --since "30 days ago" | grep -E 'algif_aead|algif_skcipher'
bash
# 4. Riferimento alla regola Falco (deploya tramite helm chart)
# https://github.com/falcosecurity/rules — nome regola: "Unexpected AF_ALG Socket Creation"
falcoctl artifact install copy-fail-rules

Se trovi un riscontro positivo — un nuovo binario setuid che non hai deployato tu, o un evento di caricamento kernel algif_aead legato a un utente inatteso — trattalo come una compromissione confermata. Ruota le credenziali, isola l'host, escalation al team di incident response e valuta se il timer GDPR delle 72 ore sia già partito. Il costo di una reazione eccessiva è una finestra di manutenzione; il costo di una reazione insufficiente sono i prossimi 18 mesi della tua carriera.

Hardening: Come Sopravvivere al Prossimo CVE Kernel Senza un'Emergenza

Copy Fail non sarà l'ultimo CVE kernel a sconfiggere RuntimeDefault. Sei interventi da fare questo trimestre per rendere il prossimo meno doloroso:

  • Superficie minima dei moduli kernel. Metti in blacklist algif_*, bluetooth, dccp, tipc, sctp, cifs se non li usi. La maggior parte dei workload non ne ha bisogno.
  • Seccomp deny-by-default su ogni workload. Rendi i profili Localhost la norma. RuntimeDefault è il minimo, non il massimo.
  • Refresh nodo basato su immagine (Talos Linux, Bottlerocket, Flatcar). Riavvii atomici, kernel immutabile, rollback indolore.
  • Monitoraggio a runtime. Falco o Tetragon che intercettano syscall inattese in tempo reale. Abbinali all'osservabilità a runtime per i workload AI dove la superficie di syscall è più ampia.
  • Allarmi per eventi di caricamento del modulo kernel con vita breve nel tuo SIEM. Se algif_aead dovesse mai caricarsi su un host in produzione che non ne ha bisogno, vuoi saperlo in secondi.
  • Blocca le versioni K8s e le immagini nodo su una baseline che monitori attivamente dal punto di vista della sicurezza. I tag floating sono un futuro incident già scritto.

Questa è la lezione che Copy Fail ci insegna prima che arrivi il prossimo. I team che gestiranno il prossimo zero-day in 30 minuti invece che in 60 sono quelli che hanno già implementato questi sei controlli.

Domande Frequenti

Sono interessato da Copy Fail (CVE-2026-31431)?

Quasi certamente sì, se esegui una delle principali distribuzioni Linux su un kernel rilasciato prima del 1° maggio 2026 e permetti accesso shell non privilegiato. Questo include ogni macchina multi-tenant, ogni worker Kubernetes e ogni CI runner. Esegui uname -r e confronta con la tabella delle versioni patchate sopra. Il CVSS è 7.8.

Il mio cluster Kubernetes è vulnerabile anche con PSS Restricted?

Sì. Pod Security Standards Restricted con seccompProfile.type: RuntimeDefault non blocca socket(AF_ALG, ...). Juliet.sh lo ha testato direttamente: un pod in esecuzione con PSS Restricted e RuntimeDefault ha compromesso il kernel host via Copy Fail. Serve un profilo seccomp Localhost (disponibile nella sezione di mitigazione K8s sopra).

Docker Desktop blocca Copy Fail?

Il profilo seccomp predefinito di Docker Desktop nega già molte syscall, ma non bloccava AF_ALG fino all'arrivo della moby/moby PR #52501. Aggiorna Docker a un release che include il profilo patchato (backport Docker 29.x), oppure applica il profilo seccomp manualmente. Le installazioni Linux di Docker senza quell'aggiornamento rimangono esposte.

Il seccomp RuntimeDefault ferma questo attacco?

No. RuntimeDefault è il profilo del container runtime non modificato (default Docker/containerd). Permette socket(AF_ALG, ...) perché i workload legittimi utilizzano occasionalmente la crypto API del kernel. La soluzione è un profilo Localhost che nega esplicitamente AF_ALG (JSON completo nella sezione K8s) oppure l'aggiornamento al default della moby/moby PR #52501.

Cosa fare se non posso riavviare il kernel adesso?

La blacklist modprobe più un profilo seccomp Localhost che nega socket(AF_ALG, ...) è sufficiente fino a quando non riesci ad applicare la patch. Entrambi si applicano senza riavvio. Aggiungi blacklist algif_aead in /etc/modprobe.d/copy-fail.conf, esegui rmmod algif_aead, deploya il profilo seccomp e riavvia alla prossima finestra di manutenzione.

Copy Fail è già sfruttata in the wild?

Al 5 maggio 2026, il post di threat intelligence di Microsoft non conferma sfruttamento in the wild ma descrive il bug come "banalmente sfruttabile" dato il PoC da 732 byte pubblicato da Xint. La classe di primitiva di exploit (scrittura page cache via splice) si sovrappone a Dirty Pipe (CVE-2022-0847), che fu ampiamente sfruttata entro settimane dalla divulgazione.

Copy Fail colpisce specificamente i workload AI/ML?

Sì, in modo sproporzionato. L'inferenza self-hosted (vLLM, sglang, Ollama), gli agent runtime, i MCP server e i build CI per immagini ML eseguono routinariamente codice utente non fidato. Qualunque di questi in un container, anche su PSS Restricted, può attivare Copy Fail e compromettere l'host. I nodi GPU sono il profilo a più alto rischio perché sono tipicamente multi-tenant.

In cosa differisce Copy Fail da Dirty Pipe?

Entrambe sono LPE del kernel Linux che producono scritture arbitrarie nella page cache, ma la superficie di attivazione è diversa: Dirty Pipe abusava di splice() su una pipe, Copy Fail abusa di splice() su un socket algif_aead (AF_ALG). Entrambe aggirano i default seccomp dei container. Il twist di Copy Fail: il percorso AF_ALG è raggiungibile da Pod Security Standards Restricted con RuntimeDefault.

Conclusione

Copy Fail è correggibile in circa 60 minuti se si segue il manuale dall'inizio alla fine: blacklist modprobe, aggiornamento kernel, profilo seccomp, verifica. L'angolo Kubernetes e infrastrutture AI è ciò che rende questo CVE diverso da una LPE ordinaria: PSS Restricted con RuntimeDefault non ti salverà, e un singolo pod di inferenza compromesso può compromettere l'host. La blacklist modprobe più un profilo seccomp Localhost è la difesa duratura anche dopo aver applicato la patch.

Vuoi un secondo parere sul tuo runbook di incident response, o una baseline K8s hardened prima che cada il prossimo CVE kernel? Contatta Techsy. Ci occupiamo di hardening della piattaforma per stack AI/ML in produzione.

Ultimo aggiornamento 2026-05-05. Il post verrà aggiornato con nuovi advisory per le distribuzioni entro il 2026-05-12.

Tag

copy failCVE-2026-31431kernel linuxAF_ALGalgif_aeadkubernetes securityseccompprivilege escalationincident responsesicurezza infrastrutture ai

Condividi questo articolo

Il Tuo Prossimo Passo

Hai un progetto in mente? Parliamone.

Prenota una call di 30 minuti. Ti ascoltiamo, capiamo il problema e ti diciamo se possiamo aiutarti.