-- 27_ssrf.sql: SSRF classification of endpoint URLs at validation time. -- 00_setup turns the guard off for the suite; this session turns it back on. -- Only address literals and numeric forms are used, so no DNS is needed. SET ulak.http_allow_internal_urls = off; SELECT url, ulak.validate_endpoint_config('http', jsonb_build_object('url', url)) AS accepted FROM (VALUES (1, 'http://127.0.0.1/hook'), (2, 'http://LocalHost:8080/hook'), (3, 'http://[::1]/hook'), (4, 'http://[::]/hook'), -- Linux connects :: to ::1 (5, 'http://0.0.0.0/hook'), (6, 'http://2130706433/hook'), -- 127.0.0.1 as one number (7, 'http://0x7f.1/hook'), -- 127.0.0.1 in hex shorthand (8, 'http://169.254.169.254/latest/meta-data'), (9, 'http://100.64.0.1/hook'), (10, 'http://255.255.255.255/hook'), (11, 'http://[::ffff:10.0.0.1]/hook'), -- IPv4-mapped (12, 'http://[64:ff9b::a9fe:a9fe]/hook'), -- NAT64 form of 169.254.169.254 (13, 'http://[fe80::1]/hook'), (14, 'http://[fd00::1]:8443/hook'), (15, 'http://8.8.8.8/hook'), (16, 'https://[2001:4860:4860::8888]:8443/hook'), (17, 'http://[64:ff9b::808:808]/hook'), -- NAT64 form of 8.8.8.8 (18, 'http://:8080/hook'), -- no host (19, 'http://[2001:db8::1/hook') -- unterminated IPv6 literal ) AS t(n, url) ORDER BY n; WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] SSRF blocked: '2130706433' resolves to internal/private address 127.0.0.1 WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] SSRF blocked: '0x7f.1' resolves to internal/private address 127.0.0.1 WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: HTTP config URL targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: HTTP config URL host could not be resolved WARNING: [ulak] ERROR: HTTP config URL host could not be resolved url | accepted ------------------------------------------+---------- http://127.0.0.1/hook | f http://LocalHost:8080/hook | f http://[::1]/hook | f http://[::]/hook | f http://0.0.0.0/hook | f http://2130706433/hook | f http://0x7f.1/hook | f http://169.254.169.254/latest/meta-data | f http://100.64.0.1/hook | f http://255.255.255.255/hook | f http://[::ffff:10.0.0.1]/hook | f http://[64:ff9b::a9fe:a9fe]/hook | f http://[fe80::1]/hook | f http://[fd00::1]:8443/hook | f http://8.8.8.8/hook | t https://[2001:4860:4860::8888]:8443/hook | t http://[64:ff9b::808:808]/hook | t http://:8080/hook | f http://[2001:db8::1/hook | f (19 rows) -- The OAuth2 token endpoint goes through the same check SELECT ulak.validate_endpoint_config('http', '{"url": "http://8.8.8.8/hook", "auth": {"type": "oauth2", "token_url": "http://[::]/token", "client_id": "id", "client_secret": "secret"}}'::jsonb) AS token_url_unspecified; WARNING: [ulak] OAuth2 token_url targets internal/private network address (SSRF protection) WARNING: [ulak] ERROR: Invalid HTTP auth configuration token_url_unspecified ----------------------- f (1 row) SELECT ulak.validate_endpoint_config('http', '{"url": "http://8.8.8.8/hook", "auth": {"type": "oauth2", "token_url": "https://8.8.4.4/token", "client_id": "id", "client_secret": "secret"}}'::jsonb) AS token_url_public; token_url_public ------------------ t (1 row) RESET ulak.http_allow_internal_urls;