Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Url Validator Laravel Package

craftcms/url-validator

Validate URLs and IP addresses before opening a connection to guard against SSRF and DNS rebinding. Rejects non-HTTP schemes, private/reserved/loopback addresses, cloud-metadata hosts, and IPv4-embedding IPv6, returning resolved IPs so you can pin the connection.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package is a framework-agnostic Composer library, not a Laravel package: no service provider, no publishable config, no facade. That is an advantage for a TPM — adoption is a composer require and a wrapper class, with no framework-version coupling and no upgrade treadmill tied to Laravel majors. Architecturally, though, it imposes a real constraint: the design is validate-then-pin. The validator returns the resolved IP set, and the HTTP client must be pinned to those IPs (e.g. CURLOPT_RESOLVE) for the protection to be meaningful. Validation without pinning is theatre. This means the package only fits workloads where we control the outbound client — our own Guzzle/Http calls, background jobs, and crawlers. It does not retrofit onto third-party SDKs that manage their own connection pools, and it does not protect traffic that goes through a managed egress proxy unless the proxy is doing equivalent checks.

Integration feasibility. Low engineering effort, moderate design effort. The library API is small (validate, validateIp, validateScheme, validateHostname), injectable DNS resolver, and an options array for schemes, disallowed hostnames, IPv4 ranges, and filter flags. The work is not in calling it — it is in the surrounding discipline: a shared wrapper, a form-request validation rule, manual redirect handling (Guzzle follows redirects and re-resolves DNS by default, which reopens the hole on hop two), re-validation inside queued jobs to close the submit-to-execute TOCTOU window, and connection pinning at the client. Expect roughly one engineer-week for a competent platform engineer to build and test a SafeUrlFetcher abstraction, plus per-team integration time to route existing fetches through it. No database, no migrations, no runtime services.

Technical risk. The security logic itself is the credible part: scheme allowlisting, IPv4/IPv6 range checks, IPv4-mapped/NAT64/6to4/Teredo unwrapping, hex and decimal hostname normalization, cloud-metadata domain coverage for AWS/GCP/Kubernetes, and multi-address checking. That is precisely the hard part teams get wrong when hand-rolling, and it is the main argument for adopting rather than building. The risks are around it: (1) Maturity — 1 star, 0 dependents, v1.1.0, README and changelog only. Blast radius of a regression is a security hole, so treat every version bump as a security review, not a routine composer update. (2) Maintenance continuity — published by Craft CMS (Pixel & Tonic), a reputable org, but with no dependents there is no ecosystem pressure keeping the blocklists current; the changelog is the only signal and it currently shows two releases. (3) Coverage gaps by design — metadata domain blocking is heuristic; the durable defence is the IP-range check plus network egress rules. (4) Developer-environment friction — localhost, *.local, 10.x, and Docker service names are rejected by default, which will break local workflows unless a dev-only allowlist is gated behind an environment check that cannot leak into production. (5) False confidence — the biggest risk is a team adopting it and then calling Http::get($url) without pinning.

Key questions.

  • Do we own every outbound client that will use this, or are some fetches buried inside SDKs we cannot pin?
  • Is there an egress firewall / VPC policy as a second layer, or is this library our only boundary?
  • Who is the named internal owner of the wrapper and of the bump-review process?
  • What is our policy if a bypass is found — fork, patch, or swap to an alternative? Do we have the source-read capability to triage?
  • Does our threat model include redirect chains, and do we have a hop limit policy (3–5)?
  • Do we have a dev/staging allowlist mechanism that is provably inert in production?
  • What is our logging/alerting story for rejected URLs, and who reviews it?

Integration Approach

Stack fit. Fits cleanly into a Laravel codebase as a plain Composer dependency. It should not be sprinkled through controllers; the right shape is a single platform-owned SafeUrlFetcher service (singleton-bound) that composes the validator, the pinned HTTP client, manual redirect handling, and structured logging on rejection. Teams then consume one internal API — a validation rule for form input, and a fetcher method for jobs and services. That keeps the vendor package behind one seam, which matters because swapping or patching it later becomes a one-file change.

Migration path. No migration in the data sense — no schema, no config to publish, no service provider to register. The migration is behavioural: inventory every endpoint and job where a user-supplied URL causes a server-side fetch (webhook registration and delivery, link previews/unfurling, avatar/remote-image import, RSS/feed ingestion, "import from URL" onboarding, PDF/screenshot generation, OAuth/OIDC discovery, sitemap crawlers, any AI browsing tool). Rank by exposure — unauthenticated endpoints first, then authenticated-but-low-trust, then internal admin. Each one gets rerouted through the wrapper; none get a bespoke call to the vendor class. Existing endpoints that already accept URLs are gap-closing candidates and should be tracked as remediation items with an owner and a date, not left as "backlog nice-to-have."

Compatibility. PHP-version and framework compatibility are effectively non-issues given the package is a small, dependency-light library; the real compatibility surface is the HTTP client. Guzzle supports CURLOPT_RESOLVE, so it works. Anything that abstracts away cURL options — higher-level SDK wrappers, some HTTP facades if configured restrictively — needs verification before it is declared in-scope. Note also that a hostname can return both a public A record and a private AAAA record; the pinning strategy must cover the address family the client actually uses, and all returned addresses must be checked, not just the first.

Sequencing.

  1. Decide the architecture — validate-then-pin versus managed egress proxy versus both. This decision shapes the whole egress layer and is expensive to retrofit; make it before the first URL-fetching feature ships.
  2. Build the shared wrapper — one SafeUrlFetcher plus a SafeUrl validation rule, with dev-only allowlisting and rejection logging baked in.
  3. Instrument before enforcing — run the wrapper in log-only mode against existing endpoints to size the false-positive rate and see what traffic you would block (internal services, partner hosts, CDN oddities).
  4. Enforce on the highest-risk surface, then expand endpoint by endpoint.
  5. Codify — document the pattern, add a PR checklist item ("does this fetch a user-supplied URL?"), and make the wrapper the only sanctioned way to do outbound fetches in review guidelines.
  6. Bump-review process — pin the version, commit the lockfile, and require a changelog read on every upgrade.

Operational Impact

Maintenance. Low ongoing cost in code, non-trivial in attention. The package is small and stable, so there is little to patch; the maintenance burden is the periodic review of the blocklists and options as new cloud providers and metadata endpoints appear, and the discipline of upgrading deliberately rather than automatically. With one star and zero dependents there is no community canary — we are the ones who notice a regression. Budget for a named owner and a quarterly review, plus a policy that any version bump gets a diff read from someone who can reason about SSRF.

Support. Vendor support is essentially "MIT licence and a security policy" — no SLA, no paid tier, no guaranteed response on a disclosed bypass. That is normal for a small security library from a reputable org, but it must be an explicit accepted risk in the security review, not an assumption. Internally, the wrapper owner is the support path: teams file against the wrapper, the platform team triages against the vendor or patches locally. Incident response needs a documented path for "a URL got through" — revoke, patch, audit logs, notify — because the failure mode is silent by default.

Scaling. Computationally negligible: one DNS resolution per validation, which is a rounding error against the outbound HTTP request it guards. The scaling concern is architectural, not throughput. Validate-then-pin couples the fetcher to a specific client and complicates pooling and connection reuse; at high fetch volume the cleaner answer is a dedicated fetch service or egress proxy that performs these checks centrally, with the library as the in-process guard closer to the edge. If fetch volume grows enough that per-request DNS becomes a latency item, the injectable resolver is the lever — plug in a caching resolver, keeping TTLs short enough not to undermine the rebinding defence.

Failure modes. Enumerate them explicitly, because each needs a defined behaviour:

  • Fail-open on library exception — if the validator throws, does the fetch proceed? It must not. Default to deny.
  • Pinning skipped or unsupported — the single most likely real-world failure. Detected by code review and by keeping the vendor class out of team code.
  • Redirect bypass — allow_redirects left on, or a hop limit that is too generous. Manual redirect handling with a 3–5 hop cap is the control.
  • DNS rebinding between validate and connect — mitigated only by pinning; otherwise the library buys a false sense of safety.
  • Development-environment lockout — localhost and Docker hostnames blocked, blocking engineers; needs a gated allowlist.
  • False positives on legitimate internal fetches — internal services on 10.x, partner hosts resolving to private ranges; surfaced by the log-only phase.
  • Blocklist staleness — a new metadata endpoint not in the domain list; mitigated by the IP-range check and egress rules.
  • Silent rejection with no telemetry — no signal, no threat intel; log structured rejections with host and reason and alert on spikes.

Ramp-up. Short for engineers, longer for the organisation. A competent backend engineer will read the README and the src/ directory in under an hour and be productive with the wrapper the same day. The organisational ramp is the real work: getting every team that fetches user URLs to route through one wrapper, changing review habits so unpinned fetches get flagged, and getting security comfortable that the accepted risk around a low-maturity dependency is documented. Realistic estimate: one platform engineer for a week to build and instrument the wrapper, one to two sprints of incremental integration across consuming teams, and roughly a quarter before the pattern is habitual and the log-only phase has been retired. The opportunity score of 55.25 reads correctly here — high strategic value as a guardrail for features we want to ship, low market validation, so the decision is "adopt deliberately behind a wrapper with egress defence as a second layer," not "adopt and forget."

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log