MCPcopy
hub / github.com/codeaashu/claude-code / validateTeamMemWritePath

Function validateTeamMemWritePath

src/memdir/teamMemPaths.ts:228–256  ·  view source on GitHub ↗
(
  filePath: string,
)

Source from the content-addressed store, hash-verified

226 * directory via .. segments, or escapes via a symlink (PSR M22186).
227 */
228export async function validateTeamMemWritePath(
229 filePath: string,
230): Promise<string> {
231 if (filePath.includes('\0')) {
232 throw new PathTraversalError(`Null byte in path: "${filePath}"`)
233 }
234 // First pass: normalize .. segments and check string-level containment.
235 // This is a fast rejection for obvious traversal attempts before we touch
236 // the filesystem.
237 const resolvedPath = resolve(filePath)
238 const teamDir = getTeamMemPath()
239 // Prefix attack protection: teamDir already ends with sep (from getTeamMemPath),
240 // so "team-evil/" won't match "team/"
241 if (!resolvedPath.startsWith(teamDir)) {
242 throw new PathTraversalError(
243 `Path escapes team memory directory: "${filePath}"`,
244 )
245 }
246 // Second pass: resolve symlinks on the deepest existing ancestor and verify
247 // the real path is still within the real team dir. This catches symlink-based
248 // escapes that path.resolve() alone cannot detect.
249 const realPath = await realpathDeepestExisting(resolvedPath)
250 if (!(await isRealPathWithinTeamDir(realPath))) {
251 throw new PathTraversalError(
252 `Path escapes team memory directory via symlink: "${filePath}"`,
253 )
254 }
255 return resolvedPath
256}
257
258/**
259 * Validate a relative path key from the server against the team memory directory.

Callers

nothing calls this directly

Calls 4

getTeamMemPathFunction · 0.85
realpathDeepestExistingFunction · 0.85
isRealPathWithinTeamDirFunction · 0.85
resolveFunction · 0.50

Tested by

no test coverage detected