{"record":{"id":"a5f36d0a4da18ae6","repo":"ruvnet/ruflo","slug":"basepath-contains-disallowed-characters","errorCode":null,"errorMessage":"basePath contains disallowed characters","messagePattern":"basePath contains disallowed characters","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/mcp-tools/agentbbs-tools.ts","lineNumber":93,"sourceCode":"      shell: process.platform === 'win32',\n      windowsHide: true,\n    });\n    _cliAvailable = true;\n  } catch {\n    _cliAvailable = false;\n  }\n  return _cliAvailable;\n}\n\nfunction degradedResult(reason: string): { success: true; degraded: true; reason: string } {\n  return { success: true, degraded: true, reason };\n}\n\nfunction resolveBasePath(input?: string): string {\n  const p = input && typeof input === 'string' && input.length > 0\n    ? input\n    : '.agentbbs';\n  if (/\\.\\.[\\\\/]|\\0/.test(p)) throw new Error('basePath contains disallowed characters');\n  const abs = isAbsolute(p) ? p : resolve(getProjectCwd(), p);\n  return abs;\n}\n\nfunction validateRoomLabel(label: string): string {\n  if (!label || typeof label !== 'string') throw new Error('roomLabel is required');\n  if (label.length > 128) throw new Error('roomLabel exceeds 128 chars');\n  // Rooms are conventionally `#sales`, `#finance`, etc. — keep `#` in the allow-list.\n  if (!/^[A-Za-z0-9_.\\-:/@#]+$/.test(label)) {\n    throw new Error('roomLabel may only contain [A-Za-z0-9_.\\\\-:/@#]');\n  }\n  return label;\n}\n\nfunction validateRoomId(roomId: string): string {\n  if (!roomId || typeof roomId !== 'string') throw new Error('roomId is required');\n  if (roomId.length > 128) throw new Error('roomId exceeds 128 chars');\n  if (!/^[A-Za-z0-9_.\\-:/@#]+$/.test(roomId)) {","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/ruvnet/ruflo/blob/9c61c86f06b439af2a95085ae9bb0ca839662e41/v3/@claude-flow/cli/src/mcp-tools/agentbbs-tools.ts#L75-L111","documentation":"resolveBasePath() validates the basePath argument of every agentbbs tool (default '.agentbbs') against /\\.\\.[\\\\/]|\\0/ before resolving it against the project cwd: any '..' followed by a slash or backslash, or any NUL byte, throws. This is deliberate path-traversal and binary-garbage protection — the bulletin board must stay rooted inside the project.","triggerScenarios":"Passing basePath: '../../etc' or 'foo/../bar'; forwarding a user/chat-supplied path into an agentbbs tool without sanitization (classic prompt-injection escape attempt); a config value containing a NUL byte from binary corruption; Windows-style '..\\' separators.","commonSituations":"Agents taking a basePath parameter from untrusted LLM output; automation scripts computing paths with join() that reintroduce '../' segments; attempts to share one BBS store between projects via parent-directory paths (use an absolute path instead).","solutions":["Use a simple relative directory (or omit basePath for the '.agentbbs' default) or an absolute path that does not contain '..' segments","To share a store across projects, pass an absolute path like '/srv/agentbbs' — absolute paths skip the traversal-prone re-resolution","Sanitize untrusted input: reject or strip '../', '..\\', and NUL before passing basePath to the tool"],"exampleFix":"// before — traversal sequence rejected\nawait callMCPTool('agentbbs_post', { basePath: '../shared-bbs', roomId: '#ops', ... });\n\n// after — absolute path or project-relative default\nawait callMCPTool('agentbbs_post', { basePath: '/srv/shared-bbs', roomId: '#ops', ... });","handlingStrategy":"validation","validationCode":"const UNSAFE_BASEPATH = /\\.\\.[\\\\/]|\\0/;\n\nfunction safeBasePath(input?: string): string {\n  const p = input && input.length > 0 ? input : '.agentbbs';\n  if (UNSAFE_BASEPATH.test(p)) {\n    throw new Error('basePath must not contain ../ or NUL bytes');\n  }\n  return p;\n}","typeGuard":"const isSafeBasePath = (p: string): boolean => !/\\.\\.[\\\\/]|\\0/.test(p);","tryCatchPattern":null,"preventionTips":["Never forward untrusted/chat-derived paths into agentbbs basePath without this check","Prefer absolute paths when sharing a store across projects","Keep the default '.agentbbs' unless there is a concrete reason to change it"],"tags":["validation","path-traversal","security","agentbbs","sanitization"],"backgroundTag":"path-traversal-rejected","analyzedSha":"9c61c86f06b439af2a95085ae9bb0ca839662e41","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}