← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2026-28779 · CWE-668 · Disclosed 2026-03-17

Apache Airflow versions 3

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is leaving your master badge accepted at every office door in the building instead of just your own suite

The bug is not in authentication itself; it is in *where the browser sends the Airflow session cookie*. For affected Apache Airflow releases, the _token cookie is scoped to / instead of the configured base_url, so any sibling application under the same parent domain can receive it in request headers. The public records are slightly inconsistent on version bounds: the narrative description says 3.1.0 through 3.1.7, while the NVD/GitHub advisory affected-range metadata says >=3.0.0, <3.1.8; either way, 3.1.8 is the fixed release.

The vendor's *HIGH 7.5* score overrates real enterprise risk. Raw CVSS treats this like a clean unauthenticated network confidentiality issue, but the actual attack path needs a very specific topology: Airflow must share a parent domain with another app the attacker controls or has already compromised, and users must browse both. That is real and worth fixing, but it is not the same thing as an internet-drive-by Airflow takeover.

"Serious session theft impact, but only if Airflow shares a domain with another app an attacker can run or compromise."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Find a shared-domain Airflow deployment

Using ordinary recon with a browser, curl, or reverse-proxy configs, the attacker identifies an Airflow instance mounted on a shared hostname, often under a subpath such as /team-a. The flaw only matters when the deployment model gives the browser a reason to send Airflow cookies to sibling apps on that same domain.
Conditions required:
  • Airflow is on an affected release before 3.1.8
  • Airflow is reachable on a hostname that also serves other applications
  • The organization uses path-based routing or same-domain multi-app hosting
Where this breaks in practice:
  • Dedicated Airflow hostnames kill most of the risk immediately
  • Many enterprises isolate admin tooling on separate subdomains or VPN-only ingress
  • Version scanners can find Airflow, but they cannot prove the vulnerable topology
Detection/coverage: External scanners and SCA will usually detect only the package version. They will *not* validate the same-domain co-hosting prerequisite.
STEP 02

Gain control of a sibling app on the same domain

The attacker then needs a second application under that same parent domain that they operate, can configure, or have already compromised. A simple web app with access logs is enough; the goal is not code execution on Airflow, just visibility into inbound request headers where the browser will volunteer the _token cookie.
Conditions required:
  • Attacker controls or compromises another app under the same parent domain
  • Victims can browse to that sibling app
  • The sibling app can log request headers or otherwise read inbound cookies
Where this breaks in practice:
  • This is the decisive brake on severity: it usually implies prior compromise, risky multi-tenant hosting, or a self-inflicted shared-ingress design
  • NGFW/WAF do not stop a legitimate browser from sending cookies to a same-domain sibling path
  • If no untrusted sibling app exists, there is no theft path
Detection/coverage: Look for unusual Cookie: headers containing Airflow _token values in non-Airflow application logs. Most vuln scanners miss this completely.
STEP 03

Harvest the session token from normal victim traffic

Once a user authenticates to Airflow, the browser stores _token with path /. When that same browser visits the sibling app, it includes the Airflow cookie in the request automatically, and the sibling app can capture it from headers without touching Airflow directly.
Conditions required:
  • A valid Airflow user session exists
  • Victim browses to the sibling app after login
  • Cookie scope remains / instead of the intended Airflow base path
Where this breaks in practice:
  • Short session lifetimes reduce the value of stolen cookies
  • User behavior matters; if users never hit the sibling app, no token is exposed
  • Some deployments may already run at /, where the intended path narrowing benefit is absent
Detection/coverage: Proxy and application access logs can reveal cross-app cookie leakage, but only if header logging is enabled and reviewed carefully.
STEP 04

Replay the token for Airflow session takeover

The attacker reuses the stolen _token with a browser extension, Burp Suite, or curl against the Airflow UI or API and inherits the victim's session. Impact can be full session takeover, including admin actions, but only within the victim's Airflow privileges.
Conditions required:
  • Captured token is still valid
  • Airflow accepts the replayed session token
  • Victim account has meaningful Airflow permissions
Where this breaks in practice:
  • MFA helps at login, but not after a bearer-style session cookie is stolen
  • Blast radius is limited to the stolen user's Airflow role, not blanket infrastructure compromise
  • Session invalidation or restart after upgrade can burn captured tokens
Detection/coverage: Session replay may show new IPs, user agents, or geography for the same Airflow session, but many Airflow deployments lack that level of session analytics.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo public exploitation evidence in the cited sources. This CVE is *not* presented as exploited by CISA KEV, and the reviewed advisories do not mention active campaigns.
Proof-of-concept availabilityNo stand-alone exploit repo surfaced in the reviewed sources, but the bug is trivial to reproduce from the vendor fix discussion in PR #62771. This is a *low-complexity abuse pattern*, not a specialized exploit chain.
EPSS0.031% and 9th percentile per the GitHub advisory, which is consistent with a niche, topology-dependent issue rather than a broad internet exploitation wave.
KEV statusNot listed in the CISA Known Exploited Vulnerabilities catalog. That removes the strongest urgency signal.
CVSS vector reality checkCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N scores it like a clean remote confidentiality loss. In practice, the *real* prerequisite is same-domain sibling-app control, which CVSS does not model well.
Affected versionsThere is an advisory mismatch: the description text in NVD and GHSA says 3.1.0 through 3.1.7, while their affected-version metadata says >=3.0.0, <3.1.8. Treat anything before 3.1.8 as suspect until your package inventory proves otherwise.
Fixed versionsVendor fix shipped in 3.1.8, documented in the Airflow 3.1.8 release notes and the GitHub advisory. I did not find distro backport guidance in the reviewed sources.
Topology prerequisiteThe vendor patch text is explicit: the bug matters because the cookie is sent to *other applications that run under the same domain*; see PR #62771 and the Openwall disclosure. That is the main downward pressure on severity.
Scanning / exposure dataNo reliable public GreyNoise/Censys/Shodan count in the reviewed sources isolates *this* issue. *Inference:* internet exposure alone is a poor proxy because the decisive condition is shared-domain co-hosting, which external scanners usually cannot fingerprint.
Disclosure and creditDisclosed on 2026-03-17. Openwall credits Daniel Wolf as finder and remediation developer.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (5.3/10)

The decisive factor is that exploitation normally requires control of a *different* application on the same parent domain, which is a major real-world narrowing of the reachable population. Impact after theft is real session takeover, but this is mostly a shared-hosting and post-compromise amplifier, not an internet-scale initial access bug.

HIGH Fixed release and advisory facts
MEDIUM Practical exploitability across real enterprise topologies
MEDIUM Absence of public active-exploitation reporting

Why this verdict

  • Downgraded for attacker position: the attacker usually needs control of a sibling app on the same domain, which implies prior compromise, risky multi-tenant hosting, or an internal/shared platform design.
  • Downgraded for exposed population: only Airflow deployments sharing a parent domain with other reachable apps are meaningfully exposed; dedicated hostnames make the bug mostly irrelevant.
  • Kept at MEDIUM for impact: if the prerequisite is met, the attacker can steal a live Airflow session and inherit the victim's privileges with no need to attack Airflow directly.
  • Downgraded for threat intel: EPSS is extremely low, there is no KEV entry, and the reviewed sources do not describe active campaigns.
  • Notably, even the disclosure mail says Severity: Medium: that lines up better with real operator risk than the 7.5 CVSS label.

Why not higher?

This is not a straightforward unauthenticated remote compromise of Airflow. The exploit chain depends on same-domain co-hosting and a second app the attacker can run or compromise, which dramatically cuts both the exposed population and the likelihood of internet-scale abuse. There is also no public exploitation evidence pushing this into emergency territory.

Why not lower?

Once the prerequisite exists, the impact is not cosmetic; it is full Airflow session hijack. In organizations where platform teams multiplex admin apps behind one shared ingress, this can become a meaningful lateral-movement shortcut, especially against privileged Airflow users.

05 · Compensating Control

What to do — in priority order.

  1. Move Airflow to a dedicated hostname — Stop sharing the parent domain with unrelated applications so the browser never has a sibling app to send the Airflow cookie to. For a MEDIUM verdict there is no mitigation SLA, but this is the cleanest architectural fix to schedule before or alongside the upgrade and complete within the 365-day remediation window.
  2. Eliminate path-based multi-app co-hosting for admin tools — If Airflow is mounted at /team-a, /airflow, or similar behind a shared reverse proxy, split it onto its own DNS name or trust boundary. There is no mitigation SLA for MEDIUM, so do this in the next normal change cycle rather than as an emergency block.
  3. Reduce session lifetime and invalidate old sessions after upgrade — Short-lived sessions reduce the usable window for stolen _token values, and forced re-authentication burns any previously harvested cookies after you patch. For MEDIUM, handle this during standard ops change management and finish actual remediation within 365 days.
  4. Review sibling-app logging for inbound cookies — Check same-domain app and reverse-proxy logs for unexpected Airflow _token cookies landing outside Airflow paths. This is detection-heavy rather than preventive, and for MEDIUM it belongs in the next routine detection engineering sprint.
What doesn't work
  • A WAF does not fix this; the browser is legitimately sending the cookie to a same-domain sibling app, so there is no obvious attack payload to block.
  • MFA does not save you after the token is stolen; session replay happens *after* authentication.
  • TLS everywhere is still necessary, but it does not address the core flaw because the leak occurs in normal HTTPS requests to another app under the same domain.
06 · Verification

Crowdsourced verification payload.

Run this on the Airflow host, container, or image build pipeline where apache-airflow is installed. Invoke it as python3 check_cve_2026_28779.py /etc/airflow/airflow.cfg; no admin rights are required unless the config file is root-readable only. The script checks the installed Airflow version and the configured AIRFLOW__WEBSERVER__BASE_URL / AIRFLOW__API__BASE_URL or values from airflow.cfg, then prints VULNERABLE, PATCHED, or UNKNOWN.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# check_cve_2026_28779.py
# Detect likely exposure to CVE-2026-28779 on an Airflow node/container.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

import configparser
import os
import sys
from urllib.parse import urlparse

try:
    from importlib import metadata as importlib_metadata
except Exception:
    import importlib_metadata  # type: ignore


def parse_version(v):
    parts = []
    for token in str(v).split('.'):
        num = ''
        for ch in token:
            if ch.isdigit():
                num += ch
            else:
                break
        parts.append(int(num) if num else 0)
    while len(parts) < 3:
        parts.append(0)
    return tuple(parts[:3])


def version_in_range(v, low_incl, high_excl):
    return parse_version(low_incl) <= parse_version(v) < parse_version(high_excl)


def get_installed_version():
    candidates = ['apache-airflow', 'apache_airflow']
    for name in candidates:
        try:
            return importlib_metadata.version(name)
        except Exception:
            continue
    return None


def read_cfg(path):
    data = {}
    if not path or not os.path.isfile(path):
        return data
    cp = configparser.ConfigParser()
    try:
        cp.read(path)
    except Exception:
        return data
    if cp.has_section('webserver') and cp.has_option('webserver', 'base_url'):
        data['webserver_base_url'] = cp.get('webserver', 'base_url').strip()
    if cp.has_section('api') and cp.has_option('api', 'base_url'):
        data['api_base_url'] = cp.get('api', 'base_url').strip()
    return data


def path_from_url(value):
    if not value:
        return None
    try:
        parsed = urlparse(value)
        path = parsed.path or '/'
        return path
    except Exception:
        return None


def non_root_path(value):
    p = path_from_url(value)
    if p is None:
        return False
    return p not in ('', '/')


def main():
    cfg_path = sys.argv[1] if len(sys.argv) > 1 else os.environ.get('AIRFLOW_CONFIG') or '/etc/airflow/airflow.cfg'
    version = get_installed_version()
    if not version:
        print('UNKNOWN - apache-airflow package version not found')
        sys.exit(2)

    cfg = read_cfg(cfg_path)
    web_base = os.environ.get('AIRFLOW__WEBSERVER__BASE_URL') or cfg.get('webserver_base_url')
    api_base = os.environ.get('AIRFLOW__API__BASE_URL') or cfg.get('api_base_url')

    affected = version_in_range(version, '3.0.0', '3.1.8')
    fixed = parse_version(version) >= parse_version('3.1.8')

    if fixed:
        print(f'PATCHED - apache-airflow {version} >= 3.1.8')
        sys.exit(0)

    if not affected:
        print(f'UNKNOWN - apache-airflow {version} is outside the published affected range used by this check')
        sys.exit(2)

    # Practical exposure check: bug matters when Airflow is intended to live under a subpath.
    web_non_root = non_root_path(web_base)
    api_non_root = non_root_path(api_base)

    if web_non_root or api_non_root:
        details = []
        if web_non_root:
            details.append(f'webserver.base_url={web_base}')
        if api_non_root:
            details.append(f'api.base_url={api_base}')
        print('VULNERABLE - apache-airflow {} with non-root base URL(s): {}'.format(version, ', '.join(details)))
        sys.exit(1)

    if web_base or api_base:
        print('UNKNOWN - apache-airflow {} is in affected versions, but configured base URLs appear root-scoped; validate shared-domain co-hosting manually'.format(version))
        sys.exit(2)

    print('UNKNOWN - apache-airflow {} is in affected versions, but base_url settings were not found; inspect AIRFLOW__WEBSERVER__BASE_URL, AIRFLOW__API__BASE_URL, and reverse-proxy topology manually'.format(version))
    sys.exit(2)


if __name__ == '__main__':
    main()
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, do not treat this like an internet-fire RCE. First, inventory Airflow deployments before 3.1.8 and separate the ones on *dedicated hostnames* from the ones sharing a parent domain with other apps or mounted on subpaths; the latter are your real risk set. Because this lands at MEDIUM, there is no noisgate mitigation SLA — go straight to the 365-day remediation window for the actual upgrade, but if you knowingly share a domain across admin tools, fix that design in the next normal change cycle and complete the vendor patch to 3.1.8+ within the noisgate remediation SLA of 365 days.

Sources

  1. NVD CVE record
  2. GitHub Advisory GHSA-4fhm-p86v-hwpx
  3. Apache Airflow fix PR #62771
  4. Apache Airflow releases
  5. Openwall disclosure mail
  6. Airflow configuration reference
  7. CISA Known Exploited Vulnerabilities catalog
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.