{"record":{"id":"769b179dba863025","repo":"phacility/phabricator","slug":"associated-hook-s-for-webhook-request-s-769b17","errorCode":null,"errorMessage":"Associated hook (\"%s\") for webhook request (\"%s\") has invalid fetch URI: %s","messagePattern":"Associated hook \\(\"(.+?)\"\\) for webhook request \\(\"(.+?)\"\\) has invalid fetch URI: (.+?)","errorType":"exception","errorClass":"PhabricatorWorkerPermanentFailureException","httpStatus":null,"severity":"error","filePath":"src/applications/herald/worker/HeraldWebhookWorker.php","lineNumber":72,"sourceCode":"          'Associated hook (\"%s\") for webhook request (\"%s\") is disabled.',\n          $hook->getPHID(),\n          $request_phid));\n    }\n\n    $uri = $hook->getWebhookURI();\n    try {\n      PhabricatorEnv::requireValidRemoteURIForFetch(\n        $uri,\n        array(\n          'http',\n          'https',\n        ));\n    } catch (Exception $ex) {\n      $this->failRequest(\n        $request,\n        HeraldWebhookRequest::ERRORTYPE_HOOK,\n        HeraldWebhookRequest::ERROR_URI);\n      throw new PhabricatorWorkerPermanentFailureException(\n        pht(\n          'Associated hook (\"%s\") for webhook request (\"%s\") has invalid '.\n          'fetch URI: %s',\n          $hook->getPHID(),\n          $request_phid,\n          $ex->getMessage()));\n    }\n\n    $object_phid = $request->getObjectPHID();\n\n    $object = id(new PhabricatorObjectQuery())\n      ->setViewer($viewer)\n      ->withPHIDs(array($object_phid))\n      ->executeOne();\n    if (!$object) {\n      $this->failRequest(\n        $request,\n        HeraldWebhookRequest::ERRORTYPE_HOOK,","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/herald/worker/HeraldWebhookWorker.php#L54-L90","documentation":"The hook's URI must pass PhabricatorEnv::requireValidRemoteURIForFetch(): protocol must be http or https, the domain must be present and DNS-resolvable, and no resolved address may sit on the outbound blacklist (loopback, link-local, and other internal ranges) unless allowlisted. On failure the request is marked ERROR_URI and the task permanently fails, embedding the underlying reason from the caught exception.","triggerScenarios":"Webhook URI set to something like http://localhost:9000/hooks, https://10.0.0.5/hook, a domain that resolves to 127.0.0.1, or a non-http(s) scheme; DNS for the target domain not resolvable from the Phabricator host.","commonSituations":"Pointing webhooks at internal/dev endpoints on the same network or host (blocked as SSRF protection); containerized installs where DNS differs from the operator's machine; scheme typos like 'htt://' or 'ftp://'.","solutions":["Read the embedded reason (%s from the exception) -- it names the exact failed check (protocol, unresolvable domain, or blacklisted address).","Point the hook at a resolvable, non-blacklisted https endpoint reachable from the Phabricator host.","If the target must be an internal address, allowlist the exact URI by setting 'phabricator.allowed-uris' (checked inside requireValidRemoteURIForFetch) and re-test.","Fix DNS resolution on the Phabricator host if the domain fails to resolve there."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate the hook URI exactly as the worker will, before saving/queueing:\ntry {\n  PhabricatorEnv::requireValidRemoteURIForFetch(\n    $uri,\n    array('http', 'https'));\n} catch (Exception $ex) {\n  $errors[] = $ex->getMessage(); // show to the admin at edit time\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate webhook URIs with requireValidRemoteURIForFetch() in the hook edit form, not just at delivery time.","Remember the check is SSRF-aware: loopback/link-local/private targets are rejected unless allowlisted via phabricator.allowed-uris.","Test DNS resolution from the Phabricator host, since gethostbynamel() runs there."],"tags":["herald","webhook","phabricator","uri-validation","ssrf","dns"],"backgroundTag":"ssrf-blocked-outbound-request","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}