{
  "variant_id": "GHSA-2943-9672-r45w-airflow-exc-ser-bypass",
  "created_at": "2026-07-07T22:44:00Z",
  "variant_summary": "Airflow 3.3.0 removes/rejects the parent BASE_TRIGGER serialized-DAG import path, but BaseSerialization.deserialize() still imports attacker-controlled AIRFLOW_EXC_SER exc_cls_name from serialized DAG data. The API Server loads the malicious serialized DAG through /ui/grid/structure/{dag_id} and imports evil_exception_module.EvilException, executing module-level code in the API Server process.",
  "relation": "newer_version_sibling",
  "origin_kind": "pruva_variant",
  "repository": "https://github.com/apache/airflow",
  "submitted_target": {
    "target_kind": "release_tag",
    "commit_sha": "cde4885818be51a6cdcfdf9275e100bf070025de",
    "version": "3.2.2",
    "ref": "refs/tags/3.2.2",
    "display": "apache-airflow 3.2.2 / tag 3.2.2"
  },
  "variant_target": {
    "target_kind": "release_tag",
    "commit_sha": "1438ea3587031417cc85d74323235cf087a058fb",
    "version": "3.3.0",
    "ref": "refs/tags/3.3.0",
    "display": "apache-airflow 3.3.0 fixed/latest release / tag 3.3.0"
  },
  "same_root_cause_confidence": "high",
  "same_surface_confidence": "high",
  "claimed_surface": "api_remote",
  "validated_surface": "api_remote",
  "required_entrypoint_kind": "endpoint",
  "required_entrypoint_detail": "Airflow api-server HTTP GET /ui/grid/structure/{dag_id}?offset=0&limit=100 loads SerializedDagModel.dag and recursively deserializes dag.default_args",
  "attacker_controlled_input": "Serialized DAG dag.default_args containing __type=airflow_exc_ser and exc_cls_name=evil_exception_module.EvilException",
  "trigger_path": "HTTP GET /ui/grid/structure/{dag_id} -> SerializedDagModel.dag -> DagSerialization.from_dict -> BaseSerialization.deserialize(AIRFLOW_EXC_SER) -> import_string(exc_cls_name)",
  "observed_impact_class": "code_execution",
  "exploitability_confidence": "high",
  "evidence_scope": "production_path",
  "runtime_manifest_present": true,
  "end_to_end_target_reached": true,
  "inferred": false,
  "file_path": "airflow/serialization/serialized_objects.py",
  "line_start": 660,
  "line_end": 667,
  "secondary_anchors": [
    {
      "file_path": "airflow/serialization/serialized_objects.py",
      "line_start": 615,
      "line_end": 704
    },
    {
      "file_path": "airflow/serialization/serialized_objects.py",
      "line_start": 1753,
      "line_end": 1810
    }
  ],
  "review_scope_paths": [
    "airflow/serialization/serialized_objects.py",
    "airflow/models/serialized_dag.py",
    "airflow/api_fastapi/core_api/routes/ui/grid.py",
    "airflow/sdk/serde/__init__.py"
  ],
  "artifact_refs": {
    "variant_manifest": "bundle/vuln_variant/variant_manifest.json",
    "validation_verdict": "bundle/vuln_variant/validation_verdict.json",
    "runtime_manifest": "bundle/vuln_variant/runtime_manifest.json",
    "repro_log": "bundle/logs/vuln_variant/reproduction_steps.log",
    "root_cause_equivalence": "bundle/vuln_variant/root_cause_equivalence.json",
    "reproducer": [
      "bundle/vuln_variant/reproduction_steps.sh",
      "bundle/vuln_variant/airflow_exc_variant_attempt.py"
    ],
    "patch_analysis": "bundle/vuln_variant/patch_analysis.md",
    "fixed_marker": "bundle/vuln_variant/artifacts/airflow_exc_3.3.0_variant/api_server_airflow_exc_marker.txt",
    "fixed_attempt_json": "bundle/logs/vuln_variant/airflow_exc_3.3.0_variant.json",
    "source_identity": "bundle/vuln_variant/source_identity.json"
  }
}
