
Proof-of-concept lab che dimostra l'iniezione di comandi nel workflow dispatch di GitHub Actions (CVE-2026-39866). Esegue versioni vulnerabili e corrette affiancate per un'analisi didattica.
Laboratorio proof-of-concept per l'iniezione di comandi nel workflow dispatch di GitHub Actions
CVE-2026-39866 è un bug di iniezione di comandi nel workflow di rilascio di GitHub Actions di Lawnchair. Il file release_update.yml passa l'input dell'utente direttamente a bash senza virgolette, quindi un attaccante può iniettare comandi. Questo repository esegue sia la versione vulnerabile che quella corretta affiancate.
| Campo | Valore |
|---|---|
| ID CVE | CVE-2026-39866 |
| GHSA | GHSA-9prc-pp2c-3427 |
| CWE | CWE-78 (Neutralizzazione impropria di elementi speciali usati in un comando del sistema operativo) |
| Prodotto | LawnchairLauncher/lawnchair |
| Versioni interessate | Tutte le versioni precedenti a fcba413 |
| Corretta in | fcba413 |
| Scoperta | Abhay Kumar (@abhayclasher) |
La vulnerabilità esiste nel file di workflow release_update.yml. L'azione accetta un parametro artifactName e lo passa direttamente a un comando bash senza virgolette.
- name: Rename artifact
run: mv ${{ inputs.artifactName }}.zip lawnchair.zip
GitHub Actions sostituisce il valore della variabile nella stringa prima che la shell la esegua. Senza virgolette attorno a ${{ inputs.artifactName }}, la shell interpreta spazi e punti e virgola come separatori di comandi.
Se un attaccante fornisce file.zip; touch pwned.txt # come artifactName:
Come GitHub Actions lo analizza:
${{ inputs.artifactName }} → file.zip; touch pwned.txt #
Come la shell lo esegue:
mv file.zip; touch pwned.txt #.zip lawnchair.zip
La shell esegue mv file.zip, poi touch pwned.txt, quindi ignora il resto come commento.
GITHUB_TOKEN o le chiavi di firma dei rilasci).git clone https://github.com/abhayclasher/CVE-2026-39866.git
cd CVE-2026-39866/app
npm install
node server.js
git clone https://github.com/abhayclasher/CVE-2026-39866.git
cd CVE-2026-39866
docker compose up -d
Dopo l'avvio del server, visita questi URL:
| URL | Descrizione |
|---|---|
http://localhost:3000/workflow/vulnerable | Workflow vulnerabile — l'iniezione di comandi viene eseguita all'invio |
http://localhost:3001/workflow/patched | Stesso workflow con la patch fcba413 applicata |
La versione vulnerabile eseguirà il comando iniettato sul runner. La versione corretta tratta l'input come una stringa letterale.
Puoi anche eseguire il PoC autonomo:
cd poc
node exploit.js
Questo avvia un server minimale sulla porta 3000 che dimostra lo stesso bug senza il contesto completo dell'applicazione.
1. L'attaccante controlla il parametro di input artifactName
2. GitHub Actions espande ${{ inputs.artifactName }} nel YAML
3. Lo step run lo invia a bash
4. Bash vede caratteri speciali non quotati e li tratta come sintassi di comando
5. I comandi vengono eseguiti con i privilegi dell'ambiente del runner
┌────────────────────────────────────────────────────┐
│ 1. Input malevolo: │
│ │
│ artifactName = "file.zip; id #" │
│ │
│ 2. GitHub Actions sostituisce nel YAML: │
│ │
│ run: mv file.zip; id #.zip lawnchair.zip │
│ │
│ 3. Bash vede: │
│ - mv file.zip │
│ - id <-- Comando arbitrario │
│ - #.zip lawnchair.zip (ignorato) │
│ │
│ 4. La shell esegue il comando arbitrario │
└────────────────────────────────────────────────────┘
La versione fcba413 introduce le virgolette attorno alla variabile interpolata:
- name: Rename artifact
run: mv "${{ inputs.artifactName }}.zip" lawnchair.zip
Le virgolette impediscono alla shell di analizzare i caratteri speciali. Il payload rimane trattato come una stringa di nome file letterale.
La best practice è usare variabili d'ambiente per isolare completamente l'input dell'utente:
- name: Rename artifact
env:
ARTIFACT_NAME: ${{ inputs.artifactName }}
run: mv "$ARTIFACT_NAME.zip" lawnchair.zip
Visualizza il commit completo: fcba413
CVE-2026-39866/
├── README.md # Questo file
├── docker-compose.yml # Configurazione del laboratorio Docker
├── app/
│ ├── Dockerfile # Configurazione di build del container
│ ├── package.json # Dipendenze Node.js
│ └── server.js # Simulazione del runner del workflow vulnerabile + corretto
└── poc/
└── exploit.js # Proof-of-concept minimale autonomo
Segnalato da Abhay Kumar. Questo repository è destinato esclusivamente all'uso educativo locale. Non distribuire il server vulnerabile su una rete pubblica.
Solo a scopo educativo — utilizzare in ambienti isolati