{"record":{"id":"492b44708cb8773a","repo":"badges/shields","slug":"domain-is-blocked","errorCode":null,"errorMessage":"domain is blocked","messagePattern":"domain is blocked","errorType":"validation","errorClass":"InvalidParameter","httpStatus":400,"severity":"error","filePath":"services/endpoint/endpoint.service.js","lineNumber":196,"sourceCode":"    const config = configModule.util.toObject()\n    this._allowUnsecuredEndpointRequests =\n      config?.public?.allowUnsecuredEndpointRequests || false\n  }\n\n  async handle(namedParams, { url }) {\n    let protocol, hostname\n    try {\n      const parsedUrl = new URL(url)\n      protocol = parsedUrl.protocol\n      hostname = parsedUrl.hostname\n    } catch (e) {\n      throw new InvalidParameter({ prettyMessage: 'invalid url' })\n    }\n    if (protocol !== 'https:' && !this._allowUnsecuredEndpointRequests) {\n      throw new InvalidParameter({ prettyMessage: 'please use https' })\n    }\n    if (blockedDomains.some(domain => hostname.endsWith(domain))) {\n      throw new InvalidParameter({ prettyMessage: 'domain is blocked' })\n    }\n\n    const validated = await fetchEndpointData(this, {\n      url,\n      httpErrors,\n      validationPrettyErrorMessage: 'invalid properties',\n      includeKeys: true,\n    })\n\n    return this.constructor.render(validated)\n  }\n}\n","sourceCodeStart":178,"sourceCodeEnd":209,"githubUrl":"https://github.com/badges/shields/blob/766fd8bc89a90b8534dc573ab72dec30215ab1ec/services/endpoint/endpoint.service.js#L178-L209","documentation":"The endpoint service maintains a blocked-domains list; after parsing the URL it rejects any hostname whose suffix matches an entry in that list, throwing InvalidParameter with prettyMessage 'domain is blocked'. This is a server-side SSRF/misuse mitigation for user-supplied endpoint URLs.","triggerScenarios":"Calling /badge/endpoint with a url whose hostname ends with a blocked domain (e.g. localhost, .local, or any domain on the instance's blocklist).","commonSituations":"Trying to point the endpoint badge at internal hosts (localhost, 127.0.0.1, metadata services); the target domain was recently added to the blocklist; a subdomain of a blocked domain is used.","solutions":["Use a publicly reachable, allowlisted domain for the endpoint data","If self-hosting, review and adjust the blocked-domains configuration only if the domain is legitimately safe","Host the data on a different domain that is not blocked"],"exampleFix":"// before\n/badge/endpoint?url=https://localhost:8080/data.json  // blocked\n// after\n/badge/endpoint?url=https://myapi.example.com/data.json","handlingStrategy":"validation","validationCode":"const BLOCKED = ['localhost', '.local', '.internal']\nfunction isAllowedHost(url) {\n  try {\n    const h = new URL(url).hostname\n    return !BLOCKED.some(d => h.endsWith(d))\n  } catch { return false }\n}\n// check the hostname against the instance blocklist before building the badge","typeGuard":null,"tryCatchPattern":"try {\n  const badge = await getEndpointBadge({ url })\n} catch (e) {\n  if (e.prettyMessage === 'domain is blocked') {\n    console.error(`Domain not allowed for endpoint badge: ${new URL(url).hostname}`)\n  } else throw e\n}","preventionTips":["Host badge data on public domains, never on localhost/internal names","Check the instance's blocked-domain list when self-hosting","Avoid subdomains of blocked domains — suffix matching applies","Use an approved public endpoint or proxy if internal data must be exposed"],"tags":["security","ssrf","domain-blocklist","invalid-parameter"],"backgroundTag":"domain-blocked-by-server","analyzedSha":"766fd8bc89a90b8534dc573ab72dec30215ab1ec","analyzedAt":"2026-08-30T01:40:27.499Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}