Repository navigation
Description
Problem
The two lab-ops-hub crawl validators claim the same policy (pkgs/lab-ops-hub/src/lib.ts: "The Python container crawler applies the same policy independently"; pkgs/lab-ops-hub/container/app.py: "Only public http(s) targets"), but they disagree on IPv4 literals. Verified this run on main 668dd32f by calling both validators on the same 2,542 candidate URLs (special-range + boundary samples): 169 divergent verdicts, all TS blocks / Python allows.
1. Python container validator ALLOWS IPv4 multicast — TS blocks it
Python's plain-IPv4 path is just elif not ip.is_global: raise, and ipaddress reports is_global == True for multicast (verified: 224.0.0.1 → is_global True, is_multicast True):
| URL | Python (container/app.py validate_crawl_url) |
TS (src/lib.ts validateCrawlUrl) |
|---|---|---|
http://224.0.0.1/ … http://239.255.0.1/ (224.0.0.0/4) |
ALLOW | BLOCK (a >= 224 in ipv4IsGlobal) |
The container is the component that actually fetches. The same flaw reaches the embedded-IPv4 path: _embedded_ipv4 verdicts are judged with embedded.is_global, so e.g. an IPv4-mapped/NAT64 literal embedding a multicast address is also allowed. This is the IPv4 analogue of #474 (which fixed the IPv6 case by requiring global unicast 2000::/3 on the Python side — no equivalent guard exists for IPv4).
2. TS Worker validator over-blocks four public ranges as /16s instead of /24s
ipv4IsGlobal in src/lib.ts:26-41 keys the narrow special ranges on the second octet (b), so a /24 whose distinguishing octet is the third is widened to a /16 — contradicting its own comments:
| Code | Comment says | Actually blocks | Public addresses wrongly refused (Python: ALLOW) |
|---|---|---|---|
a===192 && b===0 |
192.0.0.0/24 + TEST-NET-1 192.0.2.0/24 | 192.0.0.0/16 | 192.0.1.1; also the global 192.0.0.9/192.0.0.10 exceptions inside the /24 |
a===192 && b===88 |
6to4 relay anycast (192.88.99.0/24) | 192.88.0.0/16 | 192.88.0.1, 192.88.1.1 |
a===198 && b===51 |
TEST-NET-2 (198.51.100.0/24) | 198.51.0.0/16 | 198.51.0.1, 198.51.1.1 |
a===203 && b===0 |
TEST-NET-3 (203.0.113.0/24) | 203.0.0.0/16 | 203.0.0.1, 203.0.1.1 |
Note the reverse gap inside the 6to4 row: Python allows 192.88.99.1 (is_global True), so the deprecated relay-anycast /24 the TS comment intends to refuse is only refused on the Worker path.
Because TS ipv4IsGlobal is reused for embedded IPv4 (IPv4-mapped, NAT64, 6to4 in ipv6IsGlobal), the over-blocks propagate to those IPv6 spellings too.
Why it matters
The validators are defence-in-depth for one SSRF policy (#441, #460–#474). The fetching component accepting the whole multicast range defeats the policy; the Worker refusing ordinary public addresses in four /16s is a correctness bug that also makes the two implementations impossible to keep in sync with shared test vectors.
Acceptance criteria
- Both validators refuse the multicast range, e.g.
224.0.0.1,230.1.2.3,239.255.255.255, including embedded spellings judged by a multicast IPv4 (e.g.[::ffff:224.0.0.1]). - Both validators refuse the narrow non-global /24s:
192.0.0.1(except the global192.0.0.9/192.0.0.10, which both accept),192.0.2.1,192.88.99.1,198.51.100.1,203.0.113.1. - Both validators accept the public neighbours the TS side currently over-blocks:
192.0.1.1,192.88.0.1,198.51.0.1,203.0.0.1, plus ordinary public targets (8.8.8.8). - The same test vectors appear in both suites (
test/lib.test.tsandtest/test_container_validate.py) with identical verdicts, in the style of the lab-ops-hub crawl validators don't judge NAT64/6to4 literals by their embedded IPv4 — Python allows embedded loopback/metadata, TS and Python disagree #472/lab-ops-hub crawl validators disagree on special IPv6 ranges — Python allows multicast/reserved, TS allows 2001::/23 specials #474 shared-vectors tests. - Suggested fix: in Python, do not trust
is_globalalone for IPv4 — also refuseis_multicastand192.88.99.0/24(plain and embedded paths). In TS, add the third octetctoipv4IsGlobaland narrow the four checks above to their commented /24s (with the 192.0.0.9/.10 exceptions).
Activity
Merge pull request #477 from developing-today/creator/476-ipv4-ranges