Kestra CVE-2026-49869: One Path Ending in /configs Is Root Without a Password
Kestra CVE-2026-49869 is a CVSS 10.0 unauthenticated RCE: a suffix check in the auth filter turns any /configs-ending path into root. KEV-listed, exploited for cryptomining. Fix + hunt runbook.
On September 2, 2026, CISA added CVE-2026-49869 to the Known Exploited Vulnerabilities catalog. It is a CVSS 10.0 flaw in Kestra, the open-source data-orchestration platform, and it is the kind of bug that reads like a code-review exercise: the authentication filter decides whether a request needs credentials by asking whether the request path ends with /configs. Not whether it is /configs. That one word — endsWith instead of an exact match — is the entire vulnerability, and it hands an unauthenticated attacker remote code execution as root inside the worker container. The fix shipped weeks ago; the exploitation that put it on KEV was already happening in late June.
What CVE-2026-49869 actually is
Kestra runs your pipelines. It schedules workflows, executes tasks, and — by design — runs arbitrary code, because that is what an orchestration engine does. Protecting the API that creates and launches those workflows is therefore the whole security model. CVE-2026-49869 breaks that model at the front door.
The AuthenticationFilter in Kestra OSS exempts one public endpoint from Basic Auth so the UI can read configuration before login. It does this with:
request.getPath().endsWith("/configs")
Suffix matching is not path matching. Any route whose path ends in the string configs sails through the filter with no credentials — including routes that create and execute flows. An attacker crafts a request whose path terminates in /configs, the filter waves it through as "public config", and the request reaches an endpoint that will happily build a workflow and run a shell task. The CWE stack on the record is precise about the layering: CWE-287 improper authentication feeding CWE-78 OS command injection, with CWE-184 (incomplete list of disallowed inputs) naming the root cause — a denylist-by-suffix where an allowlist-by-exact-path was needed.
This was not the only path-matching mistake in that filter. The same fixed releases also close CVE-2026-53576, where the REST API filter @Filter("/api/v1/**") mishandles request paths and produces the same result — unauthenticated flow creation and RCE. Two separate suffix/prefix matching bugs in the same authentication layer, patched together. When a codebase gets one path-comparison bug, it usually has two.
From auth bypass to unauthenticated RCE as root
The chain is short, which is why the CVSS vector (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) maxes out. No privileges, no user interaction, network-reachable, and — the S:C scope-change bit — the impact escapes the vulnerable component into the container it runs in.
Attacker:
POSTa flow definition to a path ending in/configs, with aio.kestra.plugin.scripts.shelltask that runscurl … | sh. Kestra: No credentials? Path ends in/configs, that's the public config route. Allowed. Creating flow. Executing task as root. Attacker: I now have a reverse shell in your pipeline runner.
Because the worker executes tasks as root inside its container, the attacker's first instruction already runs at the highest local privilege. There is no second exploit needed for local escalation — the workflow engine is the code-execution primitive, and it was designed to be. The vulnerability just removed the login.
The kill chain observed in the wild
This is the part that matters more than the bug. The activity that got CVE-2026-49869 onto KEV was not a proof-of-concept; it was a working intrusion, observed from late June 2026, and its shape is the reason network-side detection matters. Reconstructed from the public reporting (The Hacker News, which covered the seven-CVE KEV batch), the stages were:
| Stage | Action | ATT&CK |
|---|---|---|
| Initial access | Unauth request to a /configs-ending path → flow creation |
T1190 Exploit Public-Facing Application |
| Execution | Shell task runs curl | sh in the worker |
T1059.004 Unix Shell |
| Ingress | Payload pulled from attacker infrastructure | T1105 Ingress Tool Transfer |
| Discovery | Enumeration of the Docker container environment | T1613 Container & Resource Discovery |
| Collection/staging | Output encoded and written to Kestra's key-value store, not to disk | T1074 Data Staged |
| Impact | Cryptocurrency miner deployed | T1496 Resource Hijacking |
Two details make this a textbook traffic-analysis case rather than a log-analysis one. First, the operator stored collected output inside Kestra's own key-value interface instead of dropping files — deliberately reducing standalone artifacts on disk, which is where most detection looks. Second, the initial delivery was curl-pipe-shell: nothing lands as a file before it executes. If your detection strategy is "watch the filesystem and the application logs", this chain is built to be quiet on exactly those surfaces. What it cannot hide is the network:
- The
curl | shreaches out to attacker infrastructure — an outbound fetch from a host that normally only receives orchestration jobs. - The reverse shell holds an outbound session to an IP the appliance has never seen.
- The cryptominer opens sustained connections to a mining pool — the single most fingerprintable traffic pattern in the entire kill chain.
Each of those is a behavioural anomaly on the wire, independent of whether the host's logs were ever written or later wiped.
Why an orchestration engine is the worst thing to lose
Blast radius is the reason this deserves emergency treatment even if you think you have "just a scheduler" exposed. An orchestration platform is, by construction, a credential vault and a lateral-movement launchpad:
- It holds the secrets for everything it orchestrates — database passwords, cloud API keys, service tokens — so an attacker inside it inherits your environment's credentials without touching a secrets manager directly.
- It is designed to reach into the rest of your network to run tasks, so egress and internal connectivity are already provisioned for it.
- It runs arbitrary code as its normal function, so malicious code does not look categorically different from legitimate workflow execution.
Kestra's own recent history underlines that this is a class problem, not a one-off: the same platform previously carried CVE-2026-34612 (SQL injection to RCE prior to 1.3.7) and further authentication issues addressed through 1.3.24. If you run it exposed, treat the API surface as a standing risk, not a settled one.
Remediation
A complete runbook for CVE-2026-49869 (and its twin CVE-2026-53576, which you patch in the same step).
1. Am I affected?
Check your running version. Affected ranges are < 1.0.45 and ≥ 1.1.0, < 1.3.21.
# Version banner from the API (adjust host/port)
curl -s http://KESTRA_HOST:8080/api/v1/version || \
docker inspect --format '{{ index .Config.Labels "org.opencontainers.image.version" }}' <kestra_container>
# Is the API reachable from outside your trust boundary? (it should not be)
curl -s -o /dev/null -w '%{http_code}\n' http://KESTRA_HOST:8080/api/v1/configs
Any Kestra instance whose API is reachable from an untrusted network and is below the fixed version is exploitable without credentials. Assume exposed = compromised until you have hunted (step 4).
2. Patch — exact fixed versions
Upgrade to 1.0.45 (1.0.x line) or 1.3.21 (1.3.x line) or later, per the Kestra security advisories and the CVE record. These releases replace the suffix/prefix matching in the auth filter with exact-path checks and close both CVE-2026-49869 and CVE-2026-53576. This is the only real fix — everything below buys time, not safety.
3. Can't patch now? Compensating controls
- Do not expose the Kestra API to the internet. Put it behind a reverse proxy or VPN and restrict to known admin sources. This alone removes the unauthenticated-remote precondition.
- Add an exact-path allowlist at the proxy. Because the bug is suffix matching, block any request whose path contains
/configsbut is not exactly the intended config route, and deny path traversal / trailing-segment tricks. Normalise paths at the proxy before they reach Kestra. - Lock down egress from the worker. A pipeline runner rarely needs to initiate arbitrary outbound connections. Default-deny egress kills the
curl | sh, the reverse shell, and the mining-pool check-in in one move. - Never mount the Docker socket into the Kestra container unless a task genuinely requires it — it turns worker RCE into host takeover.
4. Hunt for compromise
Assume the window opened in June. Look on the network and in the container, not just the logs (the operator deliberately minimised disk artifacts):
- Outbound anomalies (network side): unexpected egress from the Kestra host, especially
curl/wgetto unfamiliar IPs, long-held outbound TCP sessions (reverse shell), and connections to Stratum/mining-pool endpoints — map to T1496 (Sigma: Network Communication With Crypto Mining Pool) and T1059.004 (Sigma: Suspicious Reverse Shell Command Line). - Process/host side: miner processes (high sustained CPU), shell processes parented to the Kestra worker,
curl … | shin process history. - Application side: flows you did not author, especially recently created flows containing shell/script tasks; anomalous writes to the key-value store used as a staging channel (T1074).
- Access side: any successful request to a
/configs-ending path that was not the legitimate config endpoint.
5. Eradicate and verify
- Isolate the host, kill the miner and any reverse-shell processes, remove attacker-created flows and KV entries.
- Rotate every secret Kestra could reach — database credentials, cloud keys, service tokens. Root in the worker means all of them are burned.
- Rebuild the container from a clean image rather than cleaning in place.
- Patch to 1.0.45 / 1.3.21, then re-verify: confirm the
/configs-suffix request now returns 401/403, and confirm egress default-deny is enforced. Verify after patching, not before.
Where Zero Hunt fits
The defining feature of this intrusion is that it was engineered to be quiet on disk and in logs — curl | sh with no dropped file, staging inside the application's own key-value store, root in a container whose logs the attacker could wipe. That is precisely the failure mode Zero Hunt's AI Traffic Analysis is built for. The appliance runs a proprietary deep-learning model with four parallel inference heads (suspicious traffic, malware classification, attack-type identification, application fingerprinting) over live traffic at 2.7+ Gbit/s, on the appliance GPU, with no cloud callback. It does not need the host's logs to be intact, because it reads the one surface the attacker still has to use: the wire. The outbound curl to never-seen infrastructure, the reverse-shell session, and the mining-pool check-in are all behavioural anomalies the model flags while the miner is still spinning up — not in tomorrow's SIEM digest.
The generative side closes the loop before an attacker finds the door. Zero Hunt's 10-agent swarm treats a newly exposed orchestration API as a change-triggered event: a new asset on the perimeter kicks off a full campaign within the hour, and the Exploit agent writes a per-target attempt against your actual deployment — including the exact class of suffix-matching auth bypass CVE-2026-49869 represents — validated in the AI Gym against the Vulhub-Bench corpus before it ever runs in production, with each finding ECDSA-signed for the audit trail. The point is not to tell you Kestra had a CVE; the news already did. The point is to prove, continuously, whether your instance is reachable and exploitable — and to see it on the network the moment someone else proves it for you.
CVE-2026-49869 is a one-word bug with a full-environment blast radius. Patch to 1.0.45 or 1.3.21 today, get the API off the internet, and assume anything reachable since June has been running someone else's workflows.