{"record":{"id":"badee92b8e3fdcc9","repo":"can1357/oh-my-pi","slug":"sarif-artifact-resolves-outside-the-repository","errorCode":null,"errorMessage":"SARIF artifact resolves outside the repository: ${uri}","messagePattern":"SARIF artifact resolves outside the repository: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/security/importers/sarif.ts","lineNumber":121,"sourceCode":"): Promise<string> {\n\tconst uri = artifact.uri;\n\tif (!uri) throw new Error(\"SARIF artifact location is missing its URI\");\n\tconst rootUrl = pathToFileURL(`${repositoryRoot}${path.sep}`);\n\tlet baseUrl = rootUrl;\n\tif (artifact.uriBaseId) {\n\t\tconst declaredBase = run.originalUriBaseIds?.[artifact.uriBaseId]?.uri;\n\t\tif (!declaredBase && artifact.uriBaseId !== \"%SRCROOT%\") {\n\t\t\tthrow new Error(`SARIF artifact uses an unknown URI base: ${artifact.uriBaseId}`);\n\t\t}\n\t\tbaseUrl = declaredBase ? new URL(declaredBase, rootUrl) : rootUrl;\n\t}\n\tconst resolvedUrl = new URL(uri.replaceAll(\"\\\\\", \"/\"), baseUrl);\n\tif (resolvedUrl.protocol !== \"file:\") {\n\t\tthrow new Error(`SARIF artifact URI must resolve to a repository file: ${uri}`);\n\t}\n\tconst absolute = path.resolve(fileURLToPath(resolvedUrl));\n\tif (!pathIsWithin(absolute, repositoryRoot)) {\n\t\tthrow new Error(`SARIF artifact resolves outside the repository: ${uri}`);\n\t}\n\tconst canonical = await fs.realpath(absolute).catch(error => {\n\t\tif (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return absolute;\n\t\tthrow error;\n\t});\n\tif (!pathIsWithin(canonical, repositoryRoot)) {\n\t\tthrow new Error(`SARIF artifact resolves outside the repository through a symbolic link: ${uri}`);\n\t}\n\treturn path.relative(repositoryRoot, canonical).replaceAll(path.sep, \"/\");\n}\n\nasync function normalizeSarifLocations(\n\tresult: SarifResult,\n\trun: SarifRun,\n\trepositoryRoot: string,\n): Promise<SecurityLocation[]> {\n\tconst locations: SecurityLocation[] = [];\n\tfor (const item of result.locations ?? []) {","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/security/importers/sarif.ts#L103-L139","documentation":"Even when the URI resolves to a file URL, the importer verifies the resulting absolute path (and its realpath) stays within the repository root. This prevents SARIF findings from escaping the repository via \"..\" segments or symlinks, and throws when the resolved or canonical path lies outside.","triggerScenarios":"resolveSarifArtifactPath computes an absolute path outside repositoryRoot (e.g. uri \"../../etc/passwd\") or fs.realpath resolves a symlink to a target outside the repo.","commonSituations":"SARIF generated on a machine with the repo nested deeper, leaving ../..-style relative URIs; symlinked source files pointing into other directories; malicious or buggy scanner URIs.","solutions":["Rewrite the artifact uris to be genuinely repository-relative with no \"..\" escapes","Re-run the scan inside the repository so paths resolve within the root","Remove or retarget symlinks whose realpath leaves the repository, or exclude those artifacts"],"exampleFix":"// before\n\"uri\": \"../../shared/lib/util.ts\"\n// after: copy/link within repo and reference\n\"uri\": \"packages/shared/lib/util.ts\"","handlingStrategy":"validation","validationCode":"import * as path from \"node:path\";\nfunction pathIsWithin(candidate: string, root: string): boolean {\n  const rel = path.relative(root, candidate);\n  return rel === \"\" || (!rel.startsWith(\"..\") && !path.isAbsolute(rel));\n}\nconst abs = path.resolve(repoRoot, uri);\nif (!pathIsWithin(abs, repoRoot)) throw new Error(`URI escapes repository: ${uri}`);","typeGuard":"function withinRepo(absolutePath: string, repoRoot: string): boolean {\n  const rel = path.relative(repoRoot, absolutePath);\n  return rel !== \"\" && !rel.startsWith(\"..\") && !path.isAbsolute(rel);\n}","tryCatchPattern":"try {\n  const bundle = await importSarif(sarifDir, repoRoot);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"SARIF artifact resolves outside the repository\")) {\n    console.error(err.message + \" — rewrite the URI or re-run the scan inside the repository\");\n  } else throw err;\n}","preventionTips":["Run the scanner with the repository root as its working directory so relative URIs stay inside","Reject uris containing \"..\" segments in a pre-import pass","Check symlink targets: realpath must stay within the repository","Treat out-of-repo artifact URIs from untrusted SARIF as a security signal, not a formatting nit"],"tags":["sarif","import","path-traversal","security"],"backgroundTag":"path-escapes-repository","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}