← All research

ENDOR-VUL-2026-02021

Unauthenticated Command Injection via beforeCommands Concatenation

01Record

ProjectKestra
ComponentScriptService.scriptCommands()
CWECWE-78
CVSS9.8
Disclosed2026-08-08
Endor referenceENDOR-VUL-2026-02021
WriteupLink

02Detail

Description: In Kestra through 1.2.0, beforeCommands is Pebble-rendered and then joined to the main commands with Collectors.joining into a single string appended to the interpreter argument vector. Under the default interpreter ["/bin/sh", "-c"], everything after -c is one shell program, so any Pebble expression rendered into beforeCommands is shell source rather than an argument. A flow whose beforeCommands contains echo {{ trigger.body.command }} behind an io.kestra.plugin.core.trigger.Webhook trigger turns the webhook body into that shell program, and Kestra webhooks are unauthenticated by default.

Proof of concept, against a flow with a webhook trigger keyed test123:

curl -X POST \
  http://localhost:8081/api/v1/executions/webhook/default/rce_via_beforecommands/test123 \
  -H "Content-Type: application/json" \
  -d '{"command": "hello; touch /tmp/pwned; echo done"}'

The shell executes echo hello; touch /tmp/pwned; echo done and /tmp/pwned appears on the Kestra host. The caller holds no credential and has no account.

Impact: Unauthenticated Command Execution. This is the same sink as ENDOR-VUL-2026-0202, reached through a different property and without any authentication boundary in front of it.

Kestra closed this report as intended functionality alongside the interpreter finding, noting that beforeCommands has the same impact as commands because the two are concatenated, and recommending least privilege on flow creation. That control does not cover this path: execution is not gated by flow-creation permission once a webhook trigger exists. No advisory was assigned and no patch is planned. Full analysis is in the technical whitepaper.

Discovered by Peyton Kennedy (p80n).