ruvnet/ruflo · error · Error
basePath contains disallowed characters
Error message
basePath contains disallowed characters
What it means
Thrown by resolveBasePath() in agentbbs-tools when the user-supplied basePath matches the regex `/\.\.[\\/]|\0/` — i.e. it contains a `..` path segment (forward or back slash) or a NUL byte. This is the D-2 path-traversal hardening shared across the MCP verbs: it prevents a caller from escaping the resolved project cwd root. The default `.agentbbs` is always safe.
Source
Thrown at v3/@claude-flow/cli/src/mcp-tools/agentbbs-tools.ts:64
} catch (err: any) {
if (err && (err.code === 'ERR_MODULE_NOT_FOUND' || err.code === 'MODULE_NOT_FOUND' ||
/Cannot find (module|package)/i.test(String(err?.message)))) {
_agentbbsMod = false;
return null;
}
throw err;
}
}
function degradedResult(reason: string): { success: true; degraded: true; reason: string } {
return { success: true, degraded: true, reason };
}
function resolveBasePath(input?: string): string {
const p = input && typeof input === 'string' && input.length > 0
? input
: '.agentbbs';
if (/\.\.[\\/]|\0/.test(p)) throw new Error('basePath contains disallowed characters');
const abs = isAbsolute(p) ? p : resolve(getProjectCwd(), p);
return abs;
}
function validateRoomLabel(label: string): string {
if (!label || typeof label !== 'string') throw new Error('roomLabel is required');
if (label.length > 128) throw new Error('roomLabel exceeds 128 chars');
// Rooms are conventionally `#sales`, `#finance`, etc. — keep `#` in the allow-list.
if (!/^[A-Za-z0-9_.\-:/@#]+$/.test(label)) {
throw new Error('roomLabel may only contain [A-Za-z0-9_.\\-:/@#]');
}
return label;
}
function validateRoomId(roomId: string): string {
if (!roomId || typeof roomId !== 'string') throw new Error('roomId is required');
if (roomId.length > 128) throw new Error('roomId exceeds 128 chars');
if (!/^[A-Za-z0-9_.\-:/@#]+$/.test(roomId)) {View on GitHub (pinned to 6b01dc5a68)
Solutions
- Pass a simple relative directory name (e.g. `.agentbbs`) or an absolute path inside the project root.
- Sanitize upstream: strip `..` segments and NUL bytes before calling the tool, or resolve+verify the result is inside getProjectCwd().
- If an absolute path outside the project is genuinely required, host the BBS state there directly (absolute paths are allowed as long as they contain no `..` or NUL), but confirm the operator intends that location.
Example fix
// before — traversal attempt
federation_bbs_register({ basePath: '../../etc', roomLabel: '#x' });
// after
federation_bbs_register({ basePath: '.agentbbs', roomLabel: '#x' }); Defensive patterns
Strategy: validation
Validate before calling
function safeBasePath(p?: string): string {
const v = (p && typeof p === 'string' && p.length > 0) ? p : '.agentbbs';
if (/\.\.[\\/]|\0/.test(v)) throw new Error('basePath would escape project root');
return v;
}
const basePath = safeBasePath(input.basePath); Type guard
const isTraversalFree = (p: string): boolean => typeof p === 'string' && !/\.\.[\\/]|\0/.test(p);
Try / catch
null
Prevention
- Never interpolate untrusted input directly into basePath.
- Resolve and verify the absolute path is inside the project root before passing it.
- Reject NUL bytes anywhere user data flows into filesystem APIs.
When it happens
Trigger: A tool caller passes `basePath: '../../../tmp'` or `basePath: 'foo/../bar'`; an automated pipeline interpolates an unvalidated env var into basePath; a NUL byte is injected to truncate the path in the underlying syscall.
Common situations: User-supplied config value for basePath that was not sanitized; a path built via template string from request data; testing harness that fed a literal traversal string.
Related errors
- Key contains disallowed characters
- Namespace contains disallowed characters
- invalid receipt ID
- flywheel anchor path must stay inside project root
- Validation failed: ${result.error}
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/a5f36d0a4da18ae6.
Report an issue: GitHub.