From faaf998c7bfbbcd233e77c591b859f8fe328ee46 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sun, 22 Mar 2026 09:57:22 -0700 Subject: [PATCH] fix(security): add Azure metadata endpoint to SSRF blocklist Add metadata.azure.internal to BLOCKED_METADATA_HOSTS alongside the existing AWS/GCP endpoints. Closes the coverage gap identified in #125. Co-Authored-By: Claude Opus 4.6 (1M context) --- browse/src/url-validation.ts | 1 + browse/test/url-validation.test.ts | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/browse/src/url-validation.ts b/browse/src/url-validation.ts index 1ce8c45b..11163d82 100644 --- a/browse/src/url-validation.ts +++ b/browse/src/url-validation.ts @@ -7,6 +7,7 @@ const BLOCKED_METADATA_HOSTS = new Set([ '169.254.169.254', // AWS/GCP/Azure instance metadata 'fd00::', // IPv6 unique local (metadata in some cloud setups) 'metadata.google.internal', // GCP metadata + 'metadata.azure.internal', // Azure IMDS ]); /** diff --git a/browse/test/url-validation.test.ts b/browse/test/url-validation.test.ts index f87f4e84..f1dd301e 100644 --- a/browse/test/url-validation.test.ts +++ b/browse/test/url-validation.test.ts @@ -42,6 +42,10 @@ describe('validateNavigationUrl', () => { expect(() => validateNavigationUrl('http://metadata.google.internal/computeMetadata/v1/')).toThrow(/cloud metadata/i); }); + it('blocks Azure metadata hostname', () => { + expect(() => validateNavigationUrl('http://metadata.azure.internal/metadata/instance')).toThrow(/cloud metadata/i); + }); + it('blocks metadata hostname with trailing dot', () => { expect(() => validateNavigationUrl('http://metadata.google.internal./computeMetadata/v1/')).toThrow(/cloud metadata/i); });