{"record":{"id":"dde923701c70ff8b","repo":"can1357/oh-my-pi","slug":"absolute-paths-are-not-allowed-in-omp-urls","errorCode":null,"errorMessage":"Absolute paths are not allowed in omp:// URLs","messagePattern":"Absolute paths are not allowed in omp:// URLs","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/internal-urls/omp-protocol.ts","lineNumber":60,"sourceCode":"\t\tif (filenames.length === 0) {\n\t\t\tthrow new Error(\"No documentation files found\");\n\t\t}\n\n\t\tconst listing = filenames.map(f => `- [${f}](omp://${f})`).join(\"\\n\");\n\t\tconst content = `# Documentation\\n\\n${filenames.length} files available:\\n\\n${listing}\\n`;\n\n\t\treturn {\n\t\t\turl: url.href,\n\t\t\tcontent,\n\t\t\tcontentType: \"text/markdown\",\n\t\t\tsize: Buffer.byteLength(content, \"utf-8\"),\n\t\t};\n\t}\n\n\tasync #readDoc(filename: string, url: InternalUrl): Promise<InternalResource> {\n\t\t// Validate: no traversal, no absolute paths\n\t\tif (path.isAbsolute(filename)) {\n\t\t\tthrow new Error(\"Absolute paths are not allowed in omp:// URLs\");\n\t\t}\n\n\t\tconst normalized = path.posix.normalize(filename.replaceAll(\"\\\\\", \"/\"));\n\t\tif (normalized === \"..\" || normalized.startsWith(\"../\") || normalized.includes(\"/../\")) {\n\t\t\tthrow new Error(\"Path traversal (..) is not allowed in omp:// URLs\");\n\t\t}\n\n\t\tconst docPath =\n\t\t\tnormalized === \"docs\" ? \"\" : normalized.startsWith(\"docs/\") ? normalized.slice(\"docs/\".length) : normalized;\n\t\tif (!docPath) {\n\t\t\treturn this.#listDocs(url);\n\t\t}\n\n\t\tconst content = await getEmbeddedDoc(docPath);\n\t\tif (content === undefined) {\n\t\t\tconst lookup = docPath.replace(/\\.md$/, \"\");\n\t\t\tconst suggestions = getDocFilenames()\n\t\t\t\t.filter(f => f.includes(lookup) || lookup.includes(f.replace(/\\.md$/, \"\")))","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/internal-urls/omp-protocol.ts#L42-L78","documentation":"omp:// URLs can only name bundled doc files, not filesystem paths. #readDoc rejects any filename where path.isAbsolute() is true, e.g. omp:///etc/passwd or omp://C:/x, before any lookup happens.","triggerScenarios":"Resolving an omp:// URL whose path component is absolute — starts with '/' or a Windows drive letter — instead of a relative doc filename such as 'docs/cli.md'.","commonSituations":"Treating omp:// like file://; templating a full path into an omp URL; accidentally prefixing a doc name with '/'.","solutions":["Use the relative doc filename only, e.g. omp://docs/cli.md instead of omp:///home/user/docs/cli.md.","Strip the leading slash or drive prefix from the path before building the URL.","If you need filesystem access, use file:// paths or the read tool, not omp://."],"exampleFix":"// before\nrouter.resolve(`omp://${absolutePath}`);\n// after\nconst rel = path.relative(docsRoot, absolutePath);\nrouter.resolve(`omp://${rel}`);","handlingStrategy":"validation","validationCode":"import * as path from 'node:path';\nconst docName = pathname.replace(/^\\//, '');\nif (path.isAbsolute(docName) || /^[a-zA-Z]:/.test(docName)) throw new Error('omp:// expects a relative doc name');","typeGuard":"const isValidDocName = (s: string): boolean =>\n  !path.isAbsolute(s) && !/^[a-zA-Z]:/.test(s) && !s.includes('\\\\');","tryCatchPattern":"try {\n  return await router.resolve(url);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('Absolute paths are not allowed')) throw new Error(`use a relative doc name, got: ${url}`);\n  throw err;\n}","preventionTips":["Always build omp:// URLs from relative doc names only.","Never embed filesystem paths or user-supplied absolute paths into omp:// URLs.","Use file:// or the read tool when the target is an actual path."],"tags":["security","path-validation","internal-url"],"backgroundTag":"invalid-path","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}