SurfSense/surfsense_backend/app/proprietary
Nguyen Thanh Dat bdbd691c24 fix(crawler): refuse crawl targets that are not publicly routable
`crawl_url` validated its input with `validators.url` alone, which answers a
syntactic question and says nothing about where the URL points. Both
`http://127.0.0.1:8000/` and `http://169.254.169.254/latest/meta-data/` — the
cloud metadata endpoint — pass it and are then fetched from inside the
backend's own network namespace, by all three tiers in turn.

Resolve the target host before any tier runs and refuse it unless every
address it answers with is publicly routable. `crawl_url` is the single choke
point: the spider reaches it through `_ConnectorSession.fetch`, so the same
gate covers link-following, where a public page linking to an internal address
would otherwise be followed.

Two details the obvious implementation gets wrong:

  - `::ffff:127.0.0.1` reports `is_loopback == False`. The flags only read true
    on the mapped IPv4 form, so the mapping is unwrapped before the address is
    judged; reading them off the IPv6 object admits loopback under its v6
    spelling.
  - A union of `is_private`/`is_loopback`/`is_link_local`/`is_reserved`/
    `is_multicast` admits carrier-grade NAT (100.64.0.0/10, RFC 6598), which is
    not publicly routable. `is_global` covers that, but reports True for
    multicast, so multicast is excluded separately.

Resolution failures refuse, so an unreachable resolver is not a way past the
guard, and a host answering with both a public and a private address is
refused because the fetcher resolves independently and may pick either.

This narrows the reachable surface; it is not a defence against DNS rebinding,
which a resolve-then-fetch guard cannot address.

The malformed-URL and restricted-URL refusals carry distinct messages so the
two diagnoses stay apart. DNS blocks, so it is offloaded with
`asyncio.to_thread`, as the browser tiers already are.

Closes #1709
2026-08-31 16:33:24 +07:00
..
platforms Reapply "feat: Git remote exports, Google SERP parsing fixes, & testing video sandbox" 2026-08-29 19:51:37 +05:30
web_crawler fix(crawler): refuse crawl targets that are not publicly routable 2026-08-31 16:33:24 +07:00
__init__.py feat(03a): implement Scrapling-only web crawler and remove Firecrawl integration 2026-06-29 20:37:56 -07:00
LICENSE Update licensing information for SurfSense software 2026-07-02 03:28:42 -07:00