12.7 Dangerous File and Directory Protection
Beyond Bash command security checks, file editing tools (Edit, Write, NotebookEdit) have their own independent security mechanisms. The system maintains a list of dangerous files and directories—these paths require user confirmation even in bypassPermissions mode.
Dangerous Files List
// src/utils/permissions/filesystem.ts
export const DANGEROUS_FILES = [
'.gitconfig', // Git global config—can configure core.hooksPath to execute arbitrary scripts
'.gitmodules', // Git submodules—can pull malicious repositories during clone
'.bashrc', // Bash startup script—executed every time a terminal is opened
'.bash_profile', // Bash login script
'.zshrc', // Zsh startup script
'.zprofile', // Zsh login script
'.profile', // POSIX shell universal startup script
'.ripgreprc', // ripgrep config—can configure --pre preprocessor to execute code
'.mcp.json', // MCP server config—configured servers have full system access
'.claude.json', // Claude Code config—can modify permission rules
]The reason each file is protected is very specific: they are either scripts that execute automatically at startup (.bashrc, .zshrc, etc.—ideal vectors for persistent backdoors), or configuration files that can alter security boundaries (.gitconfig can inject git hooks, .mcp.json can add new MCP servers).
Dangerous Directories List
export const DANGEROUS_DIRECTORIES = [
'.git', // Git internal directory—scripts in the hooks/ subdirectory execute automatically during git operations
'.vscode', // VS Code config—tasks.json can define auto-executing tasks
'.idea', // JetBrains IDE config—similar risks
'.claude', // Claude Code config—contains settings, hooks, commands, agents
]Case Bypass Defense
On macOS (default case-insensitive filesystem) and Windows, attackers can bypass path checks through mixed casing. For example, .cLauDe/Settings.locaL.json is equivalent to .claude/settings.local.json at the filesystem level, but a simple string comparison would consider them different.
Claude Code normalizes to lowercase before comparison via normalizeCaseForComparison:
export function normalizeCaseForComparison(path: string): string {
return path.toLowerCase()
}Note that this function executes on every platform—even on Linux (case-sensitive) it uniformly converts to lowercase. This is a conservative strategy: preventing security vulnerabilities in cross-platform scenarios (such as a Linux CI accessing a macOS developer's configuration).
Skill Scope Narrowing
Files under the .claude/skills/ directory require special handling. Claude Code's Skill system allows users to create custom skills, with skill files stored in .claude/skills/\{skill-name\}/ directories.
When the model needs to edit a Skill's file, the system does not offer a broad "allow editing the .claude/ directory" option (that would be too dangerous—it would expose settings.json and hooks/). Instead, it generates a narrowed permission suggestion: only allowing edits to that specific Skill's directory.
// For example, editing .claude/skills/my-tool/handler.ts
// The system suggests the permission pattern "/.claude/skills/my-tool/**"
// Rather than "/.claude/**"This prevents accidentally gaining permission to modify the entire .claude/ directory while iterating on a single Skill.
Source:
src/utils/permissions/filesystem.ts