Skip to content

Restrict exception-node deserialization to BaseException subclasses (validate before import)#68511

Open
potiuk wants to merge 2 commits into
apache:mainfrom
potiuk:restrict-exception-node-deserialization
Open

Restrict exception-node deserialization to BaseException subclasses (validate before import)#68511
potiuk wants to merge 2 commits into
apache:mainfrom
potiuk:restrict-exception-node-deserialization

Conversation

@potiuk

@potiuk potiuk commented Jun 13, 2026

Copy link
Copy Markdown
Member

Stacked on #67926 — applies the same pre-import class-path validation to the AIRFLOW_EXC_SER / BASE_EXC_SER exception branches that #67926 adds for BASE_TRIGGER, reusing the shared _safe_import_for_deserialize helper. Review the top commit; the first commit belongs to #67926 and drops out once it merges.

Exception classes are now resolved through the trusted-namespace allowlist (validated before import_string), then verified as BaseException subclasses. Builtins stay allowed for standard exceptions; the subclass check rejects non-exception builtins.

Tests

  • AIRFLOW_EXC_SER path outside trusted namespaces rejected before import
  • BASE_EXC_SER non-exception builtin (e.g. eval) rejected
  • genuine builtin exception still round-trips
Was generative AI tooling used to co-author this PR?
  • Yes — Claude Opus 4.8 (1M context)

Generated-by: Claude Opus 4.8 (1M context) following the guidelines at
https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions

@potiuk potiuk requested review from ashb and bolkedebruin as code owners June 13, 2026 17:14
@potiuk potiuk force-pushed the restrict-exception-node-deserialization branch from 3baa424 to 0e8d29d Compare June 14, 2026 01:51
…GER)

The DAT.BASE_TRIGGER encode/decode (serializing a BaseTrigger instance via BaseSerialization) is a vestige of AIP-44's Internal API. Live deferral uses the structured DeferTask/TIDeferredStatePayload (classpath+kwargs); the execution API stores the classpath opaquely; the triggerer imports it from the DB row. No external producer/consumer of DAT.BASE_TRIGGER remains. Keeps generic AirflowException serialization (live).

Generated-by: Claude Opus 4.8 (1M context)
…validate before import)

Stacked on apache#68528, which removed the dead AIP-44 BASE_TRIGGER path; the
remaining hardening here is for the exception nodes.

When a serialized DAG carries an exception node (AIRFLOW_EXC_SER /
BASE_EXC_SER), deserialization called import_string on the stored class
path and instantiated whatever it resolved to, without validating the
path or the resulting type.

Add _safe_import_for_deserialize, which validates the class path against a
trusted-namespace prefix list (airflow., plus builtins. for the
BASE_EXC_SER builtin case) before importing, and then confirms the
resolved object is a BaseException subclass. A path outside the trusted
namespaces is rejected without being imported.
@potiuk potiuk force-pushed the restrict-exception-node-deserialization branch from 0e8d29d to 653105f Compare June 15, 2026 03:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant