«És només lectura» és la frase amb què s'aproven coses sense reunió. El token de només lectura per a l'script. El compte de només lectura per al consultor. El rol de lector al tenant, que es concedeix per xat en trenta segons. Com que no escriu, no trenca res; com que no trenca res, no cal discutir-ho amb ningú. El dijous 10 de setembre GitLab va publicar el pedaç d'una fallada que només sap llegir fitxers i li va posar un 10,0. La nota màxima, i el número el van signar ells.
El calendari de la setmana va així. Dijous 10: GitLab treu les versions corregides. Divendres 11: l'empresa de seguretat watchTowr informa de sondejos contra aquesta fallada en instàncies exposades a Internet. Aquest mateix divendres, CISA la fica al seu catàleg de vulnerabilitats explotades amb data límit el dilluns 14. I fins a la matinada del dissabte 12 no apareix la fitxa publicada a la base de dades nacional de vulnerabilitats, que és d'on beuen bona part dels inventaris de pedaços. La lectura és nostra, però costa esquivar-la: l'escàner que sincronitza amb el NVD se'n va assabentar després que qui ja estava provant la porta.
Nosaltres tenim un GitLab autoallotjat, amb el CI/CD GitOps des del qual es desplega aquest mateix web, així que l'avís ens tocava de primera mà. El que segueix no és la crònica de la nostra instància —això es queda a casa—, sinó l'ordre en què mirem aquestes coses quan apareix un número rodó: primer què s'ha trencat, després què diu el vector, i al final la pregunta que el pedaç no tanca.
Què es va trencar, amb noms i números
La fallada és CVE-2026-85706 i afecta GitLab Community Edition i Enterprise Edition. La descripció oficial, traduïda, diu que sota determinades condicions un usuari no autenticat podria haver llegit fitxers arbitraris del servidor GitLab, per confinament incorrecte de rutes i manca d'aplicació de l'autenticació a l'API de commits del repositori. Dos defectes, no un: la ruta no estava ben acotada i l'endpoint no comprovava qui preguntava.
Les versions afectades són totes des de la 18.7 fins abans de la 19.1.8, la branca 19.2 abans de la 19.2.6 i la 19.3 abans de la 19.3.2. Aquestes tres són les corregides, publicades el 10 de setembre en un paquet amb divuit correccions de seguretat. La va trobar algú de fora, a través del programa de recompenses: a les referències del CVE hi figuren l'informe de HackerOne i el tiquet intern de GitLab. La classificació del defecte balla segons qui l'ompli —GitLab, que és qui manté el registre del CVE, el cataloga com a CWE-22, i CISA al seu catàleg com a CWE-35—, i totes dues són variants del mateix: recorregut de rutes.
La prova de concepte completa no és pública, però els indicadors per buscar als teus registres sí que ho són des de divendres, i convé apuntar-los perquè canvien tot el que ve després. watchTowr va publicar que cal caçar peticions HTTP POST contra rutes del tipus /api/v4/projects/{id}/repository/commits/ que portin paràmetres file.path. I hi va afegir la condició prèvia que la descripció oficial deixa en «sota determinades condicions»: cal que a la instància hi hagi almenys un projecte públic.
Aquest detall del mètode és la millor notícia de tota la setmana per a qui hagi de revisar. La ruta de commits la consulten cada dia integracions, generadors d'insígnies i taulers de desplegament, i totes fan GET. Un POST sense usuari contra aquesta ruta no s'assembla al trànsit de ningú: és una anomalia amb forma reconeixible, i per tant una cosa que es pot buscar en un registre sense ser analista forense.
El 10,0 no el posa la fallada. El posa el vector
Una puntuació CVSS surt sempre d'un vector, i el d'aquest CVE el signa [email protected], és a dir el mateix fabricant. És aquest:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N — 10.0
— Vector CVSS 3.1 de CVE-2026-85706 segons el registre del CVE, font [email protected].
La primera meitat és la que tothom espera d'una fallada greu: s'ataca per xarxa (AV:N), sense que l'atacant hagi de preparar res (AC:L), sense credencials (PR:N) i sense que ningú hagi de clicar res (UI:N). Quatre zeros de fricció. La segona meitat és la interessant. C:H és el previsible: es llegeix tot. Però al costat hi ha I:H, impacte alt en integritat, en una fallada que no escriu res. I al davant, S:C: canvi d'abast, que en el vocabulari de CVSS significa que el dany surt del component vulnerable i cau en un altre lloc.
El compte el pot repetir qualsevol a la calculadora oficial. Agafa el mateix vector i deixa'l en el que una fallada de lectura sembla a simple vista: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N. Això puntua 7,5. La fallada és la mateixa, la xarxa és la mateixa i la facilitat és la mateixa. Els 2,5 punts que separen una xifra de l'altra descriuen el que hi ha guardat dins dels fitxers, i els hi posa el fabricant en l'únic idioma formal que té per dir-ho: en un servidor GitLab, llegir no es queda en llegir.
Al mateix paquet de pedaços del dia 10 hi ha un segon crític que serveix de contrast. CVE-2026-87719 puntua 9,9: una deserialització insegura en un serialitzador de subscripcions GraphQL que permet treure configuracions de la cerca avançada i credencials sensibles. És una dècima menys, i tot i així queda molt més lluny: el seu vector porta PR:L i la descripció demana un usuari autenticat amb accés a Duo Chat, a més de ser només Enterprise Edition. Per al 9,9 cal algú a dins. Per al 10,0 no cal ningú.
«Només lectura» és el permís que s'aprova sense reunió
El mateix raonament que fa que aquest CVE valgui un 10,0 s'aplica, sense canviar una coma, a mitja dotzena de decisions que es prenen a qualsevol empresa sense anomenar-les decisions. El token «de només lectura» del CI que pot clonar els cent vint repositoris, inclòs el que té el .env de producció que algú va pujar el 2023. El compte «de només lectura» que es dona al consultor per a l'auditoria i que veu la taula sencera de clients. El rol de lector del directori, que no toca res i a canvi t'ensenya l'organigrama complet, els grups i qui és administrador: el mapa exacte que necessita algú per escriure un correu creïble.
Ja vam escriure sobre un cas de manual d'aquesta família: el privilegi REPLICATION de PostgreSQL, que es concedeix perquè sona a còpia i no a escriptura, i que a la pràctica t'entrega el clúster sencer. El patró és idèntic, i la fallada és de vocabulari abans que de programari. El que fa perillós un permís no és el verb, és l'abast. «Lectura» descriu l'acció; ningú no pregunta pel complement directe.
No estem dient que llegir i escriure siguin el mateix; seria una ximpleria i a més és fals. Estem dient una cosa més incòmoda i més útil: en qualsevol sistema que guardi credencials per parlar amb altres sistemes, la distància entre llegir i escriure és un copiar i enganxar. I un servidor de codi autoallotjat és, per definició, un sistema que guarda credencials per parlar amb altres sistemes. Aquesta és la seva feina. Per això aquest S:C del vector és literal i no retòric.
CISA no va demanar només pedaçar. Va demanar mirar enrere
El catàleg de vulnerabilitats explotades de CISA és un fitxer JSON públic, i val la pena baixar-se'l en comptes de llegir el que altres n'expliquen, perquè cada entrada porta camps que la cobertura de premsa no acostuma a mirar. La de GitLab hi va entrar l'11 de setembre amb data límit el 14 —tres dies— i amb un camp posat a «Yes» que es diu forensicTriage: triatge forense.
Vam comptar quantes entrades porten aquesta marca, perquè el número diu més que l'etiqueta: 51 de 1.709. Un tres per cent del catàleg. I el termini tampoc no és el de tots: aquell mateix 11 de setembre hi van entrar dues fallades de JFrog Artifactory amb catorze dies i sense marca de triatge. Mateix dia, mateixa agència, gairebé cinc vegades més marge. Que no és qüestió de fabricant ho ensenya la tercera alta de la jornada: ConnectWise ScreenConnect, també amb tres dies i també amb la marca posada. El catàleg està distingint, entrada per entrada, entre «posa't al dia» i «posa't al dia i a més comprova si ja va passar». La segona surt cara, perquè no la resol un apt upgrade.
Aquesta directiva obliga les agències federals dels Estats Units i ningú més; ben cert que no una empresa de Sant Fruitós de Bages. Cap pime espanyola no està incomplint res per no haver pedaçat el diumenge. Però el criteri de priorització és públic i és gratuït, i el criteri diu que aquesta fallada pertany a la categoria de les que cal investigar cap enrere. La mateixa acció requerida de la fitxa inclou una frase que sí que aplica a tothom, i amb la qual estem d'acord: els responsables han d'avaluar l'exposició a Internet de cada actiu. Avaluar. No suposar.
«Ens van llegir?» té resposta, i el fitxer hi és des del primer dia
Una fallada de lectura per HTTP deixa rastre. No el rastre que busca un antivirus, perquè no hi ha procés nou ni binari caigut, però sí una línia en un registre. En una instal·lació amb el paquet oficial de GitLab, les crides a l'API s'escriuen a /var/log/gitlab/gitlab-rails/api_json.log, una línia JSON per petició, amb aquests camps, entre d'altres: time, status, method, path, params, remote_ip, route, user_id i username. Al costat, el servidor web guarda el seu propi registre a /var/log/gitlab/nginx/gitlab_access.log.
I hi ha una segona bona notícia, aquesta per defecte: la rotació que porta de fàbrica el paquet és diària, guarda 30 rotacions i comprimeix. Traduït: si ningú no ha tocat aquesta configuració, tens al voltant d'un mes d'historial a disc, que cobreix de sobres el 10 i l'11 de setembre. No cal comprar res per respondre la pregunta. Cal obrir el fitxer.
Com que la ruta es guarda normalitzada amb el patró /api/:version/..., es pot cercar pel tram de l'endpoint sense saber-se l'identificador de cap projecte. Amb els indicadors de watchTowr —mètode POST i paràmetre file.path— l'escombratge queda força estret. Sobre els registres rotats inclosos:
# 1. lo que watchTowr da como indicador: POST + file.path contra la ruta de commits
zcat -f /var/log/gitlab/gitlab-rails/api_json.log* \
| jq -r 'select((.route // "") | test("repository/commits"))
| select(.method == "POST")
| select((.params // [] | tostring) | test("file\\.?_?path"; "i"))
| [.time, .remote_ip, .status, (.username // "-")] | @tsv'
# 2. quien pregunta por esa ruta sin usuario, agrupado por IP para ver el volumen
zcat -f /var/log/gitlab/gitlab-rails/api_json.log* \
| jq -r 'select((.route // "") | test("repository/commits"))
| select(.user_id == null)
| .remote_ip' \
| sort | uniq -c | sort -rn | head -20
La primera ordre busca l'intent amb la forma que descriu watchTowr; la segona dibuixa el fons, que és quines adreces pregunten per aquesta ruta sense usuari i amb quin volum. Tres avisos abans que algú tregui conclusions. Si el teu GitLab és darrere d'un proxy o un balancejador, remote_ip pot ser el del proxy i cal anar a la capçalera reenviada. Hi ha peticions legítimament anònimes contra projectes públics, de manera que l'absència d'usuari, tota sola, no acusa ningú. I si en llançar l'ordre descobreixes que només tens set dies d'historial perquè algú va retallar la rotació fa dos anys, aquest és el teu descobriment d'avui, per damunt del CVE.
I si d'aquesta cerca en surt alguna cosa, la conversa deixa de ser tècnica i passa a ser de terminis: fa dos dies escrivíem sobre les vint-i-quatre hores del Cyber Resilience Act i el moment exacte en què arrenca el rellotge. Arrenca quan te n'assabentes, no quan es publica el CVE. Per això l'ordre importa: primer es mira, i amb el que surti es decideix. A l'inrevés no es pot.
Quan no faríem res aquesta nit
Un 10,0 no significa «t'entraran avui». Significa que per intentar-ho no cal cap credencial, que és el que diu PR:N; és una mesura de facilitat, i la probabilitat la posa la teva exposició. D'aquí surten dues recomanacions que sonen contradictòries i no ho són. Si el teu GitLab no contesta des d'Internet —i ho has comprovat, no ho suposes—, no muntis una finestra d'emergència un diumenge a la nit per a una 19.1.x. Actualitzar GitLab a la babalà un cap de setmana, sense còpia prèvia i sense ningú de guàrdia, té la seva pròpia manera d'arruïnar-te el dilluns. Finestra ordenada, còpia abans, i si pot ser amb algú al davant.
Dit això, dos matisos. El primer: la còpia prèvia ha de ser una còpia de debò, i ja vam explicar per què clonar els repositoris no és tenir còpia de GitLab —hi falten les incidències, els merge requests, els registres i, molt en particular, el fitxer de secrets sense el qual la base de dades que restaures no es pot desxifrar—. El segon: encara que no estiguis exposat, mira el registre igualment. Una lectura des de dins també és una lectura, i la part més incòmoda d'un compromís no és el que passa, sinó el que va passar fa tres setmanes i ningú no va mirar. És la mateixa lliçó que trèiem de l'incident de Cisco FMC: el pedaç tanca la porta, però no contesta què en va sortir abans.
Ho diem aquí des de fa anys amb altres paraules: la fallada és inevitable, l'avaria és una decisió de disseny. Que existeixi un CVSS 10,0 al programari que fas servir no és culpa teva ni ho evitaràs. Que no puguis contestar «ens van llegir?» sí que és una decisió, i es va prendre el dia que algú va decidir quant historial guardar i qui el mira.
Qui mira els teus registres el dia que cal?
Amb l'abast per davant: un agent al servidor no et contesta això, perquè no hi ha procés estrany ni binari nou, hi ha un POST contra l'API de commits. El que contesta és el registre guardat prou temps i algú que sàpiga què hi ha de buscar. Aquesta és la part de resposta del nostre EDR/MDR gestionat: retenció, correlació i una persona de guàrdia. Al costat hi va el Zero Trust, que és el que fa que un «només lectura» signifiqui de debò poca cosa. Si en revisar-ho resulta que ho tens ben muntat, t'ho direm i no hi haurà factura.
Parlar amb everyWANNota de fonts
Fonts primàries que hem llegit nosaltres. El registre de CVE-2026-85706 a la base de dades nacional de vulnerabilitats del NIST: d'allà surten la descripció citada, el rang de versions afectades i corregides (18.7 < 19.1.8, 19.2 < 19.2.6, 19.3 < 19.3.2), la classificació CWE-22 i el vector —tots dos aportats per [email protected] com a responsable del registre, perquè el NIST encara no l'ha analitzat: la fitxa figura en estat «Received»—, la data de publicació de la fitxa (12 de setembre de 2026, 03:16 UTC) i el vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N amb puntuació 10,0, atribuït a [email protected]; entre les seves referències hi figuren l'informe de HackerOne i el work item de GitLab. La nota de la versió 19.3.2 de GitLab, del 10 de setembre de 2026, per al paquet de divuit arreglaments i per al segon crític, CVE-2026-87719 (9,9, només Enterprise Edition), el vector del qual amb PR:L hem comprovat també al registre del NIST. El catàleg de vulnerabilitats explotades conegudes de CISA, descarregat en format JSON (instantània de l'11 de setembre de 2026, 19:32 UTC, amb 1.709 entrades): d'allà surten la data d'alta (11 de setembre), la data límit (14 de setembre), el camp forensicTriage en «Yes», el text de l'acció requerida i les entrades de JFrog Artifactory del mateix dia amb termini de catorze dies. La documentació d'administració de GitLab per a les rutes i els camps d'api_json.log i gitlab_access.log, i la seva documentació del paquet Linux per als valors per defecte de rotació (diària, 30 rotacions, comprimida). L'avís de watchTowr de l'11 de setembre, del qual prenem tant els sondejos observats com la seva guia de caça —peticions POST a rutes /api/v4/projects/{id}/repository/commits/ amb paràmetres file.path— i la condició prèvia que hi hagi almenys un projecte públic a la instància; aquella guia la recullen també SecurityWeek i The Hacker News el mateix dia. Que ConnectWise ScreenConnect (CVE-2026-84869) entrés l'11 amb tres dies i triatge forense surt del mateix JSON de CISA.
El que és compte o lectura nostra i no de les fonts. El recompte de 51 entrades amb marca de triatge forense sobre 1.709 l'hem fet nosaltres sobre el JSON descarregat; canvia cada vegada que CISA publica. La comparació entre el 7,5 i el 10,0 és aritmètica nostra amb la fórmula estàndard de CVSS 3.1: el vector hipotètic AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N puntua 7,5, i qualsevol ho pot reproduir a la calculadora oficial de FIRST. La interpretació de S:C i I:H com una afirmació del fabricant sobre el contingut dels fitxers és lectura nostra, no una declaració de GitLab. També són nostres: la tesi del vocabulari («el que fa perillós un permís no és el verb, és l'abast»), la lectura del termini de tres dies enfront del de catorze com una distinció entre pedaçar i investigar, l'observació que l'escàner que sincronitza amb el NVD se n'assabenta després que qui ja sondeja, la que un POST sense usuari contra la ruta de commits és una anomalia enfront del GET de les integracions, la que un 10,0 mesura facilitat i no probabilitat, i el càlcul d'«al voltant d'un mes d'historial» a partir dels trenta cicles diaris de rotació documentats, l'ordre de zcat i jq —que és un punt de partida, no una regla de detecció— i els seus tres avisos. Els exemples de permisos de només lectura són il·lustratius i no descriuen cap client concret. Que tinguem GitLab autoallotjat amb CI/CD propi sí que és nostre. Tot es va comprovar el 13 de setembre de 2026.
Fotografia de portada: «Documents on repository shelving at The National Archives», de The National Archives (Regne Unit), publicada a Wikimedia Commons sota llicència Creative Commons CC BY 3.0. L'hem retallada i hi hem superposat els textos de marca.