{"record":{"id":"d539bfc3478e3d5a","repo":"different-ai/openwork","slug":"path-escape-d539bf","errorCode":"path_escape","errorMessage":"Path escapes web root","messagePattern":"Path escapes web root","errorType":"http","errorClass":"GatewayHttpError","httpStatus":400,"severity":"warning","filePath":"ee/apps/den-gateway/src/app.ts","lineNumber":291,"sourceCode":"\nfunction requestPathToRelativePath(pathname: string): string | null {\n  try {\n    const decoded = decodeURIComponent(pathname)\n    return decoded.replace(/^\\/+/, \"\") || \"index.html\"\n  } catch {\n    return null\n  }\n}\n\nasync function resolveWithinRoot(root: string, ...segments: string[]) {\n  const resolvedRoot = await realpath(root)\n  const candidate = resolve(resolvedRoot, ...segments)\n  const resolvedCandidate = await realpath(candidate).catch(() => candidate)\n  if (resolvedCandidate === resolvedRoot) {\n    return candidate\n  }\n  if (!resolvedCandidate.startsWith(resolvedRoot + sep)) {\n    throw new GatewayHttpError(400, \"path_escape\", \"Path escapes web root\")\n  }\n  return candidate\n}\n\nfunction contentType(extension: string) {\n  if (extension === \".html\") {\n    return \"text/html; charset=utf-8\"\n  }\n  if (extension === \".js\" || extension === \".mjs\") {\n    return \"text/javascript; charset=utf-8\"\n  }\n  if (extension === \".css\") {\n    return \"text/css; charset=utf-8\"\n  }\n  if (extension === \".json\" || extension === \".map\") {\n    return \"application/json; charset=utf-8\"\n  }\n  if (extension === \".svg\") {","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-gateway/src/app.ts#L273-L309","documentation":"The Den gateway serves static files from a configured web root. resolveWithinRoot resolves requested path segments against the root, follows symlinks via realpath, and throws a 400 GatewayHttpError (code 'path_escape', message 'Path escapes web root') when the resolved candidate is not the root itself and does not remain inside it. This blocks path-traversal requests like /../../etc/passwd.","triggerScenarios":"An HTTP request whose URL-encoded segments (../, %2e%2e/, absolute paths) resolve outside DEN_GATEWAY_WEB_ROOT, or a symlink inside the web root pointing to a file outside it.","commonSituations":"Attackers probing for traversal vulnerabilities; misconfigured reverse proxies forwarding raw '..' segments; a developer symlinking a shared asset directory that lives outside the web root; Windows/macOS case or symlink surprises after deployment.","solutions":["Remove or rewrite request paths containing '..' or encoded traversal segments before they reach the gateway","Ensure DEN_GATEWAY_WEB_ROOT points at the directory actually containing the assets being requested","Move or re-point any symlink inside the web root so targets live under the root","Serve additional content by copying it into the web root or adding an explicit proxied route, not via symlinks"],"exampleFix":"// before\nfetch('/static/../../etc/passwd') // path_escape\n// after\nconst safe = requestedPath.replaceAll(/(\\.\\.\\/)+/g, '')\nfetch(`/static/${encodeURIComponent(safe)}`)","handlingStrategy":"try-catch","validationCode":"function staysWithinRoot(root: string, segments: string[]) {\n  const resolved = resolve(resolve(root), ...segments)\n  return resolved === resolve(root) || resolved.startsWith(resolve(root) + sep)\n}","typeGuard":"null","tryCatchPattern":"import { GatewayHttpError } from './http-error.js'\ntry {\n  const file = await filePath(segments)\n} catch (err) {\n  if (err instanceof GatewayHttpError && err.code === 'path_escape') {\n    return new Response('Not Found', { status: 404 }) // don't leak traversal attempts\n  }\n  throw err\n}","preventionTips":["Normalize/reject URL segments containing '..' at the proxy or router edge","Keep all served assets physically inside DEN_GATEWAY_WEB_ROOT — avoid outbound symlinks","Log path_escape occurrences; bursts indicate probing","Return 404 (not 400 details) to external clients to avoid leaking filesystem layout"],"tags":["path-traversal","security","gateway","filesystem"],"backgroundTag":"path-traversal","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}