Hooks

network hook

Score one or many fetch destinations for SSRF, straight from the command line.

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.

node ./.lagune/hooks/network.mjs -u 'http://example.com/'
# => safe

node ./.lagune/hooks/network.mjs -u 'http://0x7f000001/'
# => private-target

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

VerdictMeaning
safeThe destination connects to a public host, and a sloppy validator would read the same host.
private-targetThe host resolves to a private, loopback, link-local, unspecified, or cloud-metadata address.
parser-divergentA sloppy text validator would read a different real host than the one the fetcher connects to.
invalid urlThe 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

OptionAliasValueDescription
--url-ua URL or hostCheck 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.

Why a flag value

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.

What it does not cover

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.

tip

This is the same check the network sub-skill runs to prove a destination filter holds.

Copyright © 2026-present Weslley Araújo and contributors. SDH: Lagune is under the MIT License. Please check the Security Policy.

All product names, trademarks, and registered trademarks mentioned are the property of their respective owners and are used for identification purposes only.