Repository navigation
fix(security): add outbound URL guard for stream webhooks - #1864
Open
devogechukwu wants to merge 1 commit into
Open
devogechukwu wants to merge 1 commit into
devogechukwu wants to merge 1 commit into
Conversation
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.
Closes #1727
Summary of Changes
Adds a shared outbound URL guard and applies it to
POST /api/streams/[id]/webhooks/testandPATCH /api/v2/streams/[id]to block SSRF and port scanning attacks.Shared Outbound URL Guard (
app/lib/outbound-url.ts):https:in production (http:is permitted only in local/dev environments when not resolving to private or restricted addresses).user:pass@).443,8443, and80in development).dns.promises.lookupwith{ all: true }) and verifies that every resolved IP is public; returns the pinned IP address for the delivery client to mitigate DNS rebinding.Blocked IP Ranges (with RFC References):
0.0.0.0/8— RFC 1122 (Current network)10.0.0.0/8— RFC 1918 (Private address space)100.64.0.0/10— RFC 6598 (Shared Address Space / CGNAT)127.0.0.0/8— RFC 1122 (Loopback)169.254.0.0/16— RFC 3927 (Link-Local / Cloud Metadata)172.16.0.0/12— RFC 1918 (Private address space)192.0.0.0/24— RFC 6890 (IETF Protocol Assignments)192.0.2.0/24— RFC 5737 (Documentation TEST-NET-1)192.88.99.0/24— RFC 7526 (6to4 Relay Anycast)192.168.0.0/16— RFC 1918 (Private address space)198.18.0.0/15— RFC 2544 (Benchmarking)198.51.100.0/24— RFC 5737 (Documentation TEST-NET-2)203.0.113.0/24— RFC 5737 (Documentation TEST-NET-3)224.0.0.0/4— RFC 5771 (Multicast)240.0.0.0/4— RFC 1112 (Reserved / Class E & Broadcast)255.255.255.255— Broadcast::/128,::1/128(RFC 4291 Loopback),fe80::/10(RFC 4291 Link-Local),fc00::/7(RFC 4193 ULA),ff00::/8(RFC 4291 Multicast),::ffff:0:0/96(IPv4-mapped IPv6), and64:ff9b::/96(RFC 6052 Translation)Route Protections (
POST /api/streams/[id]/webhooks/test):400 UNSAFE_ENDPOINT_URLprior to dispatch.401if unauthenticated,403if unauthorized).redirect: "manual"), categorizing redirects asnon_2xxwithout following hops.success,status_code, and sanitized categories (timeout,non_2xx,connection_failed) without raw internal error texts.Persistence Protection (
PATCH /api/v2/streams/[id]):validatePatchStreamBodyasynchronously validateswebhook_urlagainstassertSafeOutboundUrl, returning422 VALIDATION_ERRORwith field-level details on unsafe hosts.Test Suite & Security Documentation:
app/api/streams/[id]/webhooks/test/route.test.tsfromjest.config.js.app/lib/outbound-url.test.tscovering all scenarios (IP ranges, DNS mocking, redirect handling, port restrictions, credentials rejection, production enforcement).SECURITY.md.Test Plan Coverage
http://169.254.169.254/-> Rejectedhttp://127.0.0.1:8080,http://[::1]/,http://[::ffff:10.0.0.1]/-> Rejectedhttps://hooks.example.comresolving to10.1.2.3-> Rejectedhttps://hooks.example.comresolving to public IP -> Accepted, pinned address returnedhttps://user:pw@hooks.example.com-> Rejectedhttp://in a production env -> Rejectednon_2xx400 UNSAFE_ENDPOINT_URL; delivery client not calledwebhook_urlto a private host ->422field error