fix(security): bump apache-airflow 3.3.0 -> 3.3.1 for CVE-2026-67587 / CVE-2026-54183 - #31861
fix(security): bump apache-airflow 3.3.0 -> 3.3.1 for CVE-2026-67587 / CVE-2026-54183#31861Khairajani wants to merge 4 commits into
Conversation
…CVE-2026-54183 CVE-2026-67587 (High) -- the Task SDK rebuilt a Serde `Callback` by re-running its constructor, which imports the module named by the stored callback path. `SyncCallback` is an Airflow class, so it passes the default `allowed_deserialization_classes` allow-list and tightening that setting does not help. A Dag author controls a task instance's `next_kwargs`, so they can get an arbitrary module imported inside the scheduler process when the `awaiting_input` timeout sweep deserializes that value. No non-default configuration is required. CVE-2026-54183 (Medium) -- the secrets masker's recursion-depth limit did not descend into values nested inside a list, tuple or set, so a Variable holding a deeply nested sensitive value rendered unmasked in the Variables UI. Anyone who can see the Variable in the UI can already read it through the Variables REST API, so this is a shoulder-surfing defense rather than a disclosure boundary -- hence Medium. Both are fixed in 3.3.1 and nothing in the 3.3.0 line is clean. The pin, both base image tags, the vendored constraints file and the integration-test image move together, as they did for 3.2.2 -> 3.3.0 in #31338. The constraints file is a straight re-download this time. It carried two hand-patches marked "keep on regeneration" -- impyla and thrift at 0.24.0 for CVE-2026-66053 / CVE-2026-41608 / CVE-2026-48586, against upstream constraints-3.3.0 shipping impyla==0.22.0 and thrift==0.16.0 -- and upstream constraints-3.3.1 now ships both at 0.24.0 natively. Diffing the vendored 3.3.0 file against upstream constraints-3.3.0 confirms those two blocks were the only divergence, and the new file is byte-identical to upstream constraints-3.3.1 outside comments. The comments are kept, reworded to say the pin is now upstream-native, so a future regeneration off a branch that regressed either version still gets caught. Two comments that name a constraint were checked rather than blind-renumbered: - tests/integration/airflow/Dockerfile explains the constraints are deliberately not applied because they pin chardet against openmetadata-ingestion's chardet==4.0.0. Still true; the version moved 6.0.0.post1 -> 7.5.1, so the number is updated. - Dockerfile.ci's universal-pathlib workaround cites Airflow's >=0.3.8 floor. apache-airflow-core 3.3.1 still declares `universal-pathlib>=0.3.8` and constraints still pin 0.3.10, so only the Airflow version in the prose changes. Resolution verified with `uv pip compile --python-version 3.12 --extra airflow`: apache-airflow==3.3.1 co-installs with every transitive floor pin in the airflow extra (providers-http, -opensearch, -elasticsearch, tornado, Werkzeug, starlette, python-multipart) with no conflict. sqlparse resolves to 0.5.4 there via collate-sqllineage, unchanged by this PR -- the release images force 0.6.0 in ingestion/operators/docker/Dockerfile, which does not consume this constraints file.
❌ PR checklist incompleteThis PR cannot be merged until the following are addressed on its linked issue:
The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically. Maintainers can bypass this check by adding the |
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
🔴 Playwright Results — workflow failedValidated commit ✅ 107 passed · ❌ 1 failed · 🟡 1 flaky · ⏭️ 1 skipped · 🧰 0 lifecycle flaky PerformanceBlocking targets: ❌ unmet · Optimization targets: 🟡 in progress Shard-job maxima below are not the full workflow wall time; the linked run includes build, fixture, planning, and reporting. 🕒 Full workflow signal wall (to summary) 53m 45s ⏱️ Max setup 4m 53s · max shard execution 19m 1s · max shard-job elapsed before upload 25m 24s · reporting 6s 🌐 220.06 requests/attempt · 1.77 app boots/UI scenario · 0.00% common-shard skew Optimization targets still in progress:
Genuine Failures (failed on all attempts)❌
|
`uv pip install ingestion[all]` + `[test]` in the CI test environment fails to resolve
against apache-airflow 3.3.1:
Because apache-airflow-core>=3.3.1 depends on croniter>=6.2.2 [...] and because
openmetadata-ingestion[test]==2.0.0.0.dev0 depends on apache-airflow==3.3.1 and
croniter<3, we can conclude that [...] requirements are unsatisfiable.
apache-airflow-core raised its croniter floor from >=2.0.2 to >=6.2.2 between 3.3.0 and
3.3.1, so the ceiling that used to co-exist with airflow now excludes it.
The ceiling is dead weight and predates this conflict -- it has been in the dagster
extra since #6416 and survived the #15679 dependency cleanup:
- dagster 1.13.18 (what `dagster_graphql>=1.8.0` resolves to) declares no croniter
dependency at all; resolving dagster_graphql alone produces no croniter.
- Nothing under ingestion/ imports croniter. The only importer in the repo is
openmetadata-airflow-apis, a separate distribution that does not declare it and picks
it up transitively from airflow.
- That importer is already running croniter 6.2.x: constraints-3.3.0 pins croniter==6.2.2
and the airflow images install under it, so 6.x compatibility for `croniter.is_valid` /
`get_prev` is established by the shipped image, not assumed here. The call site is also
behind an `is_airflow_3_or_higher()` guard and unreachable on Airflow 3.
Only the CI test environment resolved croniter 2.x, because it installs from the extras
without the constraints file. Removing the ceiling makes it match the images.
Verified with `uv pip compile --extra all --extra test` on both 3.10 and 3.12: resolves
to apache-airflow==3.3.1, croniter==6.2.4, dagster==1.13.18 with no conflict. This was
the only pin in the tree that collided with the airflow bump.
Code Review ✅ ApprovedBumps Apache Airflow from 3.3.0 to 3.3.1 across base images, constraints, and integration tests to resolve CVE-2026-67587 and CVE-2026-54183. No issues found. OptionsDisplay: compact → Showing less information. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source |
|
Greptile encountered an error while reviewing this PR. Please reach out to support@greptile.com for assistance and include this reference: |
CVE-2026-67587 (High) -- the Task SDK rebuilt a Serde
Callbackby re-running itsconstructor, which imports the module named by the stored callback path.
SyncCallbackis an Airflow class, so it passes the default
allowed_deserialization_classesallow-list and tightening that setting does not help. A Dag author controls a task
instance's
next_kwargs, so they can get an arbitrary module imported inside thescheduler process when the
awaiting_inputtimeout sweep deserializes that value. Nonon-default configuration is required.
CVE-2026-54183 (Medium) -- the secrets masker's recursion-depth limit did not descend
into values nested inside a list, tuple or set, so a Variable holding a deeply nested
sensitive value rendered unmasked in the Variables UI. Anyone who can see the Variable
in the UI can already read it through the Variables REST API, so this is a
shoulder-surfing defense rather than a disclosure boundary -- hence Medium.
Both are fixed in 3.3.1 and nothing in the 3.3.0 line is clean. The pin, both base
image tags, the vendored constraints file and the integration-test image move together,
as they did for 3.2.2 -> 3.3.0 in #31338.
The constraints file is a straight re-download this time. It carried two hand-patches
marked "keep on regeneration" -- impyla and thrift at 0.24.0 for CVE-2026-66053 /
CVE-2026-41608 / CVE-2026-48586, against upstream constraints-3.3.0 shipping
impyla==0.22.0 and thrift==0.16.0 -- and upstream constraints-3.3.1 now ships both at
0.24.0 natively. Diffing the vendored 3.3.0 file against upstream constraints-3.3.0
confirms those two blocks were the only divergence, and the new file is byte-identical
to upstream constraints-3.3.1 outside comments. The comments are kept, reworded to say
the pin is now upstream-native, so a future regeneration off a branch that regressed
either version still gets caught.
Two comments that name a constraint were checked rather than blind-renumbered:
applied because they pin chardet against openmetadata-ingestion's chardet==4.0.0.
Still true; the version moved 6.0.0.post1 -> 7.5.1, so the number is updated.
apache-airflow-core 3.3.1 still declares
universal-pathlib>=0.3.8and constraintsstill pin 0.3.10, so only the Airflow version in the prose changes.
Resolution verified with
uv pip compile --python-version 3.12 --extra airflow:apache-airflow==3.3.1 co-installs with every transitive floor pin in the airflow extra
(providers-http, -opensearch, -elasticsearch, tornado, Werkzeug, starlette,
python-multipart) with no conflict. sqlparse resolves to 0.5.4 there via
collate-sqllineage, unchanged by this PR -- the release images force 0.6.0 in
ingestion/operators/docker/Dockerfile, which does not consume this constraints file.
🤖 Generated with Claude Code
Greptile Summary
The PR upgrades the ingestion Airflow runtime from 3.3.0 to 3.3.1 to consume upstream security fixes.
Confidence Score: 5/5
The PR appears safe to merge because no blocking failure remains.
No blocking failure remains.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart LR A[Airflow 3.3.1 package pin] --> B[Production ingestion image] A --> C[CI ingestion image] D[Airflow 3.3.1 constraints] --> B D --> C A --> E[Integration-test image] B --> F[OpenMetadata managed APIs] C --> F E --> G[Airflow integration tests]Reviews (3): Last reviewed commit: "Merge branch 'main' into fix/airflow-3.3..." | Re-trigger Greptile
Context used: