* Best-effort deny check for paths obscured by :: or backtick syntax. * ONLY checks deny rules — never auto-allows. If the stripped guess * doesn't match a deny rule, we fall through to ask as before.
( strippedPath: string, cwd: string, toolPermissionContext: ToolPermissionContext, operationType: FileOperationType, )
| 982 | * doesn't match a deny rule, we fall through to ask as before. |
| 983 | */ |
| 984 | function checkDenyRuleForGuessedPath( |
| 985 | strippedPath: string, |
| 986 | cwd: string, |
| 987 | toolPermissionContext: ToolPermissionContext, |
| 988 | operationType: FileOperationType, |
| 989 | ): { resolvedPath: string; rule: PermissionRule } | null { |
| 990 | // Red-team P7: null bytes make expandPath throw. Pre-existing but |
| 991 | // defend here since we're introducing a new call path. |
| 992 | if (!strippedPath || strippedPath.includes('\0')) return null |
| 993 | // Red-team P3: `~/.ssh/x strips to ~/.ssh/x but expandTilde only fires |
| 994 | // on leading ~ — the backtick was in front of it. Re-run here. |
| 995 | const tildeExpanded = expandTilde(strippedPath) |
| 996 | const abs = isAbsolute(tildeExpanded) |
| 997 | ? tildeExpanded |
| 998 | : resolve(cwd, tildeExpanded) |
| 999 | const { resolvedPath } = safeResolvePath(getFsImplementation(), abs) |
| 1000 | const permissionType = operationType === 'read' ? 'read' : 'edit' |
| 1001 | const denyRule = matchingRuleForInput( |
| 1002 | resolvedPath, |
| 1003 | toolPermissionContext, |
| 1004 | permissionType, |
| 1005 | 'deny', |
| 1006 | ) |
| 1007 | return denyRule ? { resolvedPath, rule: denyRule } : null |
| 1008 | } |
| 1009 | |
| 1010 | /** |
| 1011 | * Validates a file system path, handling tilde expansion. |
no test coverage detected