can1357/oh-my-pi · error
Path traversal (..) is not allowed in omp:// URLs
Error message
Path traversal (..) is not allowed in omp:// URLs
What it means
As part of omp:// path sanitization, after normalizing the filename the handler rejects any result equal to '..' or containing '../' segments, blocking directory traversal out of the bundled docs namespace.
Source
Thrown at packages/coding-agent/src/internal-urls/omp-protocol.ts:65
const content = `# Documentation\n\n${filenames.length} files available:\n\n${listing}\n`;
return {
url: url.href,
content,
contentType: "text/markdown",
size: Buffer.byteLength(content, "utf-8"),
};
}
async #readDoc(filename: string, url: InternalUrl): Promise<InternalResource> {
// Validate: no traversal, no absolute paths
if (path.isAbsolute(filename)) {
throw new Error("Absolute paths are not allowed in omp:// URLs");
}
const normalized = path.posix.normalize(filename.replaceAll("\\", "/"));
if (normalized === ".." || normalized.startsWith("../") || normalized.includes("/../")) {
throw new Error("Path traversal (..) is not allowed in omp:// URLs");
}
const docPath =
normalized === "docs" ? "" : normalized.startsWith("docs/") ? normalized.slice("docs/".length) : normalized;
if (!docPath) {
return this.#listDocs(url);
}
const content = await getEmbeddedDoc(docPath);
if (content === undefined) {
const lookup = docPath.replace(/\.md$/, "");
const suggestions = getDocFilenames()
.filter(f => f.includes(lookup) || lookup.includes(f.replace(/\.md$/, "")))
.slice(0, 5);
const suffix =
suggestions.length > 0
? `\nDid you mean: ${suggestions.join(", ")}`
: "\nUse omp:// to list available files.";View on GitHub (pinned to 9690622007)
Solutions
- Remove '..' segments and reference the doc file by its plain name within docs/.
- Sanitize/normalize user-supplied names before embedding them into omp:// URLs.
- Use omp:// with no path to list valid doc filenames.
Example fix
// before
router.resolve(`omp://${userInput}`);
// after
const safe = path.posix.normalize(userInput.replaceAll('\\', '/'));
if (safe === '..' || safe.startsWith('../') || safe.includes('/../')) throw new Error('invalid doc name');
router.resolve(`omp://${safe}`); Defensive patterns
Strategy: validation
Validate before calling
const normalized = path.posix.normalize(input.replaceAll('\\', '/'));
if (normalized === '..' || normalized.startsWith('../') || normalized.includes('/../')) throw new Error('traversal not allowed in omp:// URL'); Type guard
const isTraversalSafe = (s: string): boolean => {
const n = path.posix.normalize(s.replaceAll('\\', '/'));
return n !== '..' && !n.startsWith('../') && !n.includes('/../');
}; Try / catch
try {
return await router.resolve(url);
} catch (err) {
if (err instanceof Error && err.message.includes('Path traversal')) throw new Error('omp:// doc names cannot contain ..');
throw err;
} Prevention
- Normalize and reject '..' segments before constructing omp:// URLs from any user input.
- Whitelist doc names against omp:// listing instead of accepting free-form paths.
- URL-decode input before validating, since encoded traversal still normalizes to '..'.
When it happens
Trigger: Resolving omp://../secrets or omp://docs/../../etc/passwd — the normalized path escapes the docs root via '..' segments.
Common situations: Programmatically joining user input into an omp URL; untrusted config files embedding traversal paths; URL-encoding tricks that decode to '..'.
Related errors
- Destination paths cannot contain parent traversal or NUL byt
- Shared-folder destination escapes its configured root
- Refusing to download outside the workspace: ${downloadPath}
- Absolute paths are not allowed in ${scheme}:// URLs: ${rawPa
- Path traversal (..) is not allowed in ${scheme}:// URLs: ${r
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/6567c2c85ddfa98b.
Report an issue: GitHub.