diff --git a/packages/server/src/notify_bridge_server/api/app_settings.py b/packages/server/src/notify_bridge_server/api/app_settings.py index d37d17e..1515633 100644 --- a/packages/server/src/notify_bridge_server/api/app_settings.py +++ b/packages/server/src/notify_bridge_server/api/app_settings.py @@ -100,6 +100,13 @@ async def update_settings( if value is None: continue value_str = str(value) + # GET masks the webhook secret as "***" so the real value is + # never exposed to the frontend. If the client sends the mask back + # (which happens on every save, since bind:value holds whatever GET + # returned), treat it as "unchanged" — otherwise we'd overwrite the + # real secret with its mask, silently breaking webhook HMAC. + if key == "telegram_webhook_secret" and value_str.startswith("***"): + continue row = await session.get(AppSetting, key) if row: row.value = value_str