network hook
The network hook decides whether a server-side fetch destination is safe from SSRF (a request that can be aimed at internal services, cloud metadata, or private hosts). It is the deterministic engine behind the network sub-skill, and you can run it yourself.
Run it
Pass each destination with -u. The hook prints one word per destination, read in the table below.
- One destination
- Several destinations
node ./.lagune/hooks/network.mjs -u 'http://example.com/'
# => safe
node ./.lagune/hooks/network.mjs -u 'http://0x7f000001/'
# => private-target
Repeat -u to score a whole allowlist or denylist in one call, one verdict per line, in order.
node ./.lagune/hooks/network.mjs \
-u 'http://example.com/' \
-u 'http://[::1]/' \
# => safe
# => private-target
# => parser-divergent
It resolves the host the way the network does, so encoded forms of an internal address do not slip past: hex, octal, dotless decimal, shorthand, IPv6, and IPv4-mapped all read private-target. And where a sloppy validator and the real fetcher would read different hosts, the verdict is parser-divergent.
How to read the verdict
| Verdict | Meaning |
|---|---|
safe | The destination connects to a public host, and a sloppy validator would read the same host. |
private-target | The host resolves to a private, loopback, link-local, unspecified, or cloud-metadata address. |
parser-divergent | A sloppy text validator would read a different real host than the one the fetcher connects to. |
invalid url | The string does not parse as a URL, so there is nothing to fetch. |
Only safe is an allow. Treat private-target, parser-divergent, and invalid url all as a block.
CLI options
| Option | Alias | Value | Description |
|---|---|---|---|
--url | -u | a URL or host | Check one destination. Repeat to check several, one verdict per line. |
At least one -u is required. The destination is never a bare positional, so it cannot be mistaken for a flag.
Each destination is passed as a flag value, never interpolated into the command. A value with quotes or backticks stays inert and cannot inject into the shell. Always wrap it in single quotes so your shell does not expand it first.
The hook is pure and never resolves DNS, so two runtime gaps are out of scope: DNS rebinding (a name that resolves public when checked, internal when fetched) and redirect chains (a first hop that passes, then redirects inward). Close those by resolving once and connecting to the validated address, and by refusing redirects. It pins the reserved loopback names (localhost and the .localhost family) to internal with no lookup, but any other DNS name reads safe, because asserting it resolves inward would require resolution: the allowlist guards those, and is what this checker validates.
This is the same check the network sub-skill runs to prove a destination filter holds.
