fix(security): validate secret in _reload_dynamic_routes to prevent HMAC bypass (#8306)#30370
Merged
Conversation
Covers _reload_dynamic_routes() rejecting empty or missing per-route secrets when no global fallback exists, preserving the INSECURE_NO_AUTH opt-in, inheriting a global secret when only the per-route value is missing, and partial-skip when only one of multiple routes is bad.
Contributor
🔎 Lint report:
|
6 tasks
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Salvages @memosr's PR #8306. Closes an HMAC bypass that let an agent-induced webhook subscription with an empty
secretreach the request handler — empty string is falsy at line 356 ofgateway/platforms/webhook.py, so the signature check was skipped and unauthenticated POSTs executed the webhook prompt with full tool access.Root cause
_reload_dynamic_routes()(called on every webhook POST via mtime gate) merged any dynamic route intoself._routeswithout secret validation. Startup-time validation inconnect()only fires once; the hot-reload path bypassed it entirely.Changes
gateway/platforms/webhook.py(+20 -5): per-route secret validation inside_reload_dynamic_routes(). Routes with an effectively empty secret (no per-route value and no global fallback) are skipped with a WARNING log.INSECURE_NO_AUTHopt-in is preserved.tests/gateway/test_webhook_dynamic_routes.py(+80 -1): 6 new regression cases — empty rejected, missing-no-global rejected, missing-with-global inherits,INSECURE_NO_AUTHpreserved, WARN logged, partial-skip.Validation
secret=""secret, global setsecret, no globalsecret=INSECURE_NO_AUTHTargeted tests:
tests/gateway/test_webhook_dynamic_routes.py— 12/12 pass.Full webhook suite (6 files): 105/105 pass.
Attribution
Salvaged via plain cherry-pick of @memosr's commit so original authorship survives. Closes #8306 once merged; follow-up close-with-credit will be posted on the original PR thread.
Infographic