ruvnet/ruflo · error · Error
Key contains disallowed characters
Error message
Key contains disallowed characters
What it means
Thrown by validateMemoryInput when a memory key matches DANGEROUS_KEY_PATTERN — shell metacharacters (; & | ` $ ( ) { } [ ] < > ! # \ null) or a path-traversal sequence (../ or ..\). This is the #1425 hardening against command injection and path traversal: keys eventually form filesystem paths and shell arguments, so dangerous characters are rejected outright. sanitizeMemoryKey exists to scrub derived keys before this check.
Source
Thrown at v3/@claude-flow/cli/src/mcp-tools/memory-tools.ts:83
// #1425 — single source of truth for the dangerous-character set rejected by
// validateMemoryInput. Imported by sanitizeMemoryKey so write-side sanitization
// and read-side rejection can never drift apart (the symmetry bug behind #1884).
const DANGEROUS_KEY_CHARS = /[;&|`$(){}[\]<>!#\\\0]|\.\.[/\\]/g;
const DANGEROUS_KEY_PATTERN = /[;&|`$(){}[\]<>!#\\\0]|\.\.[/\\]/;
function validateMemoryInput(key?: string, value?: string, query?: string, namespace?: string): void {
if (key && key.length > MAX_KEY_LENGTH) {
throw new Error(`Key exceeds maximum length of ${MAX_KEY_LENGTH} characters`);
}
if (value && value.length > MAX_VALUE_SIZE) {
throw new Error(`Value exceeds maximum size of ${MAX_VALUE_SIZE} bytes`);
}
if (query && query.length > MAX_QUERY_LENGTH) {
throw new Error(`Query exceeds maximum length of ${MAX_QUERY_LENGTH} characters`);
}
// Reject path traversal and shell metacharacters in keys/namespaces (#1425)
if (key && DANGEROUS_KEY_PATTERN.test(key)) {
throw new Error('Key contains disallowed characters');
}
if (namespace && DANGEROUS_KEY_PATTERN.test(namespace)) {
throw new Error('Namespace contains disallowed characters');
}
}
// #1884 — sanitize a key produced from arbitrary input (markdown headings,
// frontmatter names, file names) so it survives validateMemoryInput on the
// read/delete path. Replaces every dangerous char with `_`. Truncates to
// MAX_KEY_LENGTH so the bound check in validateMemoryInput also passes.
// Keep this in sync with DANGEROUS_KEY_PATTERN — they share DANGEROUS_KEY_CHARS.
function sanitizeMemoryKey(key: string): string {
const safe = key.replace(DANGEROUS_KEY_CHARS, '_');
return safe.length > MAX_KEY_LENGTH ? safe.slice(0, MAX_KEY_LENGTH) : safe;
}
// #1937 — minimal glob → RegExp helper for memory_import_claude exclusion
// patterns. Anchored. Supports the three operators the issue's voice-fidelityView on GitHub (pinned to 6b01dc5a68)
Solutions
- Sanitise derived keys with sanitizeMemoryKey before the memory call (replaces dangerous chars with '_').
- Restrict keys to an allowlist charset ([A-Za-z0-9._-]).
- Hash arbitrary input with sha256 and use the hex digest as the key.
- Never route raw user/LLM text into a key without scrubbing.
Example fix
// before
memory store --key "a;b | rm -rf" --value "x"
// after
const key = userInput.replace(/[;&|`$(){}[\]<>!#\\\0]|\.\.[\/\\]/g, '_')
memory store --key "$key" --value "x" Defensive patterns
Strategy: validation
Validate before calling
const DANGEROUS = /[;&|`$(){}[\]<>!#\\\0]|\.\.[\/\\]/;
function sanitizeKey(key) {
if (DANGEROUS.test(key)) {
return key.replace(/[;&|`$(){}[\]<>!#\\\0]|\.\.[\/\\]/g, '_');
}
return key;
} Type guard
function isSafeMemoryKey(k: string): boolean {
return !/[;&|`$(){}[\]<>!#\\\0]|\.\.[\/\\]/.test(k) && k.length <= 1024;
} Prevention
- Restrict keys to [A-Za-z0-9._-].
- Hash arbitrary input before use as a key.
- Never pass raw user/LLM text as a key.
When it happens
Trigger: Calling memory store/retrieve/delete with a key containing characters like ';', '|', '$', backticks, '../', or null bytes. The regex test is non-global and returns true on the first match.
Common situations: User input or file names used directly as keys (e.g. 'my/file'); LLM-generated keys with punctuation; path-traversal attempts; copy-pasted strings with smart quotes or angle brackets; keys built by string concatenation without sanitisation.
Related errors
- Namespace contains disallowed characters
- ${label} contains null bytes
- basePath contains disallowed characters
- Dangerous key segment rejected: ${part}
- Key exceeds maximum length of ${MAX_KEY_LENGTH} characters
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/b9c5bad9e2dcc4bf.
Report an issue: GitHub.