From 82c82e23e706d29e939440be46b39f648dfc0278 Mon Sep 17 00:00:00 2001 From: Leah Restad Date: Mon, 20 Apr 2026 14:01:12 -0700 Subject: [PATCH 1/3] adding ip ranges --- .github/workflows/check-license-headers.yml | 78 ++++ .github/workflows/update-ip-ranges.yml | 53 +++ .gitignore | 2 + CONTRIBUTING.md | 33 ++ config/IPAddressRanges.json | 439 ++++++++++++++++++++ csharp/config/IPAddressRanges.cs | 47 +++ nodejs/config/IPAddressRanges.ts | 43 ++ scripts/build-ip-ranges-cs.sh | 73 ++++ scripts/build-ip-ranges-nodejs.sh | 58 +++ 9 files changed, 826 insertions(+) create mode 100644 .github/workflows/check-license-headers.yml create mode 100644 .github/workflows/update-ip-ranges.yml create mode 100644 CONTRIBUTING.md create mode 100644 config/IPAddressRanges.json create mode 100644 csharp/config/IPAddressRanges.cs create mode 100644 nodejs/config/IPAddressRanges.ts create mode 100755 scripts/build-ip-ranges-cs.sh create mode 100755 scripts/build-ip-ranges-nodejs.sh diff --git a/.github/workflows/check-license-headers.yml b/.github/workflows/check-license-headers.yml new file mode 100644 index 0000000..5e8e1e7 --- /dev/null +++ b/.github/workflows/check-license-headers.yml @@ -0,0 +1,78 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +name: Check License Headers + +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +jobs: + check-license: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Check license headers + run: | + echo "Checking for required license headers..." + + # Define the required headers for different file types + HEADER_HASH="# Copyright (c) Microsoft Corporation." + HEADER_SLASH="// Copyright (c) Microsoft Corporation." + + # Find files that should have headers + files_to_check=$(find . -type f \( \ + -name "*.cs" -o \ + -name "*.ts" -o \ + -name "*.js" -o \ + -name "*.sh" -o \ + -name "*.yml" -o \ + -name "*.yaml" \ + \) \ + -not -path "./.git/*" \ + -not -path "./node_modules/*" \ + -not -path "./**/bin/*" \ + -not -path "./**/obj/*") + + missing_headers=() + + for file in $files_to_check; do + echo "Checking: $file" + + # Check based on file extension + case "$file" in + *.sh|*.yml|*.yaml) + if ! head -5 "$file" | grep -q "# Copyright (c) Microsoft Corporation."; then + missing_headers+=("$file") + fi + ;; + *.cs|*.ts|*.js) + if ! head -5 "$file" | grep -q "// Copyright (c) Microsoft Corporation."; then + missing_headers+=("$file") + fi + ;; + esac + done + + # Report results + if [ ${#missing_headers[@]} -eq 0 ]; then + echo "✅ All files have required license headers" + else + echo "❌ The following files are missing license headers:" + printf '%s\n' "${missing_headers[@]}" + echo "" + echo "Please add the appropriate header to each file:" + echo "For .sh/.yml/.yaml files:" + echo " # Copyright (c) Microsoft Corporation." + echo " # Licensed under the MIT License." + echo "" + echo "For .cs/.ts/.js files:" + echo " // Copyright (c) Microsoft Corporation." + echo " // Licensed under the MIT License." + exit 1 + fi \ No newline at end of file diff --git a/.github/workflows/update-ip-ranges.yml b/.github/workflows/update-ip-ranges.yml new file mode 100644 index 0000000..47aab87 --- /dev/null +++ b/.github/workflows/update-ip-ranges.yml @@ -0,0 +1,53 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +name: Verify IP Address Ranges + +on: + pull_request: + paths: + - 'config/IPAddressRanges.json' + - 'nodejs/config/IPAddressRanges.ts' + - 'csharp/config/IPAddressRanges.cs' + push: + branches: [main] + paths: + - 'config/IPAddressRanges.json' + - 'nodejs/config/IPAddressRanges.ts' + - 'csharp/config/IPAddressRanges.cs' + workflow_dispatch: # Allow manual triggering + +jobs: + verify-ranges: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install jq + run: sudo apt-get update && sudo apt-get install -y jq + + - name: Make scripts executable + run: chmod +x scripts/*.sh + + - name: Build Node.js/TypeScript version + run: ./scripts/build-ip-ranges-nodejs.sh + + - name: Build C# version + run: ./scripts/build-ip-ranges-cs.sh + + - name: Verify generated files are up-to-date + run: | + if ! git diff --exit-code nodejs/config/IPAddressRanges.ts csharp/config/IPAddressRanges.cs; then + echo "❌ Generated IP address range files are out of sync!" + echo "The following files need to be regenerated:" + git diff --name-only nodejs/config/IPAddressRanges.ts csharp/config/IPAddressRanges.cs + echo "" + echo "Please run the following commands locally and commit the results:" + echo " ./scripts/build-ip-ranges-nodejs.sh" + echo " ./scripts/build-ip-ranges-cs.sh" + exit 1 + else + echo "✅ All generated files are up-to-date" + fi diff --git a/.gitignore b/.gitignore index ce89292..83cde20 100644 --- a/.gitignore +++ b/.gitignore @@ -416,3 +416,5 @@ FodyWeavers.xsd *.msix *.msm *.msp + +.DS_Store \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..83e069e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,33 @@ +# Contributing to AntiSSRF + +Thank you for your interest in contributing to the AntiSSRF project! This guide will help you get started. + +## Development Setup + +1. Clone the repository +2. Install dependencies for your target language (C# or Node.js) +3. Make your changes +4. Test thoroughly +5. Submit a pull request + +## Updating IP Address Ranges + +The IP address ranges are maintained in [`config/IPAddressRanges.json`](config/IPAddressRanges.json) and automatically generated into language-specific files. + +### Prerequisites +Install `jq`: `brew install jq` (macOS) or `sudo apt-get install jq` (Linux) + +### Process +1. **Edit** [`config/IPAddressRanges.json`](config/IPAddressRanges.json) +2. **Regenerate** the code files: + ```bash + ./scripts/build-ip-ranges-nodejs.sh + ./scripts/build-ip-ranges-cs.sh + ``` +3. **Commit** all changes (JSON + generated files): + ```bash + git add config/IPAddressRanges.json nodejs/config/IPAddressRanges.ts csharp/config/IPAddressRanges.cs + git commit -m "Update IP address ranges" + ``` + +**Important**: The GitHub Actions workflow will fail if generated files don't match the source JSON. diff --git a/config/IPAddressRanges.json b/config/IPAddressRanges.json new file mode 100644 index 0000000..005a9eb --- /dev/null +++ b/config/IPAddressRanges.json @@ -0,0 +1,439 @@ +{ + "_sources": { + "ianaIpv4": { + "title": "IANA IPv4 Special-Purpose Address Registry", + "url": "https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml", + "last_updated": "2025-10-09" + }, + "ianaIpv6": { + "title": "IANA IPv6 Special-Purpose Address Registry", + "url": "https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml", + "last_updated": "2025-10-09" + }, + "ianaIpv4Multicast": { + "title": "IANA IPv4 Multicast Address Space", + "url": "https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml", + "last_updated": "2026-01-27" + }, + "ianaIpv6Multicast": { + "title": "IANA IPv6 Multicast Address Space", + "url": "https://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xhtml", + "last_updated": "2026-02-02" + }, + "imds": { + "title": "Microsoft Learn Azure Instance Metadata Service", + "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service?tabs=windows", + "last_updated": "NA" + }, + "wireserver": { + "title": "Microsoft Learn Azure IP Address 168.63.129.16 Overview", + "url": "https://learn.microsoft.com/en-us/azure/virtual-network/what-is-ip-address-168-63-129-16?tabs=windows", + "last_updated": "NA" + }, + "siteLocal": { + "title": "Microsoft Learn IPv6 Link-local and Site-local Addresses", + "url": "https://learn.microsoft.com/en-us/windows/win32/winsock/link-local-and-site-local-addresses-2", + "last_updated": "NA" + } + }, + "amt": { + "purpose": "AMT", + "cidr": [ + "192.52.193.0/24", + "2001:3::/32" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4", + "ianaIpv6" + ] + }, + "as112": { + "purpose": "AS112", + "cidr": [ + "192.31.196.0/24", + "192.175.48.0/24", + "2001:4:112::/48", + "2620:4f:8000::/48" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4", + "ianaIpv6" + ] + }, + "benchmarking": { + "purpose": "Benchmarking", + "cidr": [ + "198.18.0.0/15", + "2001:2::/48" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4", + "ianaIpv6" + ] + }, + "deprecated": { + "purpose": "Deprecated", + "cidr": [ + "192.88.99.0/24", + "2001:10::/28" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4", + "ianaIpv6" + ] + }, + "detsPrefix": { + "purpose": "Drone Remote ID Protocol Entity Tags (DETs) Prefix", + "cidr": [ + "2001:30::/28" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv6" + ] + }, + "discardOnly": { + "purpose": "Discard-Only Address Block", + "cidr": [ + "100::/64" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv6" + ] + }, + "dnsSdAnycast": { + "purpose": "DNS-SD Service Registration Protocol Anycast", + "cidr": [ + "2001:1::3/128" + ], + "standaloneVariable": false, + "_sources": [ + "ianaIpv6" + ] + }, + "documentation": { + "purpose": "Documentation", + "cidr": [ + "192.0.2.0/24", + "198.51.100.0/24", + "203.0.113.0/24", + "2001:db8::/32", + "3fff::/20" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4", + "ianaIpv6" + ] + }, + "dummy": { + "purpose": "Dummy address", + "cidr": [ + "192.0.0.8/32", + "100:0:0:1::/64" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4", + "ianaIpv6" + ] + }, + "ietfProtocol": { + "purpose": "IETF Protocol Assignments", + "cidr": [ + "192.0.0.0/24", + "2001::/23" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4", + "ianaIpv6" + ] + }, + "imds": { + "purpose": "Instance Metadata Service", + "cidr": [ + "169.254.169.254/32" + ], + "standaloneVariable": true, + "_sources": [ + "imds" + ] + }, + "ipv4Ipv6Translat": { + "purpose": "IPv4-IPv6 Translated", + "cidr": [ + "64:ff9b::/96", + "64:ff9b:1::/48" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv6" + ] + }, + "ipv4ServiceContinuity": { + "purpose": "IPv4 Service Continuity Prefix", + "cidr": [ + "192.0.0.0/29" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4" + ] + }, + "broadcast": { + "purpose": "Limited Broadcast", + "cidr": [ + "255.255.255.255/32" + ], + "standaloneVariable": false, + "_sources": [ + "ianaIpv4" + ] + }, + "linkLocal": { + "purpose": "Link Local", + "cidr": [ + "169.254.0.0/16", + "fe80::/10" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4", + "ianaIpv6", + "siteLocal" + ] + }, + "loopback": { + "purpose": "Loopback", + "cidr": [ + "127.0.0.0/8", + "::1/128" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4", + "ianaIpv6" + ] + }, + "multicast": { + "purpose": "Multicast", + "cidr": [ + "224.0.0.0/4", + "ff00::/8" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4Multicast", + "ianaIpv6Multicast" + ] + }, + "nat64Dns64Discovery": { + "purpose": "NAT64/DNS64 Discovery", + "cidr": [ + "192.0.0.170/32", + "192.0.0.171/32" + ], + "standaloneVariable": false, + "_sources": [ + "ianaIpv4" + ] + }, + "orchidv2": { + "purpose": "ORCHIDv2", + "cidr": [ + "2001:20::/28" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv6" + ] + }, + "pcpAnycast": { + "purpose": "Port Control Protocol Anycast", + "cidr": [ + "192.0.0.9/32", + "2001:1::1/128" + ], + "standaloneVariable": false, + "_sources": [ + "ianaIpv4", + "ianaIpv6" + ] + }, + "privateUse": { + "purpose": "Private-Use", + "cidr": [ + "10.0.0.0/8", + "172.16.0.0/12", + "192.168.0.0/16" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4" + ] + }, + "reserved": { + "purpose": "Reserved", + "cidr": [ + "240.0.0.0/4" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4" + ] + }, + "sharedAddressSpace": { + "purpose": "Shared Address Space", + "cidr": [ + "100.64.0.0/10" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4" + ] + }, + "siteLocal": { + "purpose": "Site Local", + "cidr": [ + "fec0::/10" + ], + "standaloneVariable": true, + "_sources": [ + "siteLocal" + ] + }, + "six4aaRelayAnycast": { + "purpose": "6a44-relay Anycast Address", + "cidr": [ + "192.88.99.2/32" + ], + "standaloneVariable": false, + "_sources": [ + "ianaIpv4" + ] + }, + "sixto4": { + "purpose": "6to4", + "cidr": [ + "2002::/16" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv6" + ] + }, + "srv6Sid": { + "purpose": "Segment Routing (SRv6) SIDs", + "cidr": [ + "5f00::/16" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv6" + ] + }, + "teredo": { + "purpose": "TEREDO", + "cidr": [ + "2001::/32" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv6" + ] + }, + "turnAnycast": { + "purpose": "Traversal Using Relays around NAT Anycast", + "cidr": [ + "192.0.0.10/32", + "2001:1::2/128" + ], + "standaloneVariable": false, + "_sources": [ + "ianaIpv4", + "ianaIpv6" + ] + }, + "uniqueLocal": { + "purpose": "Unique Local Unicast", + "cidr": [ + "fc00::/7" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv6" + ] + }, + "unspecified": { + "purpose": "This host on this network; unspecified address", + "cidr": [ + "0.0.0.0/8", + "::/128" + ], + "standaloneVariable": true, + "_sources": [ + "ianaIpv4", + "ianaIpv6" + ] + }, + "wireserver": { + "purpose": "Azure WireServer", + "cidr": [ + "168.63.129.16/32" + ], + "standaloneVariable": true, + "_sources": [ + "wireserver" + ] + }, + "recommendedV1": { + "purpose": "Current list of recommended special-purpose addresses", + "cidr": [ + "0.0.0.0/8", + "10.0.0.0/8", + "100.64.0.0/10", + "127.0.0.0/8", + "168.63.129.16/32", + "169.254.0.0/16", + "172.16.0.0/12", + "192.0.0.0/24", + "192.0.2.0/24", + "192.31.196.0/24", + "192.52.193.0/24", + "192.88.99.0/24", + "192.168.0.0/16", + "192.175.48.0/24", + "198.18.0.0/15", + "198.51.100.0/24", + "203.0.113.0/24", + "224.0.0.0/4", + "240.0.0.0/4", + "::1/128", + "::/128", + "64:ff9b::/96", + "64:ff9b:1::/48", + "100::/64", + "100:0:0:1::/64", + "2001::/23", + "2001:db8::/32", + "2002::/16", + "2620:4f:8000::/48", + "3fff::/20", + "5f00::/16", + "fc00::/7", + "fe80::/10", + "fec0::/10", + "ff00::/8" + ], + "standaloneVariable": true, + "_notes": [ + "Skipping the following CIDR ranges that are already included in other CIDR ranges: 169.254.169.254/32, 192.0.0.0/29, 192.0.0.8/32, 192.0.0.9/32, 192.0.0.10/32, 192.0.0.170/32, 192.0.0.171/32, 192.88.99.2/32, 255.255.255.255/32, 2001::/32, 2001:1::1/128, 2001:1::2/128, 2001:1::3/128, 2001:2::/48, 2001:3::/32, 2001:4:112::/48, 2001:10::/28, 2001:20::/28, 2001:30::/28" + ] + } +} \ No newline at end of file diff --git a/csharp/config/IPAddressRanges.cs b/csharp/config/IPAddressRanges.cs new file mode 100644 index 0000000..3805c2a --- /dev/null +++ b/csharp/config/IPAddressRanges.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Auto-generated from IPAddressRanges.json +// Do not edit this file manually + +namespace Microsoft.Security.AntiSSRF +{ + /// + /// Static IP address ranges for AntiSSRF protection + /// + public static class IPAddressRanges + { + public static readonly string[] amt = { "192.52.193.0/24", "2001:3::/32" }; + public static readonly string[] as112 = { "192.31.196.0/24", "192.175.48.0/24", "2001:4:112::/48", "2620:4f:8000::/48" }; + public static readonly string[] benchmarking = { "198.18.0.0/15", "2001:2::/48" }; + public static readonly string[] deprecated = { "192.88.99.0/24", "2001:10::/28" }; + public static readonly string[] detsPrefix = { "2001:30::/28" }; + public static readonly string[] discardOnly = { "100::/64" }; + public static readonly string[] documentation = { "192.0.2.0/24", "198.51.100.0/24", "203.0.113.0/24", "2001:db8::/32", "3fff::/20" }; + public static readonly string[] dummy = { "192.0.0.8/32", "100:0:0:1::/64" }; + public static readonly string[] ietfProtocol = { "192.0.0.0/24", "2001::/23" }; + public static readonly string[] imds = { "169.254.169.254/32" }; + public static readonly string[] ipv4Ipv6Translat = { "64:ff9b::/96", "64:ff9b:1::/48" }; + public static readonly string[] ipv4ServiceContinuity = { "192.0.0.0/29" }; + public static readonly string[] linkLocal = { "169.254.0.0/16", "fe80::/10" }; + public static readonly string[] loopback = { "127.0.0.0/8", "::1/128" }; + public static readonly string[] multicast = { "224.0.0.0/4", "ff00::/8" }; + public static readonly string[] orchidv2 = { "2001:20::/28" }; + public static readonly string[] privateUse = { "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16" }; + public static readonly string[] reserved = { "240.0.0.0/4" }; + public static readonly string[] sharedAddressSpace = { "100.64.0.0/10" }; + public static readonly string[] siteLocal = { "fec0::/10" }; + public static readonly string[] sixto4 = { "2002::/16" }; + public static readonly string[] srv6Sid = { "5f00::/16" }; + public static readonly string[] teredo = { "2001::/32" }; + public static readonly string[] uniqueLocal = { "fc00::/7" }; + public static readonly string[] unspecified = { "0.0.0.0/8", "::/128" }; + public static readonly string[] wireserver = { "168.63.129.16/32" }; + public static readonly string[] recommendedV1 = { "0.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "127.0.0.0/8", "168.63.129.16/32", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", "192.88.99.0/24", "192.168.0.0/16", "192.175.48.0/24", "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "224.0.0.0/4", "240.0.0.0/4", "::1/128", "::/128", "64:ff9b::/96", "64:ff9b:1::/48", "100::/64", "100:0:0:1::/64", "2001::/23", "2001:db8::/32", "2002::/16", "2620:4f:8000::/48", "3fff::/20", "5f00::/16", "fc00::/7", "fe80::/10", "fec0::/10", "ff00::/8" }; + + /// + /// recommendedLatest always points to the latest version + /// + public static readonly string[] recommendedLatest = recommendedV1; + } +} diff --git a/nodejs/config/IPAddressRanges.ts b/nodejs/config/IPAddressRanges.ts new file mode 100644 index 0000000..4c256db --- /dev/null +++ b/nodejs/config/IPAddressRanges.ts @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Auto-generated from IPAddressRanges.json +// Do not edit this file manually + +/** + * Static IP address ranges for AntiSSRF protection + */ +export class IPAddressRanges { + public static readonly amt: string[] = ["192.52.193.0/24", "2001:3::/32"]; + public static readonly as112: string[] = ["192.31.196.0/24", "192.175.48.0/24", "2001:4:112::/48", "2620:4f:8000::/48"]; + public static readonly benchmarking: string[] = ["198.18.0.0/15", "2001:2::/48"]; + public static readonly deprecated: string[] = ["192.88.99.0/24", "2001:10::/28"]; + public static readonly detsPrefix: string[] = ["2001:30::/28"]; + public static readonly discardOnly: string[] = ["100::/64"]; + public static readonly documentation: string[] = ["192.0.2.0/24", "198.51.100.0/24", "203.0.113.0/24", "2001:db8::/32", "3fff::/20"]; + public static readonly dummy: string[] = ["192.0.0.8/32", "100:0:0:1::/64"]; + public static readonly ietfProtocol: string[] = ["192.0.0.0/24", "2001::/23"]; + public static readonly imds: string[] = ["169.254.169.254/32"]; + public static readonly ipv4Ipv6Translat: string[] = ["64:ff9b::/96", "64:ff9b:1::/48"]; + public static readonly ipv4ServiceContinuity: string[] = ["192.0.0.0/29"]; + public static readonly linkLocal: string[] = ["169.254.0.0/16", "fe80::/10"]; + public static readonly loopback: string[] = ["127.0.0.0/8", "::1/128"]; + public static readonly multicast: string[] = ["224.0.0.0/4", "ff00::/8"]; + public static readonly orchidv2: string[] = ["2001:20::/28"]; + public static readonly privateUse: string[] = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]; + public static readonly reserved: string[] = ["240.0.0.0/4"]; + public static readonly sharedAddressSpace: string[] = ["100.64.0.0/10"]; + public static readonly siteLocal: string[] = ["fec0::/10"]; + public static readonly sixto4: string[] = ["2002::/16"]; + public static readonly srv6Sid: string[] = ["5f00::/16"]; + public static readonly teredo: string[] = ["2001::/32"]; + public static readonly uniqueLocal: string[] = ["fc00::/7"]; + public static readonly unspecified: string[] = ["0.0.0.0/8", "::/128"]; + public static readonly wireserver: string[] = ["168.63.129.16/32"]; + public static readonly recommendedV1: string[] = ["0.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "127.0.0.0/8", "168.63.129.16/32", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", "192.88.99.0/24", "192.168.0.0/16", "192.175.48.0/24", "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "224.0.0.0/4", "240.0.0.0/4", "::1/128", "::/128", "64:ff9b::/96", "64:ff9b:1::/48", "100::/64", "100:0:0:1::/64", "2001::/23", "2001:db8::/32", "2002::/16", "2620:4f:8000::/48", "3fff::/20", "5f00::/16", "fc00::/7", "fe80::/10", "fec0::/10", "ff00::/8"]; + + /** + * recommendedLatest always points to the latest version + */ + public static readonly recommendedLatest: string[] = IPAddressRanges.recommendedV1; +} diff --git a/scripts/build-ip-ranges-cs.sh b/scripts/build-ip-ranges-cs.sh new file mode 100755 index 0000000..932c472 --- /dev/null +++ b/scripts/build-ip-ranges-cs.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# Script to build IPAddressRanges.cs from IPAddressRanges.json +# Only includes cidr ranges as C# static readonly arrays + +set -e + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +JSON_FILE="$SCRIPT_DIR/../config/IPAddressRanges.json" +CS_FILE="$SCRIPT_DIR/../csharp/config/IPAddressRanges.cs" + +# Check if jq is available +if ! command -v jq &> /dev/null; then + echo "Error: jq is required but not installed. Install with: brew install jq" + exit 1 +fi + +# Check if JSON file exists +if [[ ! -f "$JSON_FILE" ]]; then + echo "Error: IPAddressRanges.json not found in $SCRIPT_DIR" + exit 1 +fi + +# Create directory if it doesn't exist +mkdir -p "$(dirname "$CS_FILE")" + +# Generate C# file +cat > "$CS_FILE" << 'EOF' +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Auto-generated from IPAddressRanges.json +// Do not edit this file manually + +namespace Microsoft.Security.AntiSSRF +{ + /// + /// Static IP address ranges for AntiSSRF protection + /// + public static class IPAddressRanges + { +EOF + +# Generate individual field declarations +jq -r ' + to_entries + | map(select(.key != "_sources" and .value.standaloneVariable == true)) + | .[] + | " public static readonly string[] " + .key + " = { " + (.value.cidr | map("\"" + . + "\"") | join(", ")) + " };" +' "$JSON_FILE" >> "$CS_FILE" + +# Add recommendedLatest property that matches recommendedV1 +cat >> "$CS_FILE" << 'EOF' + + /// + /// recommendedLatest always points to the latest version + /// + public static readonly string[] recommendedLatest = recommendedV1; +EOF + + + +# Close the class and namespace +cat >> "$CS_FILE" << 'EOF' + } +} +EOF + +echo "Successfully generated $CS_FILE" \ No newline at end of file diff --git a/scripts/build-ip-ranges-nodejs.sh b/scripts/build-ip-ranges-nodejs.sh new file mode 100755 index 0000000..b0b27d6 --- /dev/null +++ b/scripts/build-ip-ranges-nodejs.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# Script to build IPAddressRanges.ts from IPAddressRanges.json +# Generates a TypeScript class with static readonly properties + +set -e + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +JSON_FILE="$SCRIPT_DIR/../config/IPAddressRanges.json" +TS_FILE="$SCRIPT_DIR/../nodejs/config/IPAddressRanges.ts" + +# Check if jq is available +if ! command -v jq &> /dev/null; then + echo "Error: jq is required but not installed. Install with: brew install jq" + exit 1 +fi + +# Check if JSON file exists +if [[ ! -f "$JSON_FILE" ]]; then + echo "Error: IPAddressRanges.json not found in $SCRIPT_DIR" + exit 1 +fi + +# Generate TypeScript file +echo "// Copyright (c) Microsoft Corporation." > "$TS_FILE" +echo "// Licensed under the MIT License." >> "$TS_FILE" +echo "" >> "$TS_FILE" +echo "// Auto-generated from IPAddressRanges.json" >> "$TS_FILE" +echo "// Do not edit this file manually" >> "$TS_FILE" +echo "" >> "$TS_FILE" +echo "/**" >> "$TS_FILE" +echo " * Static IP address ranges for AntiSSRF protection" >> "$TS_FILE" +echo " */" >> "$TS_FILE" +echo "export class IPAddressRanges {" >> "$TS_FILE" + +# Generate individual property declarations +jq -r ' + to_entries + | map(select(.key != "_sources" and .value.standaloneVariable == true)) + | .[] + | " public static readonly " + .key + ": string[] = [" + (.value.cidr | map("\"" + . + "\"") | join(", ")) + "];" +' "$JSON_FILE" >> "$TS_FILE" + +# Add recommendedLatest property that matches recommendedV1 +echo "" >> "$TS_FILE" +echo " /**" >> "$TS_FILE" +echo " * recommendedLatest always points to the latest version" >> "$TS_FILE" +echo " */" >> "$TS_FILE" +echo " public static readonly recommendedLatest: string[] = IPAddressRanges.recommendedV1;" >> "$TS_FILE" + +# Close the class +echo "}" >> "$TS_FILE" + +echo "Successfully generated $TS_FILE" \ No newline at end of file From 33a7ae18c1dcb1e009d21e261649f52b2b8dea1e Mon Sep 17 00:00:00 2001 From: Leah Restad Date: Mon, 20 Apr 2026 14:15:55 -0700 Subject: [PATCH 2/3] update node version to fix github actions warning --- .github/workflows/check-license-headers.yml | 4 +++- .github/workflows/update-ip-ranges.yml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-license-headers.yml b/.github/workflows/check-license-headers.yml index 5e8e1e7..22621c1 100644 --- a/.github/workflows/check-license-headers.yml +++ b/.github/workflows/check-license-headers.yml @@ -12,10 +12,12 @@ on: jobs: check-license: runs-on: ubuntu-latest + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Check license headers run: | diff --git a/.github/workflows/update-ip-ranges.yml b/.github/workflows/update-ip-ranges.yml index 47aab87..db80b69 100644 --- a/.github/workflows/update-ip-ranges.yml +++ b/.github/workflows/update-ip-ranges.yml @@ -20,10 +20,12 @@ on: jobs: verify-ranges: runs-on: ubuntu-latest + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install jq run: sudo apt-get update && sudo apt-get install -y jq From 4b0d5c358c2c2d083b08f4015082ef8a1b81a8a8 Mon Sep 17 00:00:00 2001 From: Leah Restad Date: Mon, 20 Apr 2026 14:37:06 -0700 Subject: [PATCH 3/3] feedback from emmie --- config/IPAddressRanges.json | 2 +- csharp/config/IPAddressRanges.cs | 1 + nodejs/config/IPAddressRanges.ts | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/config/IPAddressRanges.json b/config/IPAddressRanges.json index 005a9eb..8ef68eb 100644 --- a/config/IPAddressRanges.json +++ b/config/IPAddressRanges.json @@ -191,7 +191,7 @@ "cidr": [ "255.255.255.255/32" ], - "standaloneVariable": false, + "standaloneVariable": true, "_sources": [ "ianaIpv4" ] diff --git a/csharp/config/IPAddressRanges.cs b/csharp/config/IPAddressRanges.cs index 3805c2a..2b79bbb 100644 --- a/csharp/config/IPAddressRanges.cs +++ b/csharp/config/IPAddressRanges.cs @@ -23,6 +23,7 @@ public static class IPAddressRanges public static readonly string[] imds = { "169.254.169.254/32" }; public static readonly string[] ipv4Ipv6Translat = { "64:ff9b::/96", "64:ff9b:1::/48" }; public static readonly string[] ipv4ServiceContinuity = { "192.0.0.0/29" }; + public static readonly string[] broadcast = { "255.255.255.255/32" }; public static readonly string[] linkLocal = { "169.254.0.0/16", "fe80::/10" }; public static readonly string[] loopback = { "127.0.0.0/8", "::1/128" }; public static readonly string[] multicast = { "224.0.0.0/4", "ff00::/8" }; diff --git a/nodejs/config/IPAddressRanges.ts b/nodejs/config/IPAddressRanges.ts index 4c256db..130e9a9 100644 --- a/nodejs/config/IPAddressRanges.ts +++ b/nodejs/config/IPAddressRanges.ts @@ -20,6 +20,7 @@ export class IPAddressRanges { public static readonly imds: string[] = ["169.254.169.254/32"]; public static readonly ipv4Ipv6Translat: string[] = ["64:ff9b::/96", "64:ff9b:1::/48"]; public static readonly ipv4ServiceContinuity: string[] = ["192.0.0.0/29"]; + public static readonly broadcast: string[] = ["255.255.255.255/32"]; public static readonly linkLocal: string[] = ["169.254.0.0/16", "fe80::/10"]; public static readonly loopback: string[] = ["127.0.0.0/8", "::1/128"]; public static readonly multicast: string[] = ["224.0.0.0/4", "ff00::/8"];