Skip to content

Extending

Extending

Everything is a contract bound in the container, so you override by rebinding.

A custom resolver

Supply your own DNS view — an internal resolver, a cache, a pinned map — by binding the Resolver contract:

use Cbox\Ssrf\Contracts\Resolver;

$this->app->singleton(Resolver::class, function () {
    return new class implements Resolver {
        public function resolve(string $host): array
        {
            // consult your resolver; return a list of IP strings
        }
    };
});

The guard calls this once per validation and pins the connection to what it returns, so a resolver that already enforces an internal policy composes cleanly.

Tuning the policy

The policy is built from config/ssrf.php. Publish it and edit the lists; the GuardPolicy singleton reads them at boot. For a fully programmatic policy, bind GuardPolicy yourself:

use Cbox\Ssrf\GuardPolicy;

$this->app->singleton(GuardPolicy::class, fn () => new GuardPolicy(
    allowedSchemes: ['https'],           // https only
    blockedHostSuffixes: ['.internal'],
    // …
));

Wrapping a different HTTP client

The guard is client-agnostic. pinnedOptions() returns Guzzle-style options (allow_redirects, on_stats, curl), which Laravel's HTTP client accepts directly. For a bespoke Guzzle client, spread them into your request options after calling assertSafe():

$guard->assertSafe($url);
$client->request('GET', $url, $guard->pinnedOptions($url));

Swapping the whole guard

Bind your own UrlGuard implementation to replace the behaviour entirely — the Http::ssrf() macro, the PublicUrl rule, and every caller resolve the contract, so they all pick up your implementation.