This is an automated email from the ASF dual-hosted git repository.

vincbeck pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 1100afbec5c Reserve /auth and /pluginsv2 from plugin url_prefix 
(#66501)
1100afbec5c is described below

commit 1100afbec5c4daa60670ebd9ba47ded55c14dd88
Author: Jarek Potiuk <[email protected]>
AuthorDate: Thu May 7 16:07:24 2026 +0200

    Reserve /auth and /pluginsv2 from plugin url_prefix (#66501)
    
    The framework mounts the auth-manager subapp under /auth and the FAB
    plugin shim under /pluginsv2, but RESERVED_URL_PREFIXES only listed
    /api/v2, /ui, and /execution. A trusted plugin attempting to mount under
    either of the missing prefixes was accepted and (because plugin init runs
    before the auth-manager mount) would shadow the auth routes.
    
    Plugins are trusted code per Airflow's security model so this is
    defense-in-depth, not a vulnerability — but accidental collisions with
    the auth-manager / Flask-plugins mount points should be caught and
    logged like the other reserved prefixes.
---
 airflow-core/src/airflow/api_fastapi/app.py     |  2 +-
 airflow-core/tests/unit/api_fastapi/test_app.py | 19 ++++++-------------
 2 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/airflow-core/src/airflow/api_fastapi/app.py 
b/airflow-core/src/airflow/api_fastapi/app.py
index 86ba79f7a06..8931840c880 100644
--- a/airflow-core/src/airflow/api_fastapi/app.py
+++ b/airflow-core/src/airflow/api_fastapi/app.py
@@ -61,7 +61,7 @@ def get_cookie_path() -> str:
 
 
 # Fast API apps mounted under these prefixes are not allowed
-RESERVED_URL_PREFIXES = ["/api/v2", "/ui", "/execution"]
+RESERVED_URL_PREFIXES = ["/api/v2", "/ui", "/execution", "/auth", "/pluginsv2"]
 
 log = logging.getLogger(__name__)
 
diff --git a/airflow-core/tests/unit/api_fastapi/test_app.py 
b/airflow-core/tests/unit/api_fastapi/test_app.py
index 130247f60c0..1e8817ef243 100644
--- a/airflow-core/tests/unit/api_fastapi/test_app.py
+++ b/airflow-core/tests/unit/api_fastapi/test_app.py
@@ -98,27 +98,20 @@ def test_catch_all_route_last(client):
 
 
 @pytest.mark.parametrize(
-    ("fastapi_apps", "expected_message", "invalid_path"),
+    ("invalid_prefix", "expected_message"),
     [
-        (
-            [{"name": "test", "app": FastAPI(), "url_prefix": ""}],
-            "'url_prefix' key is empty string for the fastapi app: test",
-            "",
-        ),
-        (
-            [{"name": "test", "app": FastAPI(), "url_prefix": 
next(iter(app_module.RESERVED_URL_PREFIXES))}],
-            "attempted to use reserved url_prefix",
-            next(iter(app_module.RESERVED_URL_PREFIXES)),
-        ),
+        ("", "'url_prefix' key is empty string for the fastapi app: test"),
+        *((prefix, "attempted to use reserved url_prefix") for prefix in 
app_module.RESERVED_URL_PREFIXES),
     ],
 )
-def test_plugin_with_invalid_url_prefix(caplog, fastapi_apps, 
expected_message, invalid_path):
+def test_plugin_with_invalid_url_prefix(caplog, invalid_prefix, 
expected_message):
+    fastapi_apps = [{"name": "test", "app": FastAPI(), "url_prefix": 
invalid_prefix}]
     app = FastAPI()
     with mock.patch.object(plugins_manager, "get_fastapi_plugins", 
return_value=(fastapi_apps, [])):
         app_module.init_plugins(app)
 
     assert any(expected_message in rec.message for rec in caplog.records)
-    assert not any(r.path == invalid_path for r in app.routes)
+    assert not any(r.path == invalid_prefix for r in app.routes)
 
 
 class TestGetCookiePath:

Reply via email to