Harden webhook authentication and outbound fetch handling#13
Merged
kshahbw merged 11 commits intoJul 15, 2026
Conversation
Strip brackets from IPv6-literal hostnames before the isIP() fast path so literals like https://[::1]/ are classified against the blocklist instead of silently falling through, and wrap DNS resolution failures (including the default resolver's ENOTFOUND throw) in EgressBlockedError so callers that pattern-match on the typed error get a consistent fail-closed result.
Add an onRequest hook that enforces HTTP Basic auth (via safeEqual) on every /bw/* route, gated by new required AdapterConfig fields webhookUser/webhookPassword. The REST facade keeps its own separate authOk check and is unaffected. Updates all existing tests that hit /bw/* or build an AdapterConfig to supply the new fields and, where applicable, the Authorization header, plus the local bench script.
Update stale test count in README and make SECURITY.md / egress-guard.ts honest about the range denylist not defending against DNS rebinding.
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
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
Hardens the adapter's authentication and outbound-fetch handling. The adapter now authenticates the webhooks Bandwidth sends it, constrains where it will make server-side requests, and compares credentials in constant time.
What changed
safeEqualhelper built oncrypto.timingSafeEqual(replaces the previous!==string comparisons)./bw/*routes now require HTTP Basic auth (WEBHOOK_USER/WEBHOOK_PASSWORD), matching Bandwidth's nativeCallbackCredsmechanism. This is a distinct secret from the Twilio-compat REST credential. The translator stamps the same credentials onto the BXML callback verbs it emits, so Bandwidth presents them on continuation callbacks.http/https, and loopback/link-local/private IP ranges (IPv4, IPv6, IPv4-mapped) are refused. Redirects are disabled and a request timeout is applied.127.0.0.1; setHOST=0.0.0.0to expose it (containers/production).EGRESS_ALLOW_HOSTSswitches outbound fetches to a strict default-deny allowlist for deployments with fixed, known customer hosts.SECURITY.mddocumenting the auth model, the egress guard (and its defense-in-depth boundary), and setup.WEBHOOK_USER,WEBHOOK_PASSWORD(also set the matchingCallbackCredson your Bandwidth Voice application).127.0.0.1. Containerized/exposed deployments must setHOST=0.0.0.0.EGRESS_ALLOW_PRIVATE=1(local dev againstlocalhost/LAN),EGRESS_ALLOW_HOSTS(strict allowlist).Testing
Full suite green: 303/303 (
npm test), typecheck clean. Adds coverage for the egress guard (range classification, IPv6-literal + IPv4-mapped handling, redirect/timeout), inbound auth (401 on missing/wrong creds, REST facade not unlocked by webhook creds), and callback-credential stamping.🤖 Generated with Claude Code