santifer/career-ops · info

Blocked request to restricted destination: ${requestUrl}

Error message

Blocked request to restricted destination: ${requestUrl}

What it means

Not a malfunction: this is the first layer of the SSRF egress guard in liveness-browser.mjs reporting that it aborted a request. rejectPrivateOrInvalid examined a URL emitted by the checked page and matched a private or invalid destination — localhost/127.0.0.1, RFC1918 ranges (10.x, 172.16-31.x, 192.168.x), link-local 169.254.x, IPv6-mapped forms, .local names, non-http(s) protocols (code unsupported_protocol), or an unparseable URL (code invalid_url) — and the route was aborted with blockedbyclient. The liveness check continues; only that subresource was refused.

Source

Thrown at liveness-browser.mjs:256

    }
  }
}

export async function checkUrlLiveness(page, url, { extraSettleMs = 0 } = {}) {
  const guardError = rejectPrivateOrInvalid(url);
  if (guardError) {
    return { result: 'uncertain', code: guardError.code, reason: guardError.reason };
  }
  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

View on GitHub (pinned to 60398d6549)

Solutions

  1. No action needed when the posting still renders — subresource blocks do not affect the verdict.
  2. If the MAIN document URL is the blocked one, you passed a private-network URL to the checker; re-run with the public posting URL.
  3. Do not disable the guard to silence the line — the block is the tool protecting your network from SSRF via fetched pages.
Defensive patterns

Strategy: validation

Validate before calling

import { rejectPrivateOrInvalid, validateUrlSecurity } from './liveness-browser.mjs';
const preflight =
  rejectPrivateOrInvalid(url) ??
  (await validateUrlSecurity(url).then(() => null, (e) => e));
if (preflight) throw new Error(`Refusing non-public URL up front: ${url}`);

Prevention

When it happens

Trigger: A checked posting page loads a tracker, script, or image from http://localhost:*, a private-range IP, a .local hostname, or a non-http(s) URI; every such request is aborted and logged with its URL.

Common situations: Career pages wired to internal-only analytics collectors; staging/dev pages left public; test setups deliberately pointing the checker at pages that reference internal hosts.

Related errors


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