santifer/career-ops · info

Blocked request to restricted destination (DNS): ${requestUr

Error message

Blocked request to restricted destination (DNS): ${requestUrl} - ${err.message}

What it means

The guard's second layer — validateUrlSecurity — resolved the request's hostname with real DNS (resolve4 + resolve6 + lookup) and either got no addresses at all (dead host, tagged livenessCode 'dns_no_addresses') or got addresses inside private/loopback space ('Access denied: Egress guard blocked private target IP', a DNS-rebinding-shaped hit). The request is aborted either way. Per the 2026-08-14 measurement note in the source, a dead third-party host (shut-down trackers like addthis) must NOT poison the verdict — only the main document failing to resolve says the posting itself is dead.

Source

Thrown at liveness-browser.mjs:264

  }
  if (page) {
    page._blockedByGuard = null;
  }
  if (page && typeof page.route === 'function' && !page._routeInterceptorRegistered) {
    page._routeInterceptorRegistered = true;
    await page.route('**/*', async (route) => {
      const requestUrl = route.request().url();
      const errGuard = rejectPrivateOrInvalid(requestUrl);
      if (errGuard) {
        console.warn(`Blocked request to restricted destination: ${requestUrl}`);
        page._blockedByGuard = errGuard;
        return route.abort('blockedbyclient');
      }
      try {
        await validateUrlSecurity(requestUrl);
        return route.continue();
      } catch (err) {
        console.warn(`Blocked request to restricted destination (DNS): ${requestUrl} - ${err.message}`);
        // A host that resolves to nothing is a DEAD THIRD-PARTY SCRIPT, not a
        // statement about the posting. Measured 2026-08-14 over a 217-URL
        // recheck: 78 live postings were returned as `uncertain` because an
        // analytics or ad host on the page no longer exists — 53 on
        // personalisation.visitorqueue.com, 17 on s7.addthis.com (AddThis was
        // shut down in 2023), the rest on fluidads and cloudfront. One was
        // opened by hand to confirm: 11,178 characters of live posting and a
        // working apply control, called uncertain because of a dead tracker.
        //
        // The request is still aborted either way, so the egress guard loses
        // nothing. Only the VERDICT stops being poisoned, and only for a
        // subresource: if the main document itself cannot resolve, that is a
        // real finding about the posting and still counts.
        // Whether this was the main document or a subresource can only be asked
        // of a real Playwright request. Callers may pass a lighter route double
        // (the test suite does, with request() returning just a url()), and for
        // those the answer is unknowable — so default to TRUE, which keeps the
        // pre-existing behaviour of poisoning the verdict. The relaxation only

View on GitHub (pinned to 60398d6549)

Solutions

  1. Treat as noise if the verdict is still live/dead based on the main document — dead subresource hosts are expected on old pages.
  2. If MANY hosts trip it or everything returns uncertain, check your own DNS: dig the blocked hostname and look for wildcard or internal answers (VPN, captive portal).
  3. Confirm the posting's own hostname resolves publicly before re-running the check.
Defensive patterns

Strategy: validation

Validate before calling

import dns from 'node:dns/promises';
const addrs = await dns.lookup(host, { all: true }).catch(() => []);
const isPrivate = (a) => /^(10\.|127\.|169\.254\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.|::1|f[cd])/i.test(a);
if (addrs.length === 0 || addrs.some((x) => isPrivate(x.address))) {
  console.warn(`host ${host} is dead or resolves privately — expect guard blocks`);
}

Prevention

When it happens

Trigger: The page references analytics hosts that no longer exist (ENOTFOUND → dns_no_addresses); a public hostname resolves into 10.x/127.0.0.1/169.254.x (rebinding — hard block); corporate DNS, VPN split-DNS, or a captive portal resolves every name to an internal IP, so every subresource trips the guard.

Common situations: Old job postings with dead trackers; VPN split-DNS wildcards; captive portals resolving all hosts to a login IP; restrictive corporate resolvers.

Related errors


AI-assisted analysis of santifer/career-ops@60398d6549 (2026-08-20). Data as JSON: /api/errors/95dc9e618c1db51a. Report an issue: GitHub.