Share
## https://sploitus.com/exploit?id=DF3A1E2B-3984-5D6A-A4D0-95B864B82A66
# CVE-2026-39866 โ€” Command Injection via unquoted workflow dispatch input


  
  
  
  



  Proof-of-concept lab for command injection in GitHub Actions workflow dispatch


---

## Purpose

CVE-2026-39866 is a command injection bug in Lawnchair's GitHub Actions release workflow. The `release_update.yml` file passes user input directly to bash without quoting, so an attacker can inject commands. This repo runs both the vulnerable and patched versions side by side.

## Quick facts

| Field | Value |
|-------|-------|
| CVE ID | [CVE-2026-39866](https://nvd.nist.gov/vuln/detail/CVE-2026-39866) |
| GHSA | [GHSA-9prc-pp2c-3427](https://github.com/LawnchairLauncher/lawnchair/security/advisories/GHSA-9prc-pp2c-3427) |
| CWE | [CWE-78](https://cwe.mitre.org/data/definitions/78.html) (Improper Neutralization of Special Elements used in an OS Command) |
| Product | [LawnchairLauncher/lawnchair](https://github.com/LawnchairLauncher/lawnchair) |
| Affected | All versions below fcba413 |
| Patched | fcba413 |
| Discovery | [Abhay Kumar (@abhayclasher)](https://github.com/abhayclasher) |

## Vulnerability details

The vulnerability exists in the `release_update.yml` workflow file. The action takes an `artifactName` parameter and passes it directly into a bash command without quoting.

```yaml
- name: Rename artifact
  run: mv ${{ inputs.artifactName }}.zip lawnchair.zip
```

GitHub Actions substitutes the variable value into the string before the shell runs it. Without quotes around `${{ inputs.artifactName }}`, the shell interprets spaces and semicolons as command separators.

If an attacker supplies `file.zip; touch pwned.txt #` as the `artifactName`:

**How GitHub Actions parses it:**
`${{ inputs.artifactName }}` โ†’ `file.zip; touch pwned.txt #`

**How the shell executes it:**
```
mv file.zip; touch pwned.txt #.zip lawnchair.zip
```

The shell executes `mv file.zip`, then `touch pwned.txt`, then ignores the rest as a comment.

## Impact

- Execute arbitrary commands on the GitHub Actions runner.
- Steal repository secrets exposed to the runner environment (like `GITHUB_TOKEN` or release signing keys).
- Alter release artifacts before they are uploaded.
- Pivot into connected infrastructure if the runner is self-hosted.

## System requirements

- Node.js 18 or later
- Docker (optional, for containerized lab)
- 500 MB free disk space

## Setup

### Option 1: Run directly

```bash
git clone https://github.com/abhayclasher/CVE-2026-39866.git
cd CVE-2026-39866/app
npm install
node server.js
```

### Option 2: Run with Docker

```bash
git clone https://github.com/abhayclasher/CVE-2026-39866.git
cd CVE-2026-39866
docker compose up -d
```

## Usage

After the server starts, visit these URLs:

| URL | Description |
|-----|-------------|
| `http://localhost:3000/workflow/vulnerable` | Vulnerable workflow โ€” command injection executes on submit |
| `http://localhost:3001/workflow/patched` | Same workflow with fcba413 patch applied |

The vulnerable version will execute your injected command on the runner. The patched version treats the input as a literal string.

You can also run the standalone PoC:

```bash
cd poc
node exploit.js
```

This spins up a minimal server on port 3000 that demonstrates the same bug without the full application context.

## How it works

### Detection flow

```
1. Attacker controls the artifactName input parameter
2. GitHub Actions expands ${{ inputs.artifactName }} into the YAML
3. The run step sends this to bash
4. Bash sees unquoted special characters and treats them as command syntax
5. Commands execute with runner environment privileges
```

### The attack chain

```
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  1. Malicious input:                               โ”‚
โ”‚                                                     โ”‚
โ”‚     artifactName = "file.zip; id #"                โ”‚
โ”‚                                                     โ”‚
โ”‚  2. GitHub Actions substitutes into YAML:          โ”‚
โ”‚                                                     โ”‚
โ”‚     run: mv file.zip; id #.zip lawnchair.zip       โ”‚
โ”‚                                                     โ”‚
โ”‚  3. Bash sees:                                      โ”‚
โ”‚     - mv file.zip                                   โ”‚
โ”‚     - id                    
  Educational purposes only โ€” use in isolated environments