You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The SMS adapter's inbound webhook handler (/webhooks/twilio) performs zero authentication on incoming requests. Since the official docs instruct users to expose the webhook to the internet (directly or via ngrok/cloudflared), any attacker who can reach the endpoint can inject forged SMS messages that the agent processes with full tool access, including terminal execution (unauthenticated RCE).
We confirmed this manually: a single curl with a forged payload caused the agent to create an arbitrary file on disk via the terminal tool.
This PR adds X-Twilio-Signature validation (HMAC-SHA1) using stdlib-only crypto (hmac, hashlib, base64), so no new dependencies. The implementation is fail-closed: the adapter refuses to start without SMS_WEBHOOK_URL configured, with an explicit opt-out (SMS_INSECURE_NO_SIGNATURE=true) for local development.
This PR introduces an intentional breaking change for SMS adapter users. On upgrade, the SMS adapter will refuse to start unless one of the following is set:
SMS_WEBHOOK_URL — the public URL configured in your Twilio console (e.g. https://example.com/webhooks/twilio). This enables Twilio signature validation. Recommended.
SMS_INSECURE_NO_SIGNATURE=true — disables signature validation with a loud warning. For local development only. Not recommended for production.
Why this is necessary: Without this change, every existing and new SMS deployment is silently vulnerable to unauthenticated remote code execution. The previous behavior (no validation, no warning) cannot remain the default.
Migration effort is minimal: Every SMS user already knows their webhook URL — they configured it in the Twilio console. Setting SMS_WEBHOOK_URL to that same value is a one-time change.
Changes Made
gateway/platforms/base.py — Added is_network_accessible() as a shared utility (moved from api_server.py), added ipaddress and socket imports
gateway/platforms/api_server.py — Removed local _is_network_accessible(), imports from base instead, removed unused ipaddress import
gateway/platforms/sms.py:
Added hashlib, hmac imports and is_network_accessible import from base
Added DEFAULT_WEBHOOK_HOST constant and SMS_WEBHOOK_HOST / SMS_WEBHOOK_URL /SMS_INSECURE_NO_SIGNATURE env vars
Added fail-closed startup guard: refuses to start without SMS_WEBHOOK_URL (unless explicitly opted out)
Added _validate_twilio_signature(), _check_signature(), and _port_variant_url() methods implementing Twilio's HMAC-SHA1 signature algorithm with timing-safe comparison
Verify fail-closed behavior: Start the gateway with SMS enabled but without SMS_WEBHOOK_URL: TWILIO_ACCOUNT_SID=ACtest TWILIO_AUTH_TOKEN=tok TWILIO_PHONE_NUMBER=+15550000000 hermes gateway
Expected: adapter refuses to start with:
[sms] Refusing to start: SMS_WEBHOOK_URL is required for Twilio signature validation.
Expected: adapter starts with warning, forged curl returns HTTP 200 (vulnerable, as intended for dev).
Verify signature validation: Set SMS_WEBHOOK_URL=https://your-domain/webhooks/twilio and restart. A forged curl without X-Twilio-Signature returns HTTP 403:
curl -X POST http://127.0.0.1:8080/webhooks/twilio \
-d 'From=%2B15551234567&To=%2B15550000000&Body=forged&MessageSid=SMfake'
Expected: HTTP 403 and log [sms] Rejected: missing X-Twilio-Signature header
This PR contains patterns commonly associated with supply chain attacks. This does not mean the PR is malicious — but these patterns require careful human review before merging.
⚠️ WARNING: base64 encoding/decoding detected
Base64 has legitimate uses (images, JWT, etc.) but is also commonly used to obfuscate malicious payloads. Verify the usage is appropriate.
This PR contains patterns commonly associated with supply chain attacks. This does not mean the PR is malicious — but these patterns require careful human review before merging.
⚠️ WARNING: base64 encoding/decoding detected
Base64 has legitimate uses (images, JWT, etc.) but is also commonly used to obfuscate malicious payloads. Verify the usage is appropriate.
This PR contains patterns commonly associated with supply chain attacks. This does not mean the PR is malicious — but these patterns require careful human review before merging.
⚠️ WARNING: base64 encoding/decoding detected
Base64 has legitimate uses (images, JWT, etc.) but is also commonly used to obfuscate malicious payloads. Verify the usage is appropriate.
This PR contains patterns commonly associated with supply chain attacks. This does not mean the PR is malicious — but these patterns require careful human review before merging.
⚠️ WARNING: base64 encoding/decoding detected
Base64 has legitimate uses (images, JWT, etc.) but is also commonly used to obfuscate malicious payloads. Verify the usage is appropriate.
Merged via PR #7933. Your commits were cherry-picked onto current main with your authorship preserved in git log. Thanks for the thorough implementation, @entropidelic — fail-closed design, port variant handling, and the keep_blank_values fix were all excellent.
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
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.
What does this PR do?
The SMS adapter's inbound webhook handler (/webhooks/twilio) performs zero authentication on incoming requests. Since the official docs instruct users to expose the webhook to the internet (directly or via ngrok/cloudflared), any attacker who can reach the endpoint can inject forged SMS messages that the agent processes with full tool access, including terminal execution (unauthenticated RCE).
We confirmed this manually: a single curl with a forged payload caused the agent to create an arbitrary file on disk via the terminal tool.
This PR adds
X-Twilio-Signaturevalidation (HMAC-SHA1) using stdlib-only crypto (hmac, hashlib, base64), so no new dependencies. The implementation is fail-closed: the adapter refuses to start withoutSMS_WEBHOOK_URLconfigured, with an explicit opt-out (SMS_INSECURE_NO_SIGNATURE=true) for local development.Related Issue
Fixes #7089
Type of Change
This PR introduces an intentional breaking change for SMS adapter users. On upgrade, the SMS adapter will refuse to start unless one of the following is set:
SMS_WEBHOOK_URL— the public URL configured in your Twilio console (e.g. https://example.com/webhooks/twilio). This enables Twilio signature validation. Recommended.SMS_INSECURE_NO_SIGNATURE=true— disables signature validation with a loud warning. For local development only. Not recommended for production.Why this is necessary: Without this change, every existing and new SMS deployment is silently vulnerable to unauthenticated remote code execution. The previous behavior (no validation, no warning) cannot remain the default.
Migration effort is minimal: Every SMS user already knows their webhook URL — they configured it in the Twilio console. Setting SMS_WEBHOOK_URL to that same value is a one-time change.
Changes Made
How to Test
[sms] Refusing to start: SMS_WEBHOOK_URL is required for Twilio signature validation.
SMS_INSECURE_NO_SIGNATURE=true hermes gateway
curl -X POST http://127.0.0.1:8080/webhooks/twilio \ -d 'From=%2B15551234567&To=%2B15550000000&Body=forged&MessageSid=SMfake'