Apache Airflow FAB provider: LDAP Filter Injection in FAB Auth Manager _search_ldap reachable via /auth/token
Description
Apache Airflow FAB Auth Manager contains an LDAP filter injection vulnerability (CWE-90) that allows unauthenticated attackers to exfiltrate directory data or bypass authentication. Upgrade to apache-airflow-providers-fab 3.6.4 or later. If immediate upgrade is not possible, disable LDAP authentication until the provider can be updated.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Apache Airflow FAB Auth Manager LDAP filter injection allows unauthenticated attackers to exfiltrate directory data or bypass authentication.
Vulnerability
Apache Airflow's FAB Auth Manager contains an LDAP filter injection vulnerability (CWE-90) in the LDAP authentication handler. An unauthenticated attacker can inject arbitrary LDAP filters by crafting malicious input to the authentication endpoint. This affects all versions of apache-airflow-providers-fab prior to 3.6.4. The vulnerability is present when LDAP authentication is enabled.
Exploitation
An attacker with network access to an Airflow instance that has LDAP authentication enabled can send specially crafted authentication requests. By injecting LDAP filter syntax into the username or other fields, the attacker can manipulate the LDAP query to either bypass authentication entirely or extract sensitive directory information. No prior authentication or special privileges are required.
Impact
Successful exploitation allows an unauthenticated attacker to bypass authentication and gain unauthorized access to the Airflow web interface, potentially with administrative privileges. Additionally, the attacker can exfiltrate data from the LDAP directory, including user credentials and other sensitive information. This compromises the confidentiality and integrity of the Airflow deployment and the underlying directory service.
Mitigation
The vulnerability is fixed in apache-airflow-providers-fab version 3.6.4 and later. Users should upgrade immediately. If an immediate upgrade is not possible, disable LDAP authentication as a workaround until the provider can be updated. The fix is implemented in pull request [1].
AI Insight generated on May 25, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2- Range: <3.6.4
- Range: <3.6.4
Patches
13f7756bea71afix: the ldap authentication handler in the flask-ap... in override.py (#66417)
1 file changed · +18 −9
providers/fab/src/airflow/providers/fab/auth_manager/security_manager/override.py+18 −9 modified@@ -17,16 +17,17 @@ # under the License. from __future__ import annotations +import base64 import copy import datetime import importlib import itertools +import json import logging import uuid from collections.abc import Collection, Iterable, Mapping from typing import TYPE_CHECKING, Any -import jwt from flask import current_app, flash, g, has_app_context, has_request_context, session from flask_appbuilder import Model, const from flask_appbuilder.const import ( @@ -411,8 +412,6 @@ def _validate_jwt(self, id_token, jwks): return claims def _get_authentik_token_info(self, id_token): - me = jwt.decode(id_token, options={"verify_signature": False}) - verify_signature = self.oauth_remotes["authentik"].client_kwargs.get("verify_signature", True) if verify_signature: # Validate the token using authentik certificate @@ -426,7 +425,9 @@ def _get_authentik_token_info(self, id_token): else: # Return the token info without validating log.warning("JWT token is not validated!") - return me + _parts = id_token.split(".") + _payload = _parts[1] + "=" * (-len(_parts[1]) % 4) + return json.loads(base64.urlsafe_b64decode(_payload)) raise FabException("OAuth signature verify failed") @@ -1453,7 +1454,7 @@ def add_register_user( register_user.password = hashed_password else: register_user.password = self._hash_password(password) - register_user.registration_hash = str(uuid.uuid1()) + register_user.registration_hash = str(uuid.uuid4()) try: self.session.add(register_user) self.session.commit() @@ -2383,7 +2384,9 @@ def _decode_and_validate_azure_jwt(self, id_token: str) -> dict[str, str]: claims.validate() return claims - return jwt.decode(id_token, options={"verify_signature": False}) + _parts = id_token.split(".") + _payload = _parts[1] + "=" * (-len(_parts[1]) % 4) + return json.loads(base64.urlsafe_b64decode(_payload)) def _ldap_bind_indirect(self, ldap, con) -> None: """ @@ -2418,10 +2421,12 @@ def _search_ldap(self, ldap, con, username): raise ValueError("AUTH_LDAP_SEARCH must be set") # build the filter string for the LDAP search + # escape username to prevent LDAP injection attacks + escaped_username = ldap.filter.escape_filter_chars(username) if self.auth_ldap_search_filter: - filter_str = f"(&{self.auth_ldap_search_filter}({self.auth_ldap_uid_field}={username}))" + filter_str = f"(&{self.auth_ldap_search_filter}({self.auth_ldap_uid_field}={escaped_username}))" else: - filter_str = f"({self.auth_ldap_uid_field}={username})" + filter_str = f"({self.auth_ldap_uid_field}={escaped_username})" # build what fields to request in the LDAP search request_fields = [ @@ -2491,7 +2496,11 @@ def _ldap_get_nested_groups(self, ldap, con, user_dn) -> list[str]: """ log.debug("Nested groups for LDAP enabled.") # filter for microsoft active directory only - nested_groups_filter_str = f"(&(objectCategory=Group)(member:1.2.840.113556.1.4.1941:={user_dn}))" + # escape user_dn to prevent LDAP injection attacks + escaped_user_dn = ldap.filter.escape_filter_chars(user_dn) + nested_groups_filter_str = ( + "(&(objectCategory=Group)(member:1.2.840.113556.1.4.1941:=" + escaped_user_dn + "))" + ) nested_groups_request_fields = ["cn"] nested_groups_search_result = con.search_s(
Vulnerability mechanics
Synthesis attempt was rejected by the grounding validator. Re-run pending.
References
2- github.com/apache/airflow/pull/66417mitrepatch
- lists.apache.org/thread/dvfy0bs181xwsrjrd3y5c55ztbzm8yhhmitrevendor-advisory
News mentions
0No linked articles in our index yet.