VYPR
Moderate severityNVD Advisory· Published Oct 30, 2025· Updated Feb 26, 2026

Apache Airflow: Airflow 3 API: /api/v2/dagReports executes DAG Python in API

CVE-2025-62402

Description

API users via /api/v2/dagReports could perform Dag code execution in the context of the api-server if the api-server was deployed in the environment where Dag files were available.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

"/api/v2/dagReports" endpoint in Apache Airflow allowed remote API users to execute arbitrary DAG code in the API server process if DAG files were accessible.

Vulnerability

Overview

The vulnerability resides in the /api/v2/dagReports REST API endpoint of Apache Airflow. When invoked, the endpoint loads user-defined DAG files directly into the API server's process using the DagBag class [3]. This violates Airflow's fundamental security architecture, which mandates that the API server must never execute untrusted user code [3]. The root cause is that the endpoint performed code execution of DAG files in the same process context as the API server.

Exploitation

Conditions

Exploitation requires an authenticated API user to have access to the /api/v2/dagReports endpoint. The attacker must also be able to provide or influence DAG files that are already available in the environment where the API server is running [1]. The endpoint loads these files as Python code, meaning any malicious code embedded in a DAG file would execute in the API server's process. Note that the endpoint was not used by the Airflow UI and had no known consumers [3].

Impact

A successful attack results in arbitrary code execution in the context of the API server process. This gives the attacker the same privileges as the API server, potentially allowing full control over the Airflow deployment, including access to databases, secrets, and the ability to manipulate workflows.

Mitigation

The fix involves removing the dagReports API endpoint entirely [3]. The commit (828aaa0) [4] removes the endpoint and the associated service from the API. Users who require DAG loading reports should use the airflow dags report CLI command, which runs in an isolated process designed to safely execute user code [3]. Administrators should apply the update that includes this fix to eliminate the vulnerability.

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
apache-airflowPyPI
>= 3.0.0, < 3.1.13.1.1

Affected products

1
  • Apache Software Foundation/Apache Airflowv5
    Range: 3.0.0

Patches

1
828aaa0b1d95

Remove ``dagReports`` API endpoint (#56609)

https://github.com/apache/airflowKaxil NaikOct 14, 2025via ghsa
13 files changed · +20 415
  • airflow-core/newsfragments/56609.significant.rst+14 0 added
    @@ -0,0 +1,14 @@
    +Remove insecure dagReports API endpoint that executed user code in API server
    +
    +The ``/api/v2/dagReports`` endpoint has been removed because it loaded user DAG files directly in the API server process, violating Airflow's security architecture. This endpoint was not used in the UI and had no known consumers. Use the ``airflow dags report`` CLI command instead for DAG loading reports.
    +
    +* Types of change
    +
    +  * [ ] Dag changes
    +  * [ ] Config changes
    +  * [x] API changes
    +  * [ ] CLI changes
    +  * [ ] Behaviour changes
    +  * [ ] Plugin changes
    +  * [ ] Dependency changes
    +  * [ ] Code interface changes
    
  • airflow-core/src/airflow/api_fastapi/core_api/datamodels/dag_report.py+0 40 removed
    @@ -1,40 +0,0 @@
    -# Licensed to the Apache Software Foundation (ASF) under one
    -# or more contributor license agreements.  See the NOTICE file
    -# distributed with this work for additional information
    -# regarding copyright ownership.  The ASF licenses this file
    -# to you under the Apache License, Version 2.0 (the
    -# "License"); you may not use this file except in compliance
    -# with the License.  You may obtain a copy of the License at
    -#
    -#   http://www.apache.org/licenses/LICENSE-2.0
    -#
    -# Unless required by applicable law or agreed to in writing,
    -# software distributed under the License is distributed on an
    -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    -# KIND, either express or implied.  See the License for the
    -# specific language governing permissions and limitations
    -# under the License.
    -
    -from __future__ import annotations
    -
    -from datetime import timedelta
    -
    -from airflow.api_fastapi.core_api.base import BaseModel
    -
    -
    -class DagReportResponse(BaseModel):
    -    """DAG Report serializer for responses."""
    -
    -    file: str
    -    duration: timedelta
    -    dag_num: int
    -    task_num: int
    -    dags: str
    -    warning_num: int
    -
    -
    -class DagReportCollectionResponse(BaseModel):
    -    """DAG Report Collection serializer for responses."""
    -
    -    dag_reports: list[DagReportResponse]
    -    total_entries: int
    
  • airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml+0 47 modified
    @@ -2704,53 +2704,6 @@ paths:
                 application/json:
                   schema:
                     $ref: '#/components/schemas/HTTPValidationError'
    -  /api/v2/dagReports:
    -    get:
    -      tags:
    -      - DagReport
    -      summary: Get Dag Reports
    -      description: Get DAG report.
    -      operationId: get_dag_reports
    -      security:
    -      - OAuth2PasswordBearer: []
    -      - HTTPBearer: []
    -      parameters:
    -      - name: subdir
    -        in: query
    -        required: true
    -        schema:
    -          type: string
    -          title: Subdir
    -      responses:
    -        '200':
    -          description: Successful Response
    -          content:
    -            application/json:
    -              schema: {}
    -        '401':
    -          content:
    -            application/json:
    -              schema:
    -                $ref: '#/components/schemas/HTTPExceptionResponse'
    -          description: Unauthorized
    -        '403':
    -          content:
    -            application/json:
    -              schema:
    -                $ref: '#/components/schemas/HTTPExceptionResponse'
    -          description: Forbidden
    -        '400':
    -          content:
    -            application/json:
    -              schema:
    -                $ref: '#/components/schemas/HTTPExceptionResponse'
    -          description: Bad Request
    -        '422':
    -          description: Validation Error
    -          content:
    -            application/json:
    -              schema:
    -                $ref: '#/components/schemas/HTTPValidationError'
       /api/v2/config:
         get:
           tags:
    
  • airflow-core/src/airflow/api_fastapi/core_api/routes/public/dag_report.py+0 75 removed
    @@ -1,75 +0,0 @@
    -# Licensed to the Apache Software Foundation (ASF) under one
    -# or more contributor license agreements.  See the NOTICE file
    -# distributed with this work for additional information
    -# regarding copyright ownership.  The ASF licenses this file
    -# to you under the Apache License, Version 2.0 (the
    -# "License"); you may not use this file except in compliance
    -# with the License.  You may obtain a copy of the License at
    -#
    -#   http://www.apache.org/licenses/LICENSE-2.0
    -#
    -# Unless required by applicable law or agreed to in writing,
    -# software distributed under the License is distributed on an
    -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    -# KIND, either express or implied.  See the License for the
    -# specific language governing permissions and limitations
    -# under the License.
    -
    -from __future__ import annotations
    -
    -import ast
    -import os
    -from typing import cast
    -
    -from fastapi import Depends, HTTPException, status
    -
    -from airflow import settings
    -from airflow.api_fastapi.common.router import AirflowRouter
    -from airflow.api_fastapi.core_api.datamodels.dag_report import (
    -    DagReportCollectionResponse,
    -    DagReportResponse,
    -)
    -from airflow.api_fastapi.core_api.openapi.exceptions import create_openapi_http_exception_doc
    -from airflow.api_fastapi.core_api.security import (
    -    ReadableDagsFilterDep,
    -    requires_access_dag,
    -)
    -from airflow.dag_processing.dagbag import DagBag
    -
    -dag_report_router = AirflowRouter(tags=["DagReport"], prefix="/dagReports")
    -
    -
    -@dag_report_router.get(
    -    "",
    -    responses=create_openapi_http_exception_doc(
    -        [
    -            status.HTTP_400_BAD_REQUEST,
    -        ]
    -    ),
    -    dependencies=[Depends(requires_access_dag(method="GET"))],
    -)
    -def get_dag_reports(
    -    subdir: str,
    -    readable_dags_filter: ReadableDagsFilterDep,
    -):
    -    """Get DAG report."""
    -    fullpath = os.path.normpath(subdir)
    -    if not fullpath.startswith(settings.DAGS_FOLDER):
    -        raise HTTPException(status.HTTP_400_BAD_REQUEST, "subdir should be subpath of DAGS_FOLDER settings")
    -
    -    dagbag = DagBag(fullpath)
    -
    -    readable_dag_ids: set[str] | None = readable_dags_filter.value
    -    if readable_dag_ids:
    -        filtered_dagbag_stats = [
    -            file_load_stat
    -            for file_load_stat in dagbag.dagbag_stats
    -            if len(set(ast.literal_eval(file_load_stat.dags)) - readable_dag_ids) == 0
    -        ]
    -    else:
    -        filtered_dagbag_stats = []
    -
    -    return DagReportCollectionResponse(
    -        dag_reports=cast("list[DagReportResponse]", filtered_dagbag_stats),
    -        total_entries=len(filtered_dagbag_stats),
    -    )
    
  • airflow-core/src/airflow/api_fastapi/core_api/routes/public/__init__.py+0 2 modified
    @@ -27,7 +27,6 @@
     from airflow.api_fastapi.core_api.routes.public.config import config_router
     from airflow.api_fastapi.core_api.routes.public.connections import connections_router
     from airflow.api_fastapi.core_api.routes.public.dag_parsing import dag_parsing_router
    -from airflow.api_fastapi.core_api.routes.public.dag_report import dag_report_router
     from airflow.api_fastapi.core_api.routes.public.dag_run import dag_run_router
     from airflow.api_fastapi.core_api.routes.public.dag_sources import dag_sources_router
     from airflow.api_fastapi.core_api.routes.public.dag_stats import dag_stats_router
    @@ -65,7 +64,6 @@
     authenticated_router.include_router(dag_run_router)
     authenticated_router.include_router(dag_sources_router)
     authenticated_router.include_router(dag_stats_router)
    -authenticated_router.include_router(dag_report_router)
     authenticated_router.include_router(config_router)
     authenticated_router.include_router(dag_warning_router)
     authenticated_router.include_router(dags_router)
    
  • airflow-core/src/airflow/ui/openapi-gen/queries/common.ts+1 7 modified
    @@ -1,7 +1,7 @@
     // generated with @7nohe/openapi-react-query-codegen@1.6.2 
     
     import { UseQueryResult } from "@tanstack/react-query";
    -import { AssetService, AuthLinksService, BackfillService, CalendarService, ConfigService, ConnectionService, DagParsingService, DagReportService, DagRunService, DagService, DagSourceService, DagStatsService, DagVersionService, DagWarningService, DashboardService, DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, GridService, ImportErrorService, JobService, LoginService, MonitorService, PluginService, PoolService, ProviderService, StructureService, TaskInstanceService, TaskService, VariableService, VersionService, XcomService } from "../requests/services.gen";
    +import { AssetService, AuthLinksService, BackfillService, CalendarService, ConfigService, ConnectionService, DagParsingService, DagRunService, DagService, DagSourceService, DagStatsService, DagVersionService, DagWarningService, DashboardService, DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, GridService, ImportErrorService, JobService, LoginService, MonitorService, PluginService, PoolService, ProviderService, StructureService, TaskInstanceService, TaskService, VariableService, VersionService, XcomService } from "../requests/services.gen";
     import { DagRunState, DagWarningType } from "../requests/types.gen";
     export type AssetServiceGetAssetsDefaultResponse = Awaited<ReturnType<typeof AssetService.getAssets>>;
     export type AssetServiceGetAssetsQueryResult<TData = AssetServiceGetAssetsDefaultResponse, TError = unknown> = UseQueryResult<TData, TError>;
    @@ -212,12 +212,6 @@ export const useDagStatsServiceGetDagStatsKey = "DagStatsServiceGetDagStats";
     export const UseDagStatsServiceGetDagStatsKeyFn = ({ dagIds }: {
       dagIds?: string[];
     } = {}, queryKey?: Array<unknown>) => [useDagStatsServiceGetDagStatsKey, ...(queryKey ?? [{ dagIds }])];
    -export type DagReportServiceGetDagReportsDefaultResponse = Awaited<ReturnType<typeof DagReportService.getDagReports>>;
    -export type DagReportServiceGetDagReportsQueryResult<TData = DagReportServiceGetDagReportsDefaultResponse, TError = unknown> = UseQueryResult<TData, TError>;
    -export const useDagReportServiceGetDagReportsKey = "DagReportServiceGetDagReports";
    -export const UseDagReportServiceGetDagReportsKeyFn = ({ subdir }: {
    -  subdir: string;
    -}, queryKey?: Array<unknown>) => [useDagReportServiceGetDagReportsKey, ...(queryKey ?? [{ subdir }])];
     export type ConfigServiceGetConfigDefaultResponse = Awaited<ReturnType<typeof ConfigService.getConfig>>;
     export type ConfigServiceGetConfigQueryResult<TData = ConfigServiceGetConfigDefaultResponse, TError = unknown> = UseQueryResult<TData, TError>;
     export const useConfigServiceGetConfigKey = "ConfigServiceGetConfig";
    
  • airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts+1 12 modified
    @@ -1,7 +1,7 @@
     // generated with @7nohe/openapi-react-query-codegen@1.6.2 
     
     import { type QueryClient } from "@tanstack/react-query";
    -import { AssetService, AuthLinksService, BackfillService, CalendarService, ConfigService, ConnectionService, DagReportService, DagRunService, DagService, DagSourceService, DagStatsService, DagVersionService, DagWarningService, DashboardService, DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, GridService, ImportErrorService, JobService, LoginService, MonitorService, PluginService, PoolService, ProviderService, StructureService, TaskInstanceService, TaskService, VariableService, VersionService, XcomService } from "../requests/services.gen";
    +import { AssetService, AuthLinksService, BackfillService, CalendarService, ConfigService, ConnectionService, DagRunService, DagService, DagSourceService, DagStatsService, DagVersionService, DagWarningService, DashboardService, DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, GridService, ImportErrorService, JobService, LoginService, MonitorService, PluginService, PoolService, ProviderService, StructureService, TaskInstanceService, TaskService, VariableService, VersionService, XcomService } from "../requests/services.gen";
     import { DagRunState, DagWarningType } from "../requests/types.gen";
     import * as Common from "./common";
     /**
    @@ -398,17 +398,6 @@ export const ensureUseDagStatsServiceGetDagStatsData = (queryClient: QueryClient
       dagIds?: string[];
     } = {}) => queryClient.ensureQueryData({ queryKey: Common.UseDagStatsServiceGetDagStatsKeyFn({ dagIds }), queryFn: () => DagStatsService.getDagStats({ dagIds }) });
     /**
    -* Get Dag Reports
    -* Get DAG report.
    -* @param data The data for the request.
    -* @param data.subdir
    -* @returns unknown Successful Response
    -* @throws ApiError
    -*/
    -export const ensureUseDagReportServiceGetDagReportsData = (queryClient: QueryClient, { subdir }: {
    -  subdir: string;
    -}) => queryClient.ensureQueryData({ queryKey: Common.UseDagReportServiceGetDagReportsKeyFn({ subdir }), queryFn: () => DagReportService.getDagReports({ subdir }) });
    -/**
     * Get Config
     * @param data The data for the request.
     * @param data.section
    
  • airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts+1 12 modified
    @@ -1,7 +1,7 @@
     // generated with @7nohe/openapi-react-query-codegen@1.6.2 
     
     import { type QueryClient } from "@tanstack/react-query";
    -import { AssetService, AuthLinksService, BackfillService, CalendarService, ConfigService, ConnectionService, DagReportService, DagRunService, DagService, DagSourceService, DagStatsService, DagVersionService, DagWarningService, DashboardService, DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, GridService, ImportErrorService, JobService, LoginService, MonitorService, PluginService, PoolService, ProviderService, StructureService, TaskInstanceService, TaskService, VariableService, VersionService, XcomService } from "../requests/services.gen";
    +import { AssetService, AuthLinksService, BackfillService, CalendarService, ConfigService, ConnectionService, DagRunService, DagService, DagSourceService, DagStatsService, DagVersionService, DagWarningService, DashboardService, DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, GridService, ImportErrorService, JobService, LoginService, MonitorService, PluginService, PoolService, ProviderService, StructureService, TaskInstanceService, TaskService, VariableService, VersionService, XcomService } from "../requests/services.gen";
     import { DagRunState, DagWarningType } from "../requests/types.gen";
     import * as Common from "./common";
     /**
    @@ -398,17 +398,6 @@ export const prefetchUseDagStatsServiceGetDagStats = (queryClient: QueryClient,
       dagIds?: string[];
     } = {}) => queryClient.prefetchQuery({ queryKey: Common.UseDagStatsServiceGetDagStatsKeyFn({ dagIds }), queryFn: () => DagStatsService.getDagStats({ dagIds }) });
     /**
    -* Get Dag Reports
    -* Get DAG report.
    -* @param data The data for the request.
    -* @param data.subdir
    -* @returns unknown Successful Response
    -* @throws ApiError
    -*/
    -export const prefetchUseDagReportServiceGetDagReports = (queryClient: QueryClient, { subdir }: {
    -  subdir: string;
    -}) => queryClient.prefetchQuery({ queryKey: Common.UseDagReportServiceGetDagReportsKeyFn({ subdir }), queryFn: () => DagReportService.getDagReports({ subdir }) });
    -/**
     * Get Config
     * @param data The data for the request.
     * @param data.section
    
  • airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts+1 12 modified
    @@ -1,7 +1,7 @@
     // generated with @7nohe/openapi-react-query-codegen@1.6.2 
     
     import { UseMutationOptions, UseQueryOptions, useMutation, useQuery } from "@tanstack/react-query";
    -import { AssetService, AuthLinksService, BackfillService, CalendarService, ConfigService, ConnectionService, DagParsingService, DagReportService, DagRunService, DagService, DagSourceService, DagStatsService, DagVersionService, DagWarningService, DashboardService, DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, GridService, ImportErrorService, JobService, LoginService, MonitorService, PluginService, PoolService, ProviderService, StructureService, TaskInstanceService, TaskService, VariableService, VersionService, XcomService } from "../requests/services.gen";
    +import { AssetService, AuthLinksService, BackfillService, CalendarService, ConfigService, ConnectionService, DagParsingService, DagRunService, DagService, DagSourceService, DagStatsService, DagVersionService, DagWarningService, DashboardService, DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, GridService, ImportErrorService, JobService, LoginService, MonitorService, PluginService, PoolService, ProviderService, StructureService, TaskInstanceService, TaskService, VariableService, VersionService, XcomService } from "../requests/services.gen";
     import { BackfillPostBody, BulkBody_BulkTaskInstanceBody_, BulkBody_ConnectionBody_, BulkBody_PoolBody_, BulkBody_VariableBody_, ClearTaskInstancesBody, ConnectionBody, CreateAssetEventsBody, DAGPatchBody, DAGRunClearBody, DAGRunPatchBody, DAGRunsBatchBody, DagRunState, DagWarningType, PatchTaskInstanceBody, PoolBody, PoolPatchBody, TaskInstancesBatchBody, TriggerDAGRunPostBody, UpdateHITLDetailPayload, VariableBody, XComCreateBody, XComUpdateBody } from "../requests/types.gen";
     import * as Common from "./common";
     /**
    @@ -398,17 +398,6 @@ export const useDagStatsServiceGetDagStats = <TData = Common.DagStatsServiceGetD
       dagIds?: string[];
     } = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, "queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey: Common.UseDagStatsServiceGetDagStatsKeyFn({ dagIds }, queryKey), queryFn: () => DagStatsService.getDagStats({ dagIds }) as TData, ...options });
     /**
    -* Get Dag Reports
    -* Get DAG report.
    -* @param data The data for the request.
    -* @param data.subdir
    -* @returns unknown Successful Response
    -* @throws ApiError
    -*/
    -export const useDagReportServiceGetDagReports = <TData = Common.DagReportServiceGetDagReportsDefaultResponse, TError = unknown, TQueryKey extends Array<unknown> = unknown[]>({ subdir }: {
    -  subdir: string;
    -}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, "queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey: Common.UseDagReportServiceGetDagReportsKeyFn({ subdir }, queryKey), queryFn: () => DagReportService.getDagReports({ subdir }) as TData, ...options });
    -/**
     * Get Config
     * @param data The data for the request.
     * @param data.section
    
  • airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts+1 12 modified
    @@ -1,7 +1,7 @@
     // generated with @7nohe/openapi-react-query-codegen@1.6.2 
     
     import { UseQueryOptions, useSuspenseQuery } from "@tanstack/react-query";
    -import { AssetService, AuthLinksService, BackfillService, CalendarService, ConfigService, ConnectionService, DagReportService, DagRunService, DagService, DagSourceService, DagStatsService, DagVersionService, DagWarningService, DashboardService, DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, GridService, ImportErrorService, JobService, LoginService, MonitorService, PluginService, PoolService, ProviderService, StructureService, TaskInstanceService, TaskService, VariableService, VersionService, XcomService } from "../requests/services.gen";
    +import { AssetService, AuthLinksService, BackfillService, CalendarService, ConfigService, ConnectionService, DagRunService, DagService, DagSourceService, DagStatsService, DagVersionService, DagWarningService, DashboardService, DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, GridService, ImportErrorService, JobService, LoginService, MonitorService, PluginService, PoolService, ProviderService, StructureService, TaskInstanceService, TaskService, VariableService, VersionService, XcomService } from "../requests/services.gen";
     import { DagRunState, DagWarningType } from "../requests/types.gen";
     import * as Common from "./common";
     /**
    @@ -398,17 +398,6 @@ export const useDagStatsServiceGetDagStatsSuspense = <TData = Common.DagStatsSer
       dagIds?: string[];
     } = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, "queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey: Common.UseDagStatsServiceGetDagStatsKeyFn({ dagIds }, queryKey), queryFn: () => DagStatsService.getDagStats({ dagIds }) as TData, ...options });
     /**
    -* Get Dag Reports
    -* Get DAG report.
    -* @param data The data for the request.
    -* @param data.subdir
    -* @returns unknown Successful Response
    -* @throws ApiError
    -*/
    -export const useDagReportServiceGetDagReportsSuspense = <TData = Common.DagReportServiceGetDagReportsDefaultResponse, TError = unknown, TQueryKey extends Array<unknown> = unknown[]>({ subdir }: {
    -  subdir: string;
    -}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, "queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey: Common.UseDagReportServiceGetDagReportsKeyFn({ subdir }, queryKey), queryFn: () => DagReportService.getDagReports({ subdir }) as TData, ...options });
    -/**
     * Get Config
     * @param data The data for the request.
     * @param data.section
    
  • airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts+1 28 modified
    @@ -3,7 +3,7 @@
     import type { CancelablePromise } from './core/CancelablePromise';
     import { OpenAPI } from './core/OpenAPI';
     import { request as __request } from './core/request';
    -import type { GetAssetsData, GetAssetsResponse, GetAssetAliasesData, GetAssetAliasesResponse, GetAssetAliasData, GetAssetAliasResponse, GetAssetEventsData, GetAssetEventsResponse, CreateAssetEventData, CreateAssetEventResponse, MaterializeAssetData, MaterializeAssetResponse, GetAssetQueuedEventsData, GetAssetQueuedEventsResponse, DeleteAssetQueuedEventsData, DeleteAssetQueuedEventsResponse, GetAssetData, GetAssetResponse, GetDagAssetQueuedEventsData, GetDagAssetQueuedEventsResponse, DeleteDagAssetQueuedEventsData, DeleteDagAssetQueuedEventsResponse, GetDagAssetQueuedEventData, GetDagAssetQueuedEventResponse, DeleteDagAssetQueuedEventData, DeleteDagAssetQueuedEventResponse, NextRunAssetsData, NextRunAssetsResponse, ListBackfillsData, ListBackfillsResponse, CreateBackfillData, CreateBackfillResponse, GetBackfillData, GetBackfillResponse, PauseBackfillData, PauseBackfillResponse, UnpauseBackfillData, UnpauseBackfillResponse, CancelBackfillData, CancelBackfillResponse, CreateBackfillDryRunData, CreateBackfillDryRunResponse, ListBackfillsUiData, ListBackfillsUiResponse, DeleteConnectionData, DeleteConnectionResponse, GetConnectionData, GetConnectionResponse, PatchConnectionData, PatchConnectionResponse, GetConnectionsData, GetConnectionsResponse, PostConnectionData, PostConnectionResponse, BulkConnectionsData, BulkConnectionsResponse, TestConnectionData, TestConnectionResponse, CreateDefaultConnectionsResponse, HookMetaDataResponse, GetDagRunData, GetDagRunResponse, DeleteDagRunData, DeleteDagRunResponse, PatchDagRunData, PatchDagRunResponse, GetUpstreamAssetEventsData, GetUpstreamAssetEventsResponse, ClearDagRunData, ClearDagRunResponse, GetDagRunsData, GetDagRunsResponse, TriggerDagRunData, TriggerDagRunResponse, WaitDagRunUntilFinishedData, WaitDagRunUntilFinishedResponse, GetListDagRunsBatchData, GetListDagRunsBatchResponse, GetDagSourceData, GetDagSourceResponse, GetDagStatsData, GetDagStatsResponse, GetDagReportsData, GetDagReportsResponse, GetConfigData, GetConfigResponse, GetConfigValueData, GetConfigValueResponse, GetConfigsResponse, ListDagWarningsData, ListDagWarningsResponse, GetDagsData, GetDagsResponse, PatchDagsData, PatchDagsResponse, GetDagData, GetDagResponse, PatchDagData, PatchDagResponse, DeleteDagData, DeleteDagResponse, GetDagDetailsData, GetDagDetailsResponse, FavoriteDagData, FavoriteDagResponse, UnfavoriteDagData, UnfavoriteDagResponse, GetDagTagsData, GetDagTagsResponse, GetDagsUiData, GetDagsUiResponse, GetLatestRunInfoData, GetLatestRunInfoResponse, GetEventLogData, GetEventLogResponse, GetEventLogsData, GetEventLogsResponse, GetExtraLinksData, GetExtraLinksResponse, GetTaskInstanceData, GetTaskInstanceResponse, PatchTaskInstanceData, PatchTaskInstanceResponse, DeleteTaskInstanceData, DeleteTaskInstanceResponse, GetMappedTaskInstancesData, GetMappedTaskInstancesResponse, GetTaskInstanceDependenciesByMapIndexData, GetTaskInstanceDependenciesByMapIndexResponse, GetTaskInstanceDependenciesData, GetTaskInstanceDependenciesResponse, GetTaskInstanceTriesData, GetTaskInstanceTriesResponse, GetMappedTaskInstanceTriesData, GetMappedTaskInstanceTriesResponse, GetMappedTaskInstanceData, GetMappedTaskInstanceResponse, PatchTaskInstanceByMapIndexData, PatchTaskInstanceByMapIndexResponse, GetTaskInstancesData, GetTaskInstancesResponse, BulkTaskInstancesData, BulkTaskInstancesResponse, GetTaskInstancesBatchData, GetTaskInstancesBatchResponse, GetTaskInstanceTryDetailsData, GetTaskInstanceTryDetailsResponse, GetMappedTaskInstanceTryDetailsData, GetMappedTaskInstanceTryDetailsResponse, PostClearTaskInstancesData, PostClearTaskInstancesResponse, PatchTaskInstanceDryRunByMapIndexData, PatchTaskInstanceDryRunByMapIndexResponse, PatchTaskInstanceDryRunData, PatchTaskInstanceDryRunResponse, GetLogData, GetLogResponse, GetExternalLogUrlData, GetExternalLogUrlResponse, UpdateHitlDetailData, UpdateHitlDetailResponse, GetHitlDetailData, GetHitlDetailResponse, GetHitlDetailsData, GetHitlDetailsResponse, GetImportErrorData, GetImportErrorResponse, GetImportErrorsData, GetImportErrorsResponse, GetJobsData, GetJobsResponse, GetPluginsData, GetPluginsResponse, ImportErrorsResponse, DeletePoolData, DeletePoolResponse, GetPoolData, GetPoolResponse, PatchPoolData, PatchPoolResponse, GetPoolsData, GetPoolsResponse, PostPoolData, PostPoolResponse, BulkPoolsData, BulkPoolsResponse, GetProvidersData, GetProvidersResponse, GetXcomEntryData, GetXcomEntryResponse, UpdateXcomEntryData, UpdateXcomEntryResponse, GetXcomEntriesData, GetXcomEntriesResponse, CreateXcomEntryData, CreateXcomEntryResponse, GetTasksData, GetTasksResponse, GetTaskData, GetTaskResponse, DeleteVariableData, DeleteVariableResponse, GetVariableData, GetVariableResponse, PatchVariableData, PatchVariableResponse, GetVariablesData, GetVariablesResponse, PostVariableData, PostVariableResponse, BulkVariablesData, BulkVariablesResponse, ReparseDagFileData, ReparseDagFileResponse, GetDagVersionData, GetDagVersionResponse, GetDagVersionsData, GetDagVersionsResponse, GetHealthResponse, GetVersionResponse, LoginData, LoginResponse, LogoutData, LogoutResponse, RefreshData, RefreshResponse, GetAuthMenusResponse, GetDependenciesData, GetDependenciesResponse, HistoricalMetricsData, HistoricalMetricsResponse, DagStatsResponse2, StructureDataData, StructureDataResponse2, GetDagStructureData, GetDagStructureResponse, GetGridRunsData, GetGridRunsResponse, GetGridTiSummariesData, GetGridTiSummariesResponse, GetCalendarData, GetCalendarResponse } from './types.gen';
    +import type { GetAssetsData, GetAssetsResponse, GetAssetAliasesData, GetAssetAliasesResponse, GetAssetAliasData, GetAssetAliasResponse, GetAssetEventsData, GetAssetEventsResponse, CreateAssetEventData, CreateAssetEventResponse, MaterializeAssetData, MaterializeAssetResponse, GetAssetQueuedEventsData, GetAssetQueuedEventsResponse, DeleteAssetQueuedEventsData, DeleteAssetQueuedEventsResponse, GetAssetData, GetAssetResponse, GetDagAssetQueuedEventsData, GetDagAssetQueuedEventsResponse, DeleteDagAssetQueuedEventsData, DeleteDagAssetQueuedEventsResponse, GetDagAssetQueuedEventData, GetDagAssetQueuedEventResponse, DeleteDagAssetQueuedEventData, DeleteDagAssetQueuedEventResponse, NextRunAssetsData, NextRunAssetsResponse, ListBackfillsData, ListBackfillsResponse, CreateBackfillData, CreateBackfillResponse, GetBackfillData, GetBackfillResponse, PauseBackfillData, PauseBackfillResponse, UnpauseBackfillData, UnpauseBackfillResponse, CancelBackfillData, CancelBackfillResponse, CreateBackfillDryRunData, CreateBackfillDryRunResponse, ListBackfillsUiData, ListBackfillsUiResponse, DeleteConnectionData, DeleteConnectionResponse, GetConnectionData, GetConnectionResponse, PatchConnectionData, PatchConnectionResponse, GetConnectionsData, GetConnectionsResponse, PostConnectionData, PostConnectionResponse, BulkConnectionsData, BulkConnectionsResponse, TestConnectionData, TestConnectionResponse, CreateDefaultConnectionsResponse, HookMetaDataResponse, GetDagRunData, GetDagRunResponse, DeleteDagRunData, DeleteDagRunResponse, PatchDagRunData, PatchDagRunResponse, GetUpstreamAssetEventsData, GetUpstreamAssetEventsResponse, ClearDagRunData, ClearDagRunResponse, GetDagRunsData, GetDagRunsResponse, TriggerDagRunData, TriggerDagRunResponse, WaitDagRunUntilFinishedData, WaitDagRunUntilFinishedResponse, GetListDagRunsBatchData, GetListDagRunsBatchResponse, GetDagSourceData, GetDagSourceResponse, GetDagStatsData, GetDagStatsResponse, GetConfigData, GetConfigResponse, GetConfigValueData, GetConfigValueResponse, GetConfigsResponse, ListDagWarningsData, ListDagWarningsResponse, GetDagsData, GetDagsResponse, PatchDagsData, PatchDagsResponse, GetDagData, GetDagResponse, PatchDagData, PatchDagResponse, DeleteDagData, DeleteDagResponse, GetDagDetailsData, GetDagDetailsResponse, FavoriteDagData, FavoriteDagResponse, UnfavoriteDagData, UnfavoriteDagResponse, GetDagTagsData, GetDagTagsResponse, GetDagsUiData, GetDagsUiResponse, GetLatestRunInfoData, GetLatestRunInfoResponse, GetEventLogData, GetEventLogResponse, GetEventLogsData, GetEventLogsResponse, GetExtraLinksData, GetExtraLinksResponse, GetTaskInstanceData, GetTaskInstanceResponse, PatchTaskInstanceData, PatchTaskInstanceResponse, DeleteTaskInstanceData, DeleteTaskInstanceResponse, GetMappedTaskInstancesData, GetMappedTaskInstancesResponse, GetTaskInstanceDependenciesByMapIndexData, GetTaskInstanceDependenciesByMapIndexResponse, GetTaskInstanceDependenciesData, GetTaskInstanceDependenciesResponse, GetTaskInstanceTriesData, GetTaskInstanceTriesResponse, GetMappedTaskInstanceTriesData, GetMappedTaskInstanceTriesResponse, GetMappedTaskInstanceData, GetMappedTaskInstanceResponse, PatchTaskInstanceByMapIndexData, PatchTaskInstanceByMapIndexResponse, GetTaskInstancesData, GetTaskInstancesResponse, BulkTaskInstancesData, BulkTaskInstancesResponse, GetTaskInstancesBatchData, GetTaskInstancesBatchResponse, GetTaskInstanceTryDetailsData, GetTaskInstanceTryDetailsResponse, GetMappedTaskInstanceTryDetailsData, GetMappedTaskInstanceTryDetailsResponse, PostClearTaskInstancesData, PostClearTaskInstancesResponse, PatchTaskInstanceDryRunByMapIndexData, PatchTaskInstanceDryRunByMapIndexResponse, PatchTaskInstanceDryRunData, PatchTaskInstanceDryRunResponse, GetLogData, GetLogResponse, GetExternalLogUrlData, GetExternalLogUrlResponse, UpdateHitlDetailData, UpdateHitlDetailResponse, GetHitlDetailData, GetHitlDetailResponse, GetHitlDetailsData, GetHitlDetailsResponse, GetImportErrorData, GetImportErrorResponse, GetImportErrorsData, GetImportErrorsResponse, GetJobsData, GetJobsResponse, GetPluginsData, GetPluginsResponse, ImportErrorsResponse, DeletePoolData, DeletePoolResponse, GetPoolData, GetPoolResponse, PatchPoolData, PatchPoolResponse, GetPoolsData, GetPoolsResponse, PostPoolData, PostPoolResponse, BulkPoolsData, BulkPoolsResponse, GetProvidersData, GetProvidersResponse, GetXcomEntryData, GetXcomEntryResponse, UpdateXcomEntryData, UpdateXcomEntryResponse, GetXcomEntriesData, GetXcomEntriesResponse, CreateXcomEntryData, CreateXcomEntryResponse, GetTasksData, GetTasksResponse, GetTaskData, GetTaskResponse, DeleteVariableData, DeleteVariableResponse, GetVariableData, GetVariableResponse, PatchVariableData, PatchVariableResponse, GetVariablesData, GetVariablesResponse, PostVariableData, PostVariableResponse, BulkVariablesData, BulkVariablesResponse, ReparseDagFileData, ReparseDagFileResponse, GetDagVersionData, GetDagVersionResponse, GetDagVersionsData, GetDagVersionsResponse, GetHealthResponse, GetVersionResponse, LoginData, LoginResponse, LogoutData, LogoutResponse, RefreshData, RefreshResponse, GetAuthMenusResponse, GetDependenciesData, GetDependenciesResponse, HistoricalMetricsData, HistoricalMetricsResponse, DagStatsResponse2, StructureDataData, StructureDataResponse2, GetDagStructureData, GetDagStructureResponse, GetGridRunsData, GetGridRunsResponse, GetGridTiSummariesData, GetGridTiSummariesResponse, GetCalendarData, GetCalendarResponse } from './types.gen';
     
     export class AssetService {
         /**
    @@ -1253,33 +1253,6 @@ export class DagStatsService {
         
     }
     
    -export class DagReportService {
    -    /**
    -     * Get Dag Reports
    -     * Get DAG report.
    -     * @param data The data for the request.
    -     * @param data.subdir
    -     * @returns unknown Successful Response
    -     * @throws ApiError
    -     */
    -    public static getDagReports(data: GetDagReportsData): CancelablePromise<GetDagReportsResponse> {
    -        return __request(OpenAPI, {
    -            method: 'GET',
    -            url: '/api/v2/dagReports',
    -            query: {
    -                subdir: data.subdir
    -            },
    -            errors: {
    -                400: 'Bad Request',
    -                401: 'Unauthorized',
    -                403: 'Forbidden',
    -                422: 'Validation Error'
    -            }
    -        });
    -    }
    -    
    -}
    -
     export class ConfigService {
         /**
          * Get Config
    
  • airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts+0 33 modified
    @@ -2389,12 +2389,6 @@ export type GetDagStatsData = {
     
     export type GetDagStatsResponse = DagStatsCollectionResponse;
     
    -export type GetDagReportsData = {
    -    subdir: string;
    -};
    -
    -export type GetDagReportsResponse = unknown;
    -
     export type GetConfigData = {
         accept?: 'application/json' | 'text/plain' | '*/*';
         section?: string | null;
    @@ -4477,33 +4471,6 @@ export type $OpenApiTs = {
                 };
             };
         };
    -    '/api/v2/dagReports': {
    -        get: {
    -            req: GetDagReportsData;
    -            res: {
    -                /**
    -                 * Successful Response
    -                 */
    -                200: unknown;
    -                /**
    -                 * Bad Request
    -                 */
    -                400: HTTPExceptionResponse;
    -                /**
    -                 * Unauthorized
    -                 */
    -                401: HTTPExceptionResponse;
    -                /**
    -                 * Forbidden
    -                 */
    -                403: HTTPExceptionResponse;
    -                /**
    -                 * Validation Error
    -                 */
    -                422: HTTPValidationError;
    -            };
    -        };
    -    };
         '/api/v2/config': {
             get: {
                 req: GetConfigData;
    
  • airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dag_report.py+0 135 removed
    @@ -1,135 +0,0 @@
    -# Licensed to the Apache Software Foundation (ASF) under one
    -# or more contributor license agreements.  See the NOTICE file
    -# distributed with this work for additional information
    -# regarding copyright ownership.  The ASF licenses this file
    -# to you under the Apache License, Version 2.0 (the
    -# "License"); you may not use this file except in compliance
    -# with the License.  You may obtain a copy of the License at
    -#
    -#   http://www.apache.org/licenses/LICENSE-2.0
    -#
    -# Unless required by applicable law or agreed to in writing,
    -# software distributed under the License is distributed on an
    -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    -# KIND, either express or implied.  See the License for the
    -# specific language governing permissions and limitations
    -# under the License.
    -from __future__ import annotations
    -
    -import os
    -from unittest.mock import patch
    -
    -import pytest
    -
    -from airflow.utils.file import list_py_file_paths
    -
    -from tests_common.test_utils.config import conf_vars
    -from tests_common.test_utils.db import clear_db_dags, parse_and_sync_to_db
    -
    -pytestmark = pytest.mark.db_test
    -
    -TEST_DAG_FOLDER = os.environ["AIRFLOW__CORE__DAGS_FOLDER"]
    -TEST_DAG_FOLDER_WITH_SUBDIR = f"{TEST_DAG_FOLDER}/subdir2"
    -TEST_DAG_FOLDER_INVALID = "/invalid/path"
    -TEST_DAG_FOLDER_INVALID_2 = "/root/airflow/tests/dags/"
    -
    -
    -def get_corresponding_dag_file_count(dir: str, include_examples: bool = True) -> int:
    -    from airflow import example_dags
    -
    -    return len(list_py_file_paths(directory=dir)) + (
    -        len(list_py_file_paths(next(iter(example_dags.__path__)))) if include_examples else 0
    -    )
    -
    -
    -class TestDagReportEndpoint:
    -    @pytest.fixture(autouse=True)
    -    def setup(self) -> None:
    -        self.clear_db()
    -
    -    def teardown_method(self) -> None:
    -        self.clear_db()
    -
    -    def clear_db(self):
    -        clear_db_dags()
    -
    -    @pytest.mark.parametrize(
    -        "subdir,include_example,expected_total_entries",
    -        [
    -            pytest.param(
    -                TEST_DAG_FOLDER,
    -                True,
    -                get_corresponding_dag_file_count(TEST_DAG_FOLDER),
    -                id="dag_path_with_example",
    -            ),
    -            pytest.param(
    -                TEST_DAG_FOLDER,
    -                False,
    -                get_corresponding_dag_file_count(TEST_DAG_FOLDER, False),
    -                id="dag_path_without_example",
    -            ),
    -            pytest.param(
    -                TEST_DAG_FOLDER_WITH_SUBDIR,
    -                True,
    -                get_corresponding_dag_file_count(TEST_DAG_FOLDER_WITH_SUBDIR),
    -                id="dag_path_subdir_with_example",
    -            ),
    -            pytest.param(
    -                TEST_DAG_FOLDER_WITH_SUBDIR,
    -                False,
    -                get_corresponding_dag_file_count(TEST_DAG_FOLDER_WITH_SUBDIR, False),
    -                id="dag_path_subdir_without_example",
    -            ),
    -        ],
    -    )
    -    def test_should_response_200(self, test_client, subdir, include_example, expected_total_entries):
    -        with conf_vars({("core", "load_examples"): str(include_example)}):
    -            parse_and_sync_to_db(subdir, include_examples=include_example)
    -            response = test_client.get("/dagReports", params={"subdir": subdir})
    -            assert response.status_code == 200
    -            response_json = response.json()
    -            assert response_json["total_entries"] == expected_total_entries
    -
    -    def test_should_response_200_with_empty_dagbag(self, test_client):
    -        # the constructor of DagBag will call `collect_dags` method and store the result in `dagbag_stats`
    -        def _mock_collect_dags(self, *args, **kwargs):
    -            self.dagbag_stats = []
    -
    -        with patch("airflow.dag_processing.dagbag.DagBag.collect_dags", _mock_collect_dags):
    -            response = test_client.get("/dagReports", params={"subdir": TEST_DAG_FOLDER})
    -            assert response.status_code == 200
    -            assert response.json() == {"dag_reports": [], "total_entries": 0}
    -
    -    @pytest.mark.parametrize(
    -        "subdir",
    -        [
    -            pytest.param(TEST_DAG_FOLDER_INVALID, id="invalid_dag_path"),
    -            pytest.param(TEST_DAG_FOLDER_INVALID_2, id="invalid_dag_path_2"),
    -        ],
    -    )
    -    def test_should_response_400(self, test_client, subdir):
    -        response = test_client.get("/dagReports", params={"subdir": subdir})
    -        assert response.status_code == 400
    -        assert response.json() == {"detail": "subdir should be subpath of DAGS_FOLDER settings"}
    -
    -    def test_should_response_422(self, test_client):
    -        response = test_client.get("/dagReports")
    -        assert response.status_code == 422
    -        assert response.json() == {
    -            "detail": [
    -                {
    -                    "input": None,
    -                    "loc": ["query", "subdir"],
    -                    "msg": "Field required",
    -                    "type": "missing",
    -                }
    -            ]
    -        }
    -
    -    def test_should_respond_401(self, unauthenticated_test_client):
    -        response = unauthenticated_test_client.get("/dagReports")
    -        assert response.status_code == 401
    -
    -    def test_should_respond_403(self, unauthorized_test_client):
    -        response = unauthorized_test_client.get("/dagReports")
    -        assert response.status_code == 403
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.