Tornar al Blog

L'agent va fixar el commit del plugin. Git li va lliurar la branca de l'atacant

Dos portàtils oberts damunt d'una taula d'oficina i una mà escrivint sobre uns papers

Es va publicar aquesta setmana i es diu Plugin4Shell. Afectava els quatre agents de programació amb IA que els investigadors descriuen com els més usats —Claude Code, Codex, GitHub Copilot i Gemini CLI—, i la fallada és a dues ordres de git, no al model ni als permisos que et demana l'eina en arrencar. L'agent clona el repositori del plugin, fa checkout del commit exacte que el catàleg tenia fixat, i mai no comprova que hi hagi aterrat. Hem reproduït aquesta tarda, al nostre laboratori i amb git 2.43, el comportament en què se sosté: l'ordre acaba amb codi de sortida 0, imprimeix un avís que cap automatisme no llegeix, i deixa al directori de treball el contingut de l'atacant.

Llegit per sobre sembla un problema d'eines de desenvolupament, d'aquells que es queden a l'equip de producte. El que el treu d'aquí és la llista del que un plugin abasta quan s'executa: el codi font en local, les claus SSH del portàtil, les credencials de núvol que hi ha a l'entorn, els repositoris interns i el que aquestes credencials obrin en producció. Un plugin corre amb els permisos de qui executa l'agent. A la majoria d'empreses de programari que coneixem, aquests permisos són bastant més amplis del que ningú té escrit.

Què han publicat exactament

La troballa és d'Air Security, que diu haver construït una prova funcional el maig del 2026, haver-ho comunicat als quatre fabricants el juny i haver-ho fet públic aquesta setmana. El mecanisme el resumeixen així: «the agent checks out the exact commit the marketplace pinned but never verifies it landed there, so an attacker who controls the plugin's repo makes the checkout resolve to malicious code while the pin still looks honored». I sobre el que cal per part de la víctima: «No user interaction of any kind is required. The result is full compromise of the agent and the host it runs on.»

L'explicació d'OpenAI recollida per la premsa tècnica va a l'os de l'assumpte sense adorns: git «can interpret a requested commit SHA as a branch name», i per això l'origen d'un plugin pot «materialize a different commit than the one it pinned». Aquí hi és tot. Fixar el commit és la pràctica correcta —és el que fem tots perquè una dependència no canviï sota els peus—, i ho continua sent. El que falla és el pas següent, que ningú no fa: confirmar que el que tens al davant és el que vas demanar.

Ho hem muntat al laboratori

Abans d'escriure res vam voler veure el comportament amb els nostres ulls, perquè un titular així es repeteix malament amb facilitat. El que reproduïm és el comportament de git sobre el qual se sosté l'atac, no el codi dels agents. Un repositori, dos commits i un nom de branca triat amb mala idea.

# commit legítimo: 5c61cf42...  commit del atacante: 536fe217...
git branch 5c61cf4299f1e060978d6676edc410ebe8cbbfd1 536fe217a392034ee6c1e42ac2621841469b5d45
git checkout 5c61cf4299f1e060978d6676edc410ebe8cbbfd1

La branca es diu igual que el commit que el catàleg tenia fixat, i apunta al commit de l'atacant. Això és el que contesta git:

warning: refname '5c61cf4299f1e060978d6676edc410ebe8cbbfd1' is ambiguous.
Git normally never creates a ref that ends with 40 hex characters
because it will be ignored when you just specify 40-hex. [...]
Switched to branch '5c61cf4299f1e060978d6676edc410ebe8cbbfd1'

El fitxer del directori de treball conté el que va posar l'atacant. L'avís és eloqüent, i a més es contradiu amb el que acaba de passar: diu que un ref així «serà ignorat», i tanmateix git ha canviat a la branca. Va pel canal d'error, no trenca res i retorna zero. Qualsevol automatisme que miri el codi de sortida —que és el que mira un automatisme— continua endavant tan content.

Un matís que no ens estalviem, perquè és on això s'explica malament: al nostre laboratori, quan la branca de quaranta hexadecimals existia només com a branca remota del clon (refs/remotes/origin/…) i el commit legítim era al repositori, git checkout va aterrar al commit bo. El truc necessita que el ref existeixi en local —perquè és la branca per defecte del clon, com a la prova següent— o que el commit fixat no sigui enlloc. Així que la prova de dalt ensenya l'ambigüitat; la que ve ara és la que descriu l'atac.

La segona prova és encara menys vistosa i més incòmoda. Vam muntar un repositori on el commit fixat no existeix, amb la branca trampa com a branca per defecte. En clonar, el clon se situa tot sol en aquesta branca; i el checkout del commit fixat no dona error: respon Already on 'aaaa…' i surt amb zero. L'agent va demanar un commit que no és enlloc i es va quedar amb el codi de l'atacant, sense una sola línia vermella pel camí.

I el detall que ens sembla més perillós per a qui auditi això a posteriori: al primer escenari, amb la branca trampa creada i el commit bo present, git rev-parse 5c61cf42… retorna el commit legítim i git log -1 --format=%s 5c61cf42… imprimeix «commit legitimo». La mateixa cadena de 40 caràcters dona una resposta diferent segons quina ordre de git la llegeixi. Qui verifiqui amb git log veurà exactament el que espera veure mentre el directori de treball té una altra cosa a dins.

La comprovació que proposen els investigadors sí que resol el cas, perquè pregunta per HEAD i no per la cadena:

test "$(git rev-parse HEAD)" = "<pinned-sha>" || abort

L.hem executat a les dues proves i a totes dues avorta, perquè retorna el commit de l.atacant en lloc del fixat. Fa falta en més llocs que l.agent: qualsevol pipeline d'integració contínua pròpia que cloni un repositori i faci checkout d'un commit fixat té la mateixa peça que falta. Això no ho van inventar els agents d'IA; l'han posat a córrer milions de vegades al dia.

On no es pot fer, i on sí

Aquí l'assumpte deixa de ser una anècdota de git i passa a ser una decisió d'infraestructura. El truc necessita que algú pugui crear una branca el nom de la qual siguin quaranta caràcters hexadecimals, i les dues grans plataformes d'allotjament no ho permeten. GitHub ho va declarar a The Register: «GitHub does not allow users to create branch or tag names that resemble commit SHAs», i remata que «this mitigation ensures the reported vulnerability cannot be exploited on GitHub». GitLab ho té escrit a la seva documentació de branques, en una línia seca: «Branch names with 40 hexadecimal characters are prohibited, because they are similar to Git commit hashes.»

La recerca assenyala com a exposats altres allotjaments que sí que admeten aquests noms, i cita Bitbucket i els servidors git propis de cada empresa. Avui, per a aquesta fallada concreta, qui està protegit ho està per on viu el repositori, no pel bé que tingui configurat l'agent. I el servidor git que vas muntar tu fa tres anys, aquell que ningú no mira perquè «només és un remot intern», no porta aquesta comprovació de fàbrica.

Això s'arregla en deu minuts i sense comprar res. Un hook de pre-recepció al servidor, que rebutgi el push de qualsevol branca amb aquest patró. Ho hem provat al laboratori contra un repositori nu (bare): el push es rebutja i el missatge arriba al client.

remote: rechazado: nombre de rama con 40 caracteres hexadecimales
 ! [remote rejected] aaaaaaaa… -> aaaaaaaa… (pre-receive hook declined)

Una fallada, quatre respostes

Els quatre fabricants van rebre l'avís el juny. Això és el que consta a dia d'avui, segons la publicació dels investigadors i les respostes que ha recollit la premsa tècnica:

  • Anthropic (Claude Code): corregit a la versió 2.1.179.
  • OpenAI (Codex): corregit a la versió 0.146.0, amb una explicació pública del perquè.
  • Microsoft (GitHub Copilot): sense pedaç. Els investigadors diuen haver-ho notificat el juny i no haver tingut resposta, i atribueixen el silenci al volum de comunicacions que reben. L'exposició ve d'admetre catàlegs allotjats en llocs que sí que permeten aquests noms de branca.
  • Google (Gemini CLI): no es corregirà. L'eina està retirada —Google va deixar de servir la versió de consum al juny— i la recomanació és migrar a Antigravity, que segons els investigadors queda fora de l'abast d'aquest atac.

Una dada que sí que hem comprovat nosaltres, perquè és pública i es consulta en un segon: al registre d'npm, la versió 2.1.179 de Claude Code es va publicar el 16 de juny del 2026 i la 0.146.0 de Codex el 29 de juliol. Avui van per la 2.1.278 i la 0.155.1, publicades ahir i abans-d'ahir. Qui actualitzi les seves eines amb normalitat fa mesos que té això corregit i s'ha assabentat aquesta setmana de per què importava; qui tingui una versió clavada del primer semestre, no. Comprovar quina versió corre cada lloc de treball porta menys temps que llegir aquest paràgraf.

Ens interessa més aquesta llista que la fallada. La fallada és la mateixa per als quatre, i és un descuit honest: la mena de cosa que qualsevol de nosaltres hauria escrit igual. El que separa uns dels altres és què va passar després de rebre el correu, i això sí que és una dada de compra. Quan una eina entra al flux de treball del teu equip, hi entra també l'historial de resposta de qui la manté. «Sense pedaç tres mesos després» i «no ho arreglem, canvia de producte» són respostes legítimes d'un fabricant; la pregunta és si tu les hauries acceptat sabent-ho abans d'adoptar-la.

El portàtil de desenvolupament és part del pla de control

L'actualització automàtica dels plugins ve activada de sèrie a Claude Code i a Codex, segons la recerca. És una decisió raonable —així es distribueixen les correccions— i alhora és el camí pel qual una versió compromesa arriba a tots els llocs sense que ningú aprovi res. Un desplegament silenciós, d'aquells que només es veuen al registre quan ja cal explicar alguna cosa.

Fa mesos que escrivim al voltant d'aquesta mateixa idea des d'angles diferents. Quan vam parlar de quin nom acaba al registre quan un agent fa servir una credencial prestada, l'assumpte era la identitat. Quan vam explicar que bloquejar l'agent SSH desactivava les seves pròpies restriccions, l'assumpte era l'eina que sosté les claus. Aquí és el canal pel qual arriba el codi. Les tres vegades, el mateix objecte al centre: una màquina de treball que pot parlar amb producció i que no apareix en cap inventari de sistemes crítics.

El que faríem aquesta setmana

  • Actualitzar el que té arranjament: Claude Code a 2.1.179 o posterior, Codex a 0.146.0 o posterior. És l'únic punt d'aquesta llista que es fa en un minut.
  • Saber quins agents hi ha i de quin catàleg carreguen plugins. A moltes empreses la resposta honesta és «el que cadascú s'hagi instal·lat»; llavors la llista no existeix i cal fer-la abans de continuar.
  • Mirar on s'allotgen aquests repositoris. Si són a GitHub o a GitLab, la porta està tancada per l'allotjament. Si són en un altre lloc o en un servidor propi, el hook de pre-recepció de més amunt és la tarda d'avui.
  • Ficar la comprovació d'una línia a qualsevol automatisme propi que cloni i faci checkout d'un commit fixat. Començant per la integració contínua, que sol fer-ho amb més permisos que el portàtil.
  • Preguntar què obren les credencials del portàtil. Si la resposta inclou producció amb una clau sense caducitat, el problema d'avui és vell i Plugin4Shell només hi ha posat la data.
  • Decidir qui aprova una actualització automàtica de plugins en equips que toquen producció. Pot ser «ningú, que s'actualitzi tot sol»; el que no val és no haver-ho decidit.

I una recomanació que no surt d'aquesta notícia sinó de l'ofici: el repositori on viu el teu codi també necessita còpia pròpia, perquè clonar no és tenir una còpia de seguretat. Un atacant amb permís d'escriptura en un repositori pot reescriure història; si la teva única còpia és el mateix remot, has perdut el punt de comparació just quan el necessites.

Saps avui què abasta un plugin instal·lat al portàtil del teu equip?

Treballem la ciberseguretat pel mateix ordre que aquest post: primer l'inventari del que pot tocar producció, després els permisos de cada cosa, i només al final l'eina. I quan el que cal governar és automatització amb IA, muntem abans l'interruptor i el registre que l'automatisme. No venem llicències de cap dels productes que surten aquí, així que si la conclusió és que la teva configuració ja està bé i el que falta és un hook de pre-recepció, aquesta serà la resposta.

Parlar amb everyWAN

El que no afirmem

No hem atacat cap agent. El nostre laboratori reprodueix el comportament de git sobre el qual se sosté l'atac —que és el que podíem verificar pel nostre compte i el que ens semblava més fàcil de repetir malament—, no el codi de Claude Code, Codex, Copilot ni Gemini CLI; que cadascun d'ells executi exactament aquesta seqüència ho diu la recerca, no la nostra prova. Els números de versió corregida (2.1.179 i 0.146.0) i l'estat de cada fabricant surten de la publicació d'AIR Security i de les respostes recollides per la premsa tècnica; hem comprovat al registre d'npm que totes dues versions existeixen i quan es van publicar, però no que la correcció hi sigui a dins: el registre de canvis de cada producte no l'atribueix, així que aquesta part la sostenen els investigadors. No hem verificat amb una prova pròpia si Bitbucket admet avui noms de branca de quaranta hexadecimals, i per això ho donem com el que és: el que afirmen els investigadors. L'afirmació de GitHub sobre la seva pròpia plataforma és de GitHub, i tampoc no l'hem provada. Fins on hem pogut comprovar avui no hi ha un identificador CVE assignat, així que qui busqui per CVE no trobarà res; això no vol dir que no n'hi hagi d'haver. I no tenim constància pública d'explotació real: el que hi ha és una prova de concepte dels investigadors i una finestra de tres mesos entre l'avís i la publicació.

Nota de fonts

Tot consultat el 19 de setembre del 2026. Un, la recerca: la publicació d'AIR Security sobre Plugin4Shell, d'on surten el mecanisme (clonar i fer checkout del commit fixat sense verificar on ha aterrat), la frase «No user interaction of any kind is required. The result is full compromise of the agent and the host it runs on», el calendari (prova funcional el maig del 2026, comunicació als fabricants el juny, publicació aquesta setmana), la llista d'allotjaments exposats, l'actualització automàtica de plugins activada per defecte a Claude Code i Codex, i la comprovació d'una línia amb git rev-parse HEAD. Dos, la cobertura tècnica: les peces de Help Net Security (18 de setembre) i The Hacker News, d'on prenem la formulació «check out the pinned commit without verifying the checkout landed there, letting an attacker swap in malicious code while the pin still looks intact», l'explicació d'OpenAI («can interpret a requested commit SHA as a branch name», «materialize a different commit than the one it pinned»), les versions corregides 2.1.179 i 0.146.0, l'absència de pedaç a Copilot amb el matís que els investigadors no van obtenir resposta i la retirada de Gemini CLI. Tres, The Register (17 de setembre), d'on surten la declaració de GitHub sobre noms de branca semblants a SHA i l'explicació dels investigadors sobre per què no van obtenir resposta de Microsoft. Quatre, la documentació de GitLab: la pàgina de branques de la documentació oficial, amb la frase «Branch names with 40 hexadecimal characters are prohibited, because they are similar to Git commit hashes.» Cinc, el nostre laboratori: git 2.43.0, tres escenaris (branca amb nom de 40 hexadecimals apuntant a un altre commit; repositori on el commit fixat no existeix i la branca trampa és la branca per defecte; i un hook de pre-recepció que rebutja el push de branques amb aquest patró). Les sortides que reproduïm al cos són les d'aquella sessió, abreujades on ho indiquem amb claudàtors. Sis, el registre d.npm: consultat avui a registry.npmjs.org, d.on surten les dates de publicació de @anthropic-ai/claude-code 2.1.179 (16 de juny del 2026) i 2.1.278, i d.@openai/codex 0.146.0 (29 de juliol del 2026) i 0.155.1. El que és opinió nostra, i va dit com a tal: que la resposta del fabricant davant un avís coordinat és una dada de compra; que la defensa efectiva avui és a l'allotjament del repositori; que el portàtil de desenvolupament pertany al pla de control de producció encara que no sigui a l'inventari; i la llista del que faríem aquesta setmana.

Imatge de portada: fotografia de banc lliure de drets. Els textos i la marca els afegim nosaltres a sobre.

IA Ciberseguretat DevOps Automatització Vulnerabilitats
Compartir LinkedIn X

Subscriu-te al nostre butlletí

Per rebre històries del món IT, novetats d'everyWAN i ofertes exclusives per a subscriptors, dona't d'alta a la nostra llista de correu

everyWAN
everyWAN