{"record":{"id":"dbca918472a68911","repo":"phacility/phabricator","slug":"invalid-path-uri","errorCode":null,"errorMessage":"Invalid path URI.","messagePattern":"Invalid path URI\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/diffusion/request/DiffusionRequest.php","lineNumber":527,"sourceCode":"      $result['commit'] = $matches[1];\n      $blob = substr($blob, 0, -(strlen($matches[1]) + 1));\n    }\n\n    // We've consumed the commit if it exists, so unescape \";\" in the rest\n    // of the string.\n    $blob = str_replace(';;', ';', $blob);\n\n    if (strlen($blob)) {\n      $result['path'] = $blob;\n    }\n\n    if ($result['path'] !== null) {\n      $parts = explode('/', $result['path']);\n      foreach ($parts as $part) {\n        // Prevent any hyjinx since we're ultimately shipping this to the\n        // filesystem under a lot of workflows.\n        if ($part == '..') {\n          throw new Exception(pht('Invalid path URI.'));\n        }\n      }\n    }\n\n    return $result;\n  }\n\n  /**\n   * Check that the working copy of the repository is present and readable.\n   *\n   * @param   string  Path to the working copy.\n   */\n  protected function validateWorkingCopy($path) {\n    if (!is_readable(dirname($path))) {\n      $this->raisePermissionException();\n    }\n\n    if (!Filesystem::pathExists($path)) {","sourceCodeStart":509,"sourceCodeEnd":545,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/diffusion/request/DiffusionRequest.php#L509-L545","documentation":"When DiffusionRequest parses a request URI, it splits the extracted path on '/' and rejects any segment equal to '..' with 'Invalid path URI.'. The guard exists because the path is later passed to VCS commands and filesystem operations, so '..' segments would allow escaping the repository root (directory traversal).","triggerScenarios":"Any Diffusion request whose decoded path contains a '..' segment, e.g. /diffusion/X/browse/trunk/..%2F..%2Fsecret — usually from hand-built links, crawlers, security scanners, or clients that fail to normalize paths.","commonSituations":"Automated vulnerability scanners probing the install; copy-pasted URLs with manual path edits; double-encoded %252E%252E payloads.","solutions":["Normalize the path client-side (resolve and drop '..' segments) before issuing the request","Generate Diffusion links with the framework URI helpers instead of string concatenation","Treat occurrences in access logs as probing rather than a bug — the guard is doing its job"],"exampleFix":"// before\n$uri = '/diffusion/X/browse/'.$path_from_user; // may contain ..\n\n// after\n$parts = explode('/', $path_from_user);\n$parts = array_values(array_filter($parts, function ($p) { return $p !== '..'; }));\n$uri = '/diffusion/X/browse/'.implode('/', $parts);","handlingStrategy":"validation","validationCode":"// Reject traversal segments before constructing the request\n$parts = explode('/', $path);\nforeach ($parts as $part) {\n  if ($part === '..') {\n    return new Aphront400Response(); // or reject in the client\n  }\n}","typeGuard":"function isValidDiffusionPath($path) {\n  foreach (explode('/', $path) as $part) {\n    if ($part === '..') {\n      return false;\n    }\n  }\n  return true;\n}","tryCatchPattern":"try {\n  $request = DiffusionRequest::newFromAphrontRequest($request);\n} catch (Exception $ex) {\n  if ($ex->getMessage() === pht('Invalid path URI.')) {\n    return new Aphront400Response();\n  }\n  throw $ex;\n}","preventionTips":["Always normalize ('collapse') dot segments in user-supplied paths before requesting","Build Diffusion URLs with framework helpers, never by concatenation","Treat this exception in logs as attack traffic, not an application bug"],"tags":["security","path-traversal","diffusion"],"backgroundTag":"path-traversal","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}