MCPcopy Index your code
hub / github.com/codeaashu/claude-code / getPathsForPermissionCheck

Function getPathsForPermissionCheck

src/utils/fsOperations.ts:288–382  ·  view source on GitHub ↗
(inputPath: string)

Source from the content-addressed store, hash-verified

286 * @returns An array of absolute paths to check permissions for
287 */
288export function getPathsForPermissionCheck(inputPath: string): string[] {
289 // Expand tilde notation defensively - tools should do this in getPath(),
290 // but we normalize here as defense in depth for permission checking
291 let path = inputPath
292 if (path === '~') {
293 path = homedir().normalize('NFC')
294 } else if (path.startsWith('~/')) {
295 path = nodePath.join(homedir().normalize('NFC'), path.slice(2))
296 }
297
298 const pathSet = new Set<string>()
299 const fsImpl = getFsImplementation()
300
301 // Always check the original path
302 pathSet.add(path)
303
304 // Block UNC paths before any filesystem access to prevent network
305 // requests (DNS/SMB) during validation on Windows
306 if (path.startsWith('//') || path.startsWith('\\\\')) {
307 return Array.from(pathSet)
308 }
309
310 // Follow the symlink chain, collecting ALL intermediate targets
311 // This handles cases like: test.txt -> /etc/passwd -> /private/etc/passwd
312 // We want to check all three paths, not just test.txt and /private/etc/passwd
313 try {
314 let currentPath = path
315 const visited = new Set<string>()
316 const maxDepth = 40 // Prevent runaway loops, matches typical SYMLOOP_MAX
317
318 for (let depth = 0; depth < maxDepth; depth++) {
319 // Prevent infinite loops from circular symlinks
320 if (visited.has(currentPath)) {
321 break
322 }
323 visited.add(currentPath)
324
325 if (!fsImpl.existsSync(currentPath)) {
326 // Path doesn't exist (new file case). existsSync follows symlinks,
327 // so this is also reached for DANGLING symlinks (link entry exists,
328 // target doesn't). Resolve symlinks in the path and its ancestors
329 // so permission checks see the real destination. Without this,
330 // `./data -> /etc/cron.d/` (live parent symlink) or
331 // `./evil.txt -> ~/.ssh/authorized_keys2` (dangling file symlink)
332 // would allow writes that escape the working directory.
333 if (currentPath === path) {
334 const resolved = resolveDeepestExistingAncestorSync(fsImpl, path)
335 if (resolved !== undefined) {
336 pathSet.add(resolved)
337 }
338 }
339 break
340 }
341
342 const stats = fsImpl.lstatSync(currentPath)
343
344 // Skip special file types that can cause issues
345 if (

Callers 7

pathInAllowedWorkingPathFunction · 0.85
generateSuggestionsFunction · 0.85

Calls 6

getFsImplementationFunction · 0.85
safeResolvePathFunction · 0.85
addMethod · 0.45
hasMethod · 0.45
resolveMethod · 0.45

Tested by

no test coverage detected