Skip to content
Verified reproduction

GHSA-cc8m-98fm-rc9g: Skipper Lua Filter Arbitrary Code Execution

GHSA-cc8m-98fm-rc9g is verified against github.com/zalando/skipper · go This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00066.

REPRO-2026-00066 github.com/zalando/skipper · go Jan 17, 2026 .txt
Severity HIGH
Confidence HIGH
Reproduced in 9m 5s
Tool calls 73
Spend $0.89
$ pruva-verify REPRO-2026-00066
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00066/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
02 · The vulnerability

Arbitrary code execution through lua filters.

The default skipper configuration before v0.23 was -lua-sources=inline,file. The problem starts if untrusted users can create lua filters, because of -lua-sources=inline , for example through a Kubernetes Ingress resource. The configuration inline allows these user to create a script that is able to read the filesystem accessible to the skipper process and if the user has access to read the logs they an read skipper secrets.

Kubernetes example (vulnerability is not limited to Kubernetes)

function request(ctx, params)
  local file = io.open('/var/run/secrets/kubernetes.io/serviceaccount/token', 'r')
  if file then
    local token = file:read('*all')
    file:close()
    error('[EXFIL] ' .. token)  -- Exfiltrate via error logs
  end
end
03 · Root cause
## Summary
Skipper releases prior to v0.23.0 enable inline Lua filters by default (`-lua-sources=inline,file`). Any user able to submit a Lua filter (for example through an Ingress resource) can run arbitrary Lua code inside the Skipper process and access the local filesystem. Our reproduction shows that a crafted inline Lua script can read `/etc/hostname` and leak its contents through Skipper’s logs.

## Impact
- **Component:** `github.com/zalando/skipper` proxy binary
- **Affected Versions:** all versions before v0.23.0 (where Lua is enabled by default)
- **Risk:** High (CVSS 8.8) – attackers can execute arbitrary Lua code, read sensitive files (tokens, secrets), and exfiltrate data via logs or upstream responses. If the Skipper process holds credentials or tokens, they can be stolen.

## Root Cause
Skipper allowed inline Lua scripts to be embedded directly into route definitions and executed without sandboxing. When `-lua-sources` includes `inline` (default before v0.23.0), user-controlled Lua scripts run in the Skipper process with access to the standard Lua IO library. This enables arbitrary file reads/writes and system interaction. The issue was mitigated in v0.23.0 by disabling Lua filters by default (commit `0b52894570773b29e2f3c571b94b4211ef8fa714`).

## Reproduction Steps
1. Run `repro/reproduction_steps.sh` from the workspace root.
2. The script downloads Skipper v0.22.0, writes a malicious inline Lua route that reads `/etc/hostname`, starts Skipper with the route, and triggers it via `curl`.
3. Successful reproduction is evidenced by the Skipper log entry containing `[EXFIL] <hostname>` and the summary message printed by the script. Logs are stored under `logs/`.

## Evidence
- **Logs:**
  - `logs/reproduction.log` – full script run output
  - `logs/skipper_inline.log` – Skipper process logs
  - `logs/exfiltration.txt` – filtered `[EXFIL]` line showing leaked hostname
  - `logs/request.log` – HTTP status (404) from trigger request
- **Key Excerpt:** `logs/exfiltration.txt` contains `Error calling request ... [EXFIL] <hostname>` proving filesystem data leakage.
- **Environment:** `uname -a` → `Linux runsc 4.4.0 ... x86_64 GNU/Linux`

## Recommendations / Next Steps
- Upgrade Skipper to v0.23.0 or later, where Lua filters are disabled by default.
- If Lua scripts are required, explicitly limit `-lua-sources=file` and ensure only trusted scripts are deployed on the filesystem.
- Harden Lua execution by removing IO modules or running in a restricted sandbox, and add automated tests to ensure inline Lua stays disabled unless explicitly allowed.

## Additional Notes
- The reproduction script is idempotent: it reuses downloaded artifacts, stops Skipper between runs, and was executed successfully twice in a row.
- The exploit demonstrates read access; write/execute primitives are also possible via Lua IO APIs under the same configuration.
04 · Reproduction transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired. Phases: support triages the advisory · repro reproduces it · vuln_variant confirms the fix blocks it · judge verifies.

Loading session...

05 · Artifacts

Scripts, logs, diffs, and output captured during the reproduction.

No artifacts available