# Apache Airflow CeleryExecutor Unauthenticated RCE via Forged Broker Callback (CVE-2026-68982)

> A missing-authentication flaw (CWE-306) in Apache Airflow before 3.4.0 using CeleryExecutor lets anyone with write access to the Celery broker forge an ExecuteCallback message and make a worker run any importable Python function, with no Airflow credentials. A proof of concept is published; in-the-wild exploitation is not reported.

- **Published:** 2026-11-10T12:01:17Z
- **Last reviewed:** 2026-11-11T01:03:14.307Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-5642
- **ID:** TL-2026-5642
- **Severity:** CRITICAL (CVSS 9.8)
- **Category:** VULNERABILITY
- **Status:** ACTIVE
- **Detections:** 9 (1 shown free below) · **IOCs:** 15
- **CVEs:** CVE-2026-68982

## Description

CVE-2026-68982 affects Apache Airflow deployments before 3.4.0 that use CeleryExecutor. Airflow's web UI and REST API reject unauthenticated users, and ExecuteTask workloads delivered through the Celery broker carry a signed token that the Execution API validates. ExecuteCallback workloads travel over the same broker and the same execute_workload Celery task, but no token check occurs before the callback runs. ExecuteCallback was introduced for synchronous Deadline Alert callbacks.

The execute_workload task converts any JSON body received from the broker into a typed workload object, with no signature, HMAC or broker-side access control. In the analysed versions the callback token is never verified: execute_callback_workload() in 3.2.1 and supervise_callback() / CallbackSubprocess in 3.3.0. The worker reads the function path and kwargs from the message, loads the function with import_module and getattr, and calls it immediately, so any importable module is reachable. Per the researcher, the handler registers on every CeleryExecutor worker once the Celery provider loads, even where Deadline Alerts are not used, although the feature is documented as experimental.

Proof of concept (as described by GBHackers and Reflectiz): the attacker forges a workload of type ExecuteCallback with an empty token and a callback path of os.system with a benign test command (touch /tmp/pwned_by_broker_callback), and submits it with Celery send_task('execute_workload', ...) to a Redis broker. No JWT, DAG, DagRun or scheduler is needed; in the lab the Airflow API showed zero DAGs, DagRuns and TaskInstances afterwards, so UI/API-based monitoring will not reveal the activity. The lab used Docker Compose with CeleryExecutor, Redis and PostgreSQL, on Airflow 3.2.1 and 3.3.0.

Precondition: the attacker must be able to write to the Celery broker (for example an unauthenticated or internet-exposed Redis on 6379 or RabbitMQ on 5672, or a network foothold with broker access). LocalExecutor and KubernetesExecutor are reported as out of scope.

The fix shipped in Airflow 3.4.0 (released 2026-11-06, PR apache/airflow#71192): the executor mints a callback-scoped, single-use token bound to the callback ID, and the worker redeems it with the API server (PATCH /callbacks/{callback_id}/run) before running the callback. The call atomically moves the callback from QUEUED to RUNNING, so replayed or forged messages for a callback that is already running or finished are refused (409). Both the Execution API server and every CeleryExecutor worker must be upgraded. Apache rates the issue 'Important' and had published no CVSS score at the time of the Reflectiz post; the 9.8 CVSS v3.1 score and vector below are Reflectiz's assessment. No in-the-wild exploitation is reported in the sources reviewed.

## MITRE ATT&CK

- T1190 Exploit Public-Facing Application
- T1059.006 Python
- T1059.004 Unix Shell
- T1106 Native API
- T1082 System Information Discovery
- T1552 Unsecured Credentials
- T1005 Data from Local System

## Free detection (Splunk SPL, Microsoft KQL, Sigma)

**CVE-2026-68982 Airflow Worker Context Downloader / Reverse Shell / Staging - Post-Exploitation (SPL)** (`TL-2026-5642-SPL-002`)

Detects downloader, reverse shell, base64 decode and payload staging command lines (curl/wget piped to a shell or written to /tmp, /dev/tcp, nc -e, bash -i, mkfifo, base64 -d, python socket one-liners, chmod of files in /tmp) executed as the Airflow service account or under a Celery worker. Covers follow-on activity after a forged ExecuteCallback achieves code execution (CVE-2026-68982, TL-2026-5642), where real attacks substitute arbitrary commands for the PoC touch command.

- **Languages:** Splunk SPL, Microsoft KQL, Sigma
- **ATT&CK:** T1059.004, T1059.006, T1105, T1095, T1140, T1222.002
- **Data sources:** sysmon_for_linux, linux_process_creation, defender_for_endpoint_linux
- **Severity:** high
- **Confidence:** medium

### Splunk SPL

````spl
index=linux sourcetype="sysmon:linux" EventCode=1 (User="airflow" OR ParentCommandLine="*celery*worker*" OR ParentCommandLine="*execute_workload*")
```TL-2026-5642 / CVE-2026-68982 post-exploitation: downloader (T1105), reverse shell (T1095), decode (T1140) or chmod staging (T1222.002) in the Airflow worker context```
| where match(CommandLine,"(?i)((curl|wget) [^|]*[|] *(ba|da|z)?sh|(curl|wget) .*(-o|-O|--output) +/(tmp|dev/shm|var/tmp)/|/dev/tcp/|nc +-[ec] |ncat .*(-e|--exec)|bash +-i|mkfifo|base64 +(-d|--decode)|python[0-9.]* +-c .*socket|chmod +[+]?[0-7ax]+ +/(tmp|dev/shm|var/tmp)/)")
| eval technique=case(match(CommandLine,"(?i)(curl|wget)"),"T1105 ingress tool transfer",match(CommandLine,"(?i)(/dev/tcp/|nc +-[ec] |ncat|bash +-i|mkfifo|socket)"),"T1095 non-application layer protocol",match(CommandLine,"(?i)base64"),"T1140 deobfuscate decode",match(CommandLine,"(?i)chmod"),"T1222.002 linux file permissions",true(),"other")
| stats count min(_time) as first_seen max(_time) as last_seen values(CommandLine) as suspicious_commands values(ParentCommandLine) as parent_cmdline values(technique) as technique by host, User, Image
| convert ctime(first_seen) ctime(last_seen)
| table first_seen last_seen host User Image technique suspicious_commands parent_cmdline count
````

### Microsoft KQL

```kql
DeviceProcessEvents
| where Timestamp > ago(24h)
| where AccountName =~ 'airflow' or (InitiatingProcessCommandLine has 'celery' and InitiatingProcessCommandLine has 'worker')
| where ProcessCommandLine matches regex @'(?i)((curl|wget) [^|]*[|] *(ba|da|z)?sh|(curl|wget) .*(-o|-O|--output) +/(tmp|dev/shm|var/tmp)/|/dev/tcp/|nc +-[ec] |ncat .*(-e|--exec)|bash +-i|mkfifo|base64 +(-d|--decode)|python[0-9.]* +-c .*socket|chmod +[+]?[0-7ax]+ +/(tmp|dev/shm|var/tmp)/)'
| extend Technique = case(
    ProcessCommandLine matches regex @'(?i)(curl|wget)', 'T1105 Ingress Tool Transfer',
    ProcessCommandLine matches regex @'(?i)(/dev/tcp/|nc +-[ec] |ncat|bash +-i|mkfifo|socket)', 'T1095 Non-Application Layer Protocol',
    ProcessCommandLine has 'base64', 'T1140 Deobfuscate/Decode Files',
    ProcessCommandLine has 'chmod', 'T1222.002 Linux File Permissions Modification',
    'Other')
| project Timestamp, DeviceName, AccountName, FileName, Technique, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by Timestamp desc
```

### Sigma

```yaml
title: Airflow Worker Context Downloader or Reverse Shell - CVE-2026-68982 Post-Exploitation
id: 8c2f4a19-6d7b-4e35-b0a1-9f3e5d7c1a02
status: experimental
description: Detects downloader, reverse shell, base64 decode and chmod staging command lines run as the Airflow account or under a Celery worker, the follow-on activity after a forged ExecuteCallback gives code execution (CVE-2026-68982, TL-2026-5642).
references:
    - https://www.reflectiz.com/blog/apache-airflow-cve-2026-68982/
    - https://www.cve.org/CVERecord?id=CVE-2026-68982
author: Threadlinqs Team
date: 2026-11-10
tags:
    - attack.execution
    - attack.t1059.004
    - attack.t1059.006
    - attack.command-and-control
    - attack.t1105
    - attack.t1095
    - attack.defense-evasion
    - attack.t1140
    - attack.t1222.002
    - cve.2026-68982
logsource:
    category: process_creation
    product: linux
detection:
    selection_context_user:
        User: 'airflow'
    selection_context_parent:
        ParentCommandLine|contains|all:
            - 'celery'
            - 'worker'
    payload_download_pipe:
        CommandLine|re: '(?i)(curl|wget) [^|]*[|] *(ba|da|z)?sh'
    payload_download_stage:
        CommandLine|re: '(?i)(curl|wget) .*(-o|-O|--output) +/(tmp|dev/shm|var/tmp)/'
    payload_reverse_shell:
        CommandLine|contains:
            - '/dev/tcp/'
            - 'bash -i'
            - 'mkfifo'
            - 'nc -e '
            - 'ncat --exec'
    payload_decode:
        CommandLine|contains:
            - 'base64 -d'
            - 'base64 --decode'
    payload_staging:
        CommandLine|re: '(?i)chmod +[+]?[0-7ax]+ +/(tmp|dev/shm|var/tmp)/'
    condition: 1 of selection_context_* and 1 of payload_*
falsepositives:
    - DAGs that legitimately download artifacts with curl or wget and pipe them to a shell
    - Administrators troubleshooting from the airflow account
level: high
```

**Known false positives:**

- DAGs that legitimately fetch installers or artifacts with curl/wget and pipe them to a shell
- Administrators troubleshooting interactively as the airflow service account

**Tuning notes:** Change the service account name (airflow) to match your deployment. Allow-list known DAG download commands by exact CommandLine. Narrow to worker hosts only. Process creation only exposes the direct parent, so descendants of the shell are caught through the service-account match rather than lineage.

### 8 more detection rules (Splunk SPL, Microsoft KQL, Sigma), unlock with TL Creds

- CVE-2026-68982 Airflow Celery Worker Spawns Shell via Forged ExecuteCallback - Exploitation (KQL) (locked: unlock with TL Creds)
- CVE-2026-68982 Airflow Worker Context Downloader / Reverse Shell / Staging - Post-Exploitation (KQL) (locked: unlock with TL Creds)
- CVE-2026-68982 Celery Broker (Redis 6379 / RabbitMQ 5672) Reached From Untrusted Host - C2 / Lateral Movement (KQL) (locked: unlock with TL Creds)
- CVE-2026-68982 Airflow Celery Worker Spawns Shell via Forged ExecuteCallback - Exploitation (Sigma) (locked: unlock with TL Creds)
- CVE-2026-68982 Airflow Worker Context Downloader / Reverse Shell / Staging - Post-Exploitation (Sigma) (locked: unlock with TL Creds)
- CVE-2026-68982 Celery Broker (Redis 6379 / RabbitMQ 5672) Reached From Untrusted Host - C2 / Lateral Movement (Sigma) (locked: unlock with TL Creds)
- CVE-2026-68982 Airflow Celery Worker Spawns Shell via Forged ExecuteCallback - Exploitation (SPL) (locked: unlock with TL Creds)
- CVE-2026-68982 Celery Broker (Redis 6379 / RabbitMQ 5672) Reached From Untrusted Host - C2 / Lateral Movement (SPL) (locked: unlock with TL Creds)

Sign up free to unlock the detection rules: https://threadlinqs.com/?modal=signup

## Sources

- [Critical Apache Airflow Flaw CVE-2026-68982 Enables Unauthenticated Remote Code Execution (GBHackers)](https://gbhackers.com/critical-apache-airflow-flaw-cve-2026-68982-enables-unauthenticated-remote-code-execution/)
- [Reflectiz: Apache Airflow CVE-2026-68982 (Or Sahar)](https://www.reflectiz.com/blog/apache-airflow-cve-2026-68982/)
- [CVE-2026-68982 CVE Record](https://www.cve.org/CVERecord?id=CVE-2026-68982)
- [Apache Airflow security advisory (dev mailing list thread)](https://lists.apache.org/thread/7t514l87nhjworv2ns22b8ltxr1f7rhg)
- [Apache Airflow 3.4.0 Release Notes](https://airflow.apache.org/docs/apache-airflow/3.4.0/release_notes.html)
- [apache/airflow PR #71192: single-use callback token for deadline callbacks](https://github.com/apache/airflow/pull/71192)

## Full data

The other 8 detection rules (Splunk SPL / Microsoft KQL / Sigma) unlock with TL Creds; a free account includes daily creds: https://threadlinqs.com/?modal=signup
Indicator values unlock with TL Creds, at a lower price on Red and Purple; AI agents can query rules and IOCs through the Threadlinqs MCP server (Purple): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-5642
