This is an automated email from the ASF dual-hosted git repository.
jscheffl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new b3138e2400e Fix DiscordWebhookHook leaking webhook_endpoint as HTTP
header (#65736)
b3138e2400e is described below
commit b3138e2400eeed96863c9ced3ff2ff3e0ad7a519
Author: Sadha Chilukoori <[email protected]>
AuthorDate: Tue Apr 28 11:54:10 2026 -0700
Fix DiscordWebhookHook leaking webhook_endpoint as HTTP header (#65736)
HttpHook._configure_session_from_extra promotes all unrecognised extra
connection fields to session headers. The Discord connection stores
webhook_endpoint in extra, so it was being sent as an HTTP request
header on every call, causing Discord to return 400 Bad Request.
Override get_conn() in DiscordWebhookHook to strip webhook_endpoint
from the session headers after the parent builds the session.
Closes #65279
Co-authored-by: Sadha Chilukoori <[email protected]>
---
.../src/airflow/providers/discord/hooks/discord_webhook.py | 10 ++++++++++
.../discord/tests/unit/discord/hooks/test_discord_webhook.py | 6 ++++++
2 files changed, 16 insertions(+)
diff --git
a/providers/discord/src/airflow/providers/discord/hooks/discord_webhook.py
b/providers/discord/src/airflow/providers/discord/hooks/discord_webhook.py
index a29c7327012..fc2105b377f 100644
--- a/providers/discord/src/airflow/providers/discord/hooks/discord_webhook.py
+++ b/providers/discord/src/airflow/providers/discord/hooks/discord_webhook.py
@@ -27,6 +27,8 @@ from airflow.providers.common.compat.connection import
get_async_connection
from airflow.providers.http.hooks.http import HttpAsyncHook, HttpHook
if TYPE_CHECKING:
+ from requests import Session
+
from airflow.providers.common.compat.sdk import Connection
from airflow.providers.discord.notifications.embed import Embed
@@ -218,6 +220,14 @@ class DiscordWebhookHook(HttpHook):
conn = self.get_connection(http_conn_id)
return self.handler.get_webhook_endpoint(conn, webhook_endpoint)
+ def get_conn(
+ self, headers: dict[Any, Any] | None = None, extra_options: dict[str,
Any] | None = None
+ ) -> Session:
+ session = super().get_conn(headers=headers,
extra_options=extra_options)
+ # HttpHook promotes leftover extra fields to headers; strip the
Discord-specific one.
+ session.headers.pop("webhook_endpoint", None)
+ return session
+
def execute(self) -> None:
"""Execute the Discord webhook call."""
proxies = {}
diff --git a/providers/discord/tests/unit/discord/hooks/test_discord_webhook.py
b/providers/discord/tests/unit/discord/hooks/test_discord_webhook.py
index e644d23f249..3cf82c7f113 100644
--- a/providers/discord/tests/unit/discord/hooks/test_discord_webhook.py
+++ b/providers/discord/tests/unit/discord/hooks/test_discord_webhook.py
@@ -204,6 +204,12 @@ class TestDiscordWebhookHook:
# Then
assert webhook_endpoint == expected_webhook_endpoint
+ def test_get_conn_does_not_leak_webhook_endpoint_as_header(self):
+ """webhook_endpoint in connection extra must not be sent as an HTTP
header to Discord."""
+ hook = DiscordWebhookHook(http_conn_id="default-discord-webhook")
+ session = hook.get_conn()
+ assert "webhook_endpoint" not in session.headers
+
class TestDiscordWebhookAsyncHook:
@pytest.fixture(autouse=True)