{"record":{"id":"0195f09ed7b8c993","repo":"can1357/oh-my-pi","slug":"encoded-path-separators-are-not-allowed-in-memory","errorCode":null,"errorMessage":"Encoded path separators are not allowed in memory:// glob patterns: ${input}","messagePattern":"Encoded path separators are not allowed in memory:// glob patterns: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/internal-urls/memory-protocol.ts","lineNumber":85,"sourceCode":" * cannot escape a safely resolved base directory.\n */\nexport function splitMemoryGlobPattern(input: string): MemoryGlobPattern {\n\tconst urlMatch = input.match(/^([a-z][a-z0-9+.-]*:\\/\\/[^/?#]*)(\\/.*)?$/i);\n\tif (!urlMatch) {\n\t\tthrow new Error(`Invalid memory glob URL: ${input}`);\n\t}\n\n\t// Parse only the scheme and authority. A literal `?` in the path is glob\n\t// syntax, not a query delimiter, and must survive unchanged.\n\tconst url = parseInternalUrl(urlMatch[1]);\n\tconst namespace = url.rawHost || url.hostname;\n\tif (url.protocol !== \"memory:\" || namespace !== MEMORY_NAMESPACE) {\n\t\tthrow new Error(`Memory glob patterns require the ${MEMORY_NAMESPACE} namespace: ${input}`);\n\t}\n\n\tconst rawPathname = urlMatch[2] ?? \"\";\n\tif (/%(?:2f|5c)/i.test(rawPathname)) {\n\t\tthrow new Error(`Encoded path separators are not allowed in memory:// glob patterns: ${input}`);\n\t}\n\n\tlet relativePath: string;\n\ttry {\n\t\trelativePath = decodeURIComponent(rawPathname.replace(/^\\//, \"\"));\n\t} catch {\n\t\tthrow new Error(`Invalid URL encoding in memory:// path: ${input}`);\n\t}\n\n\ttry {\n\t\tvalidateRelativePath(relativePath);\n\t} catch (error) {\n\t\tthrow toMemoryValidationError(error);\n\t}\n\n\tconst rawSegments = rawPathname.replace(/^\\//, \"\").split(\"/\");\n\tconst firstGlobIndex = rawSegments.findIndex(segment => [\"*\", \"?\", \"[\", \"{\"].some(char => segment.includes(char)));\n\tif (firstGlobIndex === -1) {","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/internal-urls/memory-protocol.ts#L67-L103","documentation":"Percent-encoded '/' (%2F) or backslash (%5C) in the pathname would let a glob suffix smuggle path separators past the segment-based path validation. The library rejects any memory:// glob URL whose raw pathname contains these escapes before decoding, closing a traversal vector.","triggerScenarios":"Passing a memory:// glob URL where the path contains %2f, %2F, %5c, or %5C — typically produced by encodeURIComponent() being applied to a whole path that already contains '/' or '\\'.","commonSituations":"Programmatic URL builders over-encoding paths (encodeURIComponent(path) instead of per-segment encoding); frameworks that double-encode path parameters; LLM-generated URLs that escaped separators.","solutions":["Remove the encoded separators: encode each path segment's special characters but leave '/' literal (encodeURIComponent per segment joined by '/').","Decode the offending %2F/%5C into real separators in the URL string before passing it (the literal '/' in the path is allowed).","Sanitize any pipeline that serializes paths into memory:// URLs to skip path-separator escaping."],"exampleFix":"// before\nconst url = `memory://root/${encodeURIComponent(\"notes/2024/*.md\")}`; // %2F injected\n// after\nconst url = `memory://root/${\"notes/2024/*.md\".split(\"/\").map(encodeURIComponent).join(\"/\")}`;","handlingStrategy":"validation","validationCode":"function hasEncodedSeparators(input: string): boolean {\n  return /%(?:2f|5c)/i.test(input);\n}\n// reject or repair before calling splitMemoryGlobPattern","typeGuard":"function isSafeMemoryGlobPath(input: string): boolean {\n  return !/%(?:2f|5c)/i.test(input);\n}","tryCatchPattern":"try {\n  return splitMemoryGlobPattern(input);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith(\"Encoded path separators are not allowed\")) {\n    throw new Error(\"Rebuild the memory:// URL encoding per path segment instead of encoding the whole path\");\n  }\n  throw e;\n}","preventionTips":["encodeURIComponent each path segment and join with literal '/', never encode whole paths.","Scan generated memory:// URLs for %2F/%5C in CI or at config load time.","Avoid frameworks/options that double-encode path parameters."],"tags":["security","path-traversal","url-encoding"],"backgroundTag":"encoded-path-separator","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}