{"record":{"id":"acb2ff6ad4577c87","repo":"paperclipai/paperclip","slug":"invalid-wiki-path-path","errorCode":null,"errorMessage":"Invalid wiki path: ${path}","messagePattern":"Invalid wiki path: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugins/plugin-llm-wiki/src/wiki/core.ts","lineNumber":1164,"sourceCode":"    { space: defaultSpace, legacySettings: next },\n  );\n  await updateSpace(ctx, {\n    companyId: input.companyId,\n    wikiId: next.wikiId,\n    spaceSlug: DEFAULT_SPACE_SLUG,\n    settings: { paperclipIngestion: profile },\n  });\n  return next;\n}\n\nfunction assertWikiPath(path: string, options: { allowMetadata?: boolean } = {}): string {\n  const trimmed = path.trim().replace(/^\\/+/, \"\");\n  if (\n    !trimmed ||\n    trimmed.includes(\"\\\\\") ||\n    trimmed.split(\"/\").some((segment) => segment === \"\" || segment === \".\" || segment === \"..\")\n  ) {\n    throw new Error(`Invalid wiki path: ${path}`);\n  }\n  if (\n    trimmed !== \".gitignore\" &&\n    trimmed !== \"WIKI.md\" &&\n    trimmed !== \"AGENTS.md\" &&\n    trimmed !== \"IDEA.md\" &&\n    trimmed !== \"index.md\" &&\n    trimmed !== \"log.md\" &&\n    !trimmed.startsWith(\"raw/\") &&\n    !trimmed.startsWith(\"wiki/\") &&\n    !(options.allowMetadata && trimmed.startsWith(\".paperclip/\"))\n  ) {\n    throw new Error(`Wiki path must stay inside AGENTS.md, IDEA.md, raw/, or wiki/: ${path}`);\n  }\n  return trimmed;\n}\n\nfunction assertPagePath(path: string): string {","sourceCodeStart":1146,"sourceCodeEnd":1182,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/plugin-llm-wiki/src/wiki/core.ts#L1146-L1182","documentation":"Thrown by assertWikiPath when a path is empty after trimming, contains a backslash, or has any empty/dot/dot-dot segment after splitting on '/'. It is the first line of path-traversal defense shared by all wiki file APIs. The original (untrimmed) path is echoed back in the message.","triggerScenarios":"Any wiki write/read API that funnels through assertWikiPath (page writes, raw source writes, metadata) receives a path like '', '/', '//', 'a//b', 'a/./b', 'a/../b', or a Windows-style 'a\\\\b'.","commonSituations":"User input not normalized; paths joined with leading slashes; copy-pasted Windows paths; trailing slashes producing empty segments; malicious or accidental traversal attempts.","solutions":["Normalize the path client-side: strip leading slashes, collapse repeated slashes, reject '.' and '..' segments.","Validate the path is non-empty before calling the API.","Reject backslashes in path inputs at the form boundary.","Use spaceRelativePath to construct paths from trusted components."],"exampleFix":"// before\nawait writePage(ctx, { companyId, path: req.body.path }); // user sends 'wiki/../etc'\n\n// after\nconst clean = req.body.path.trim().replace(/^\\/+/, \"\");\nif (!clean || clean.includes(\"\\\\\") || clean.split(\"/\").some((s) => s === \"\" || s === \".\" || s === \"..\")) {\n  return res.status(400).json({ error: \"Invalid wiki path\" });\n}\nawait writePage(ctx, { companyId, path: clean });","handlingStrategy":"validation","validationCode":"function sanitizeWikiPath(path) {\n  const trimmed = String(path).trim().replace(/^\\/+/, \"\");\n  if (\n    !trimmed ||\n    trimmed.includes(\"\\\\\") ||\n    trimmed.split(\"/\").some((s) => s === \"\" || s === \".\" || s === \"..\")\n  ) {\n    throw new Error(`Invalid wiki path: ${path}`);\n  }\n  return trimmed;\n}","typeGuard":"function isValidWikiPathShape(path) {\n  const t = String(path ?? \"\").trim().replace(/^\\/+/, \"\");\n  return !!t && !t.includes(\"\\\\\") && !t.split(\"/\").some((s) => s === \"\" || s === \".\" || s === \"..\");\n}","tryCatchPattern":"try {\n  await writePage(ctx, { companyId, path, content });\n} catch (err) {\n  if (/Invalid wiki path/.test(err.message)) {\n    return res.status(400).json({ error: \"Path must not be empty or contain backslashes, '.', or '..' segments.\" });\n  }\n  throw err;\n}","preventionTips":["Normalize and validate paths at the form boundary.","Reject backslashes outright.","Build paths with spaceRelativePath from trusted components."],"tags":["validation","security","path-traversal","wiki"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}