Permisos y Seguridad
Claude Code opera bajo un sistema de permisos que controla qué acciones puede ejecutar. Este sistema es fundamental para mantener la seguridad mientras permites que Claude sea productivo.
Filosofía del sistema
Claude Code sigue el principio de mínimo privilegio: por defecto, solicita permiso para acciones potencialmente peligrosas. Tú decides qué permitir de forma permanente y qué requiere confirmación cada vez.
┌─────────────────────────────────────────────┐
│ Tu decisión │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Permitir│ │ Permitir│ │ Denegar │ │
│ │ siempre │ │ una vez │ │ siempre │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ Se añade a Se ejecuta Se añade a │
│ allowlist solo ahora denylist │
└─────────────────────────────────────────────┘Tools disponibles
Claude Code tiene acceso a herramientas (tools) que le permiten interactuar con tu sistema. Las principales son:
| Tool | Descripción | Ejemplos |
|---|---|---|
Read | Leer archivos del sistema | Ver código fuente, configuraciones |
Write | Crear o modificar archivos | Escribir código, editar configs |
Edit | Editar secciones de archivos | Modificar funciones específicas |
Bash | Ejecutar comandos en terminal | git, npm, scripts |
Glob | Buscar archivos por patrón | Encontrar todos los .ts |
Grep | Buscar contenido en archivos | Encontrar usos de una función |
Tool: Read
Permite a Claude leer archivos de tu sistema.
Casos de uso:
- Leer código fuente para entenderlo
- Ver archivos de configuración
- Examinar logs o outputs
Riesgos potenciales:
- Acceso a archivos sensibles (.env, credenciales)
- Lectura de datos privados
Read(./src/index.ts) → Leer archivo específico
Read(./.env) → ⚠️ Archivo sensible
Read(./package.json) → Configuración del proyectoTool: Write
Permite a Claude crear archivos nuevos o sobrescribir existentes.
Casos de uso:
- Crear nuevos archivos de código
- Generar configuraciones
- Escribir documentación
Riesgos potenciales:
- Sobrescribir archivos importantes
- Crear archivos en ubicaciones incorrectas
Write(./src/utils.ts) → Crear/sobrescribir archivo
Write(./package.json) → ⚠️ Sobrescribir configuración crítica
Write(./.env.example) → Crear templateTool: Edit
Permite a Claude modificar secciones específicas de archivos existentes.
Casos de uso:
- Modificar una función específica
- Actualizar imports
- Corregir bugs puntuales
Ventaja sobre Write:
- Más preciso: solo cambia lo necesario
- Menor riesgo de pérdida de código
Edit(./src/api.ts) → Editar sección del archivoTool: Bash
Permite a Claude ejecutar comandos en la terminal.
Casos de uso:
- Ejecutar git (commits, push, pull)
- Gestionar paquetes (npm, pip)
- Correr tests y builds
- Scripts de automatización
Riesgos potenciales:
- Comandos destructivos (rm -rf)
- Acceso a recursos del sistema
- Comandos con privilegios (sudo)
Bash(git status) → Seguro, solo lectura
Bash(npm install) → Modifica node_modules
Bash(rm -rf ./src) → ⚠️ Destructivo
Bash(sudo apt install) → ⚠️ Requiere privilegiosFlujo de permisos
Cuando Claude necesita usar una herramienta:
Claude quiere ejecutar: Bash(npm install)
│
▼
¿Está en la lista "allow"?
│ │
Sí No
│ │
▼ ▼
Ejecutar ¿Está en la lista "deny"?
│ │
Sí No
│ │
▼ ▼
Bloquear Pedir permiso
al usuario
│
┌───────────┼───────────┐
│ │ │
▼ ▼ ▼
Permitir Permitir Denegar
siempre una vezNiveles de permiso
Los permisos se pueden configurar en tres niveles, con prioridad de arriba a abajo:
| Nivel | Archivo | Alcance | Prioridad |
|---|---|---|---|
| Local | .claude/settings.local.json | Solo tu máquina | Máxima |
| Proyecto | .claude/settings.json | Todo el equipo | Media |
| Global | ~/.claude/settings.json | Todos tus proyectos | Mínima |
Ejemplo de precedencia
~/.claude/settings.json (global)
allow: ["Bash(npm *)"]
.claude/settings.json (proyecto)
deny: ["Bash(npm publish)"]
.claude/settings.local.json (local)
allow: ["Bash(npm publish)"]En este caso, npm publish está permitido porque el archivo local tiene máxima prioridad.
Trust dialogs
Cuando Claude intenta una acción no preconfigurada, aparece un diálogo de confianza:
╭──────────────────────────────────────────────╮
│ Claude wants to run: │
│ │
│ Bash(npm install lodash) │
│ │
│ [a] Allow always [y] Yes, once [n] No │
╰──────────────────────────────────────────────╯Opciones:
a(Allow always): Añade a la lista de permitidosy(Yes, once): Permite solo esta vezn(No): Deniega la acción
Las respuestas "Allow always" se guardan en .claude/settings.local.json.
Modo sin confirmación
Para automatización, puedes saltarte las confirmaciones:
# Acepta automáticamente permisos (usa con precaución)
claude --yes
# Alias común
claude -yEste modo es útil para:
- Scripts de CI/CD
- Automatizaciones controladas
- Entornos de prueba
Precaución: Solo usa --yes en entornos donde confías completamente en lo que vas a pedir.
Auditoría de permisos
Puedes ver qué permisos tiene Claude actualmente:
# En sesión interactiva
/permissionsEsto muestra:
- Herramientas permitidas
- Herramientas denegadas
- Fuente de cada permiso (global, proyecto, local)
Permisos y seguridad
El sistema de permisos es tu primera línea de defensa. Considera:
| Escenario | Recomendación |
|---|---|
| Proyecto personal | Permisos más relajados |
| Proyecto de trabajo | Permisos moderados |
| Datos sensibles | Permisos restrictivos |
| CI/CD | Solo permisos específicos necesarios |
Puntos clave
- Claude Code usa un sistema de permisos para controlar qué puede hacer
- Las herramientas principales son: Read, Write, Edit, Bash, Glob, Grep
- Los permisos se configuran en tres niveles: global, proyecto y local
- El archivo local tiene máxima prioridad
- Los trust dialogs permiten decidir en tiempo real
- Usa
--yescon precaución, solo en entornos controlados - Revisa permisos regularmente con
/permissions
Siguiente paso: En el punto 3.2 aprenderás a configurar permisos específicos con patrones.
3.2 Configuración de permisos
Los permisos se configuran en el archivo settings.json. Aquí aprenderás la sintaxis exacta y las mejores prácticas para configurarlos.
Estructura básica
{
"permissions": {
"allow": [
"Tool(patrón)"
],
"deny": [
"Tool(patrón)"
]
}
}- allow: Lista de herramientas/patrones permitidos automáticamente
- deny: Lista de herramientas/patrones bloqueados siempre
Sintaxis de permisos
Permiso simple (toda la herramienta)
{
"permissions": {
"allow": [
"Read",
"Write",
"Edit"
]
}
}Esto permite todas las operaciones de lectura, escritura y edición sin confirmación.
Permiso con patrón
{
"permissions": {
"allow": [
"Read(./src/*)",
"Write(./src/*.ts)",
"Bash(git *)"
]
}
}Esto permite:
- Leer cualquier archivo en
./src/ - Escribir solo archivos
.tsen./src/ - Ejecutar cualquier comando git
Patrones glob
Los patrones usan sintaxis glob estándar:
| Patrón | Significado | Ejemplo |
|---|---|---|
* | Cualquier cosa excepto / | *.ts → index.ts |
** | Cualquier cosa incluyendo / | **/*.ts → src/utils/index.ts |
? | Un solo carácter | file?.ts → file1.ts |
[abc] | Uno de los caracteres | file[123].ts → file1.ts |
{a,b} | Una de las opciones | *.{ts,js} → index.ts, index.js |
Ejemplos de patrones
{
"permissions": {
"allow": [
"Read(**/*.ts)",
"Read(**/*.js)",
"Read(**/*.json)",
"Write(./src/**/*)",
"Bash(npm run *)",
"Bash(git {status,log,diff,add,commit,push,pull})"
],
"deny": [
"Read(./.env*)",
"Read(**/*.pem)",
"Read(**/secrets/**)",
"Write(./package-lock.json)",
"Bash(rm -rf *)",
"Bash(sudo *)"
]
}
}Configuración por herramienta
Read
{
"permissions": {
"allow": [
"Read",
"Read(./src/**/*)",
"Read(*.{ts,js,json,md})",
"Read(./docs/**/*.md)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./.env.local)",
"Read(**/*.key)",
"Read(**/*.pem)",
"Read(**/credentials*)",
"Read(**/secrets/**)"
]
}
}Write
{
"permissions": {
"allow": [
"Write(./src/**/*.ts)",
"Write(./src/**/*.tsx)",
"Write(./tests/**/*)",
"Write(./*.md)"
],
"deny": [
"Write(./.env*)",
"Write(./package-lock.json)",
"Write(./yarn.lock)",
"Write(./.git/**/*)",
"Write(**/node_modules/**)"
]
}
}Bash
Los comandos Bash requieren especial atención por su potencial destructivo.
{
"permissions": {
"allow": [
"Bash(git status)",
"Bash(git log*)",
"Bash(git diff*)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git push)",
"Bash(git pull)",
"Bash(git branch*)",
"Bash(git checkout *)",
"Bash(npm run *)",
"Bash(npm test*)",
"Bash(npm install)",
"Bash(npx prettier *)",
"Bash(npx eslint *)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(rm -r *)",
"Bash(sudo *)",
"Bash(chmod 777 *)",
"Bash(curl * | sh)",
"Bash(wget * | sh)",
"Bash(git push --force*)",
"Bash(git reset --hard*)",
"Bash(npm publish*)",
"Bash(> *)"
]
}
}Configuración por entorno
Desarrollo personal
Permisos más relajados para máxima productividad:
{
"permissions": {
"allow": [
"Read",
"Write(./src/**/*)",
"Write(./tests/**/*)",
"Edit",
"Bash(git *)",
"Bash(npm *)",
"Bash(node *)"
],
"deny": [
"Read(./.env)",
"Bash(rm -rf *)",
"Bash(sudo *)"
]
}
}Proyecto de equipo
Permisos moderados para colaboración segura:
{
"permissions": {
"allow": [
"Read(**/*.{ts,tsx,js,jsx,json,md,css,scss})",
"Write(./src/**/*)",
"Write(./tests/**/*)",
"Bash(git status)",
"Bash(git diff*)",
"Bash(git log*)",
"Bash(npm run *)",
"Bash(npm test*)"
],
"deny": [
"Read(./.env*)",
"Read(**/secrets/**)",
"Write(./*.json)",
"Write(./*.lock)",
"Bash(git push*)",
"Bash(git commit*)",
"Bash(npm install*)",
"Bash(npm publish*)",
"Bash(rm *)",
"Bash(sudo *)"
]
}
}CI/CD Pipeline
Solo los permisos estrictamente necesarios:
{
"permissions": {
"allow": [
"Read(**/*.{ts,tsx,js,jsx})",
"Bash(npm run lint)",
"Bash(npm run test)",
"Bash(npm run build)"
],
"deny": [
"Write",
"Edit",
"Bash(git *)",
"Bash(npm install*)",
"Bash(npm publish*)",
"Bash(rm *)",
"Bash(sudo *)"
]
}
}Datos sensibles
Configuración restrictiva para proyectos con información confidencial:
{
"permissions": {
"allow": [
"Read(./src/**/*.ts)",
"Read(./docs/**/*.md)"
],
"deny": [
"Read(./.env*)",
"Read(**/config/**)",
"Read(**/secrets/**)",
"Read(**/*.key)",
"Read(**/*.pem)",
"Read(**/*.cert)",
"Read(**/credentials*)",
"Read(**/password*)",
"Read(**/token*)",
"Write",
"Edit",
"Bash"
]
}
}Combinación de niveles
Recuerda que puedes combinar configuraciones en diferentes niveles:
~/.claude/settings.json (global):
{
"permissions": {
"deny": [
"Bash(rm -rf *)",
"Bash(sudo *)",
"Read(./.env)"
]
}
}.claude/settings.json (proyecto):
{
"permissions": {
"allow": [
"Read(./src/**/*)",
"Write(./src/**/*)",
"Bash(npm run *)"
]
}
}.claude/settings.local.json (local):
{
"permissions": {
"allow": [
"Bash(npm publish)"
]
}
}Verificar configuración
Después de configurar, verifica que los permisos son correctos:
claude/permissionsDeberías ver un listado de todas las reglas activas y su origen.
Errores comunes
Patrón demasiado amplio
// ❌ Malo: permite escribir en cualquier lugar
"allow": ["Write"]
// ✅ Mejor: limita a directorios específicos
"allow": ["Write(./src/**/*)", "Write(./tests/**/*)"]Olvidar archivos sensibles
// ❌ Incompleto
"deny": ["Read(./.env)"]
// ✅ Completo
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./.env.local)",
"Read(./.env.production)"
]Patrón incorrecto para Bash
// ❌ No funciona como esperas
"allow": ["Bash(git)"]
// ✅ Correcto
"allow": ["Bash(git *)"]
// o específico
"allow": ["Bash(git status)", "Bash(git diff*)"]Puntos clave
- Usa
allowpara permisos automáticos ydenypara bloqueos permanentes - Los patrones glob permiten configuraciones flexibles (
*,**,{a,b}) - Configura permisos según el contexto: personal, equipo, CI/CD, datos sensibles
- El archivo local (
.claude/settings.local.json) tiene máxima prioridad - Verifica tu configuración con
/permissions - Sé específico: evita permisos demasiado amplios
- Siempre deniega acceso a archivos sensibles (.env, credenciales, keys)
Siguiente paso: En el punto 3.3 aprenderás patrones avanzados de permisos.
3.3 Patrones de permisos
Dominar los patrones de permisos te permite crear configuraciones precisas que permiten exactamente lo que necesitas y bloquean lo que no.
Anatomía de un patrón
Tool(patrón)
│ │
│ └── Qué archivos/comandos afecta
└── Herramienta (Read, Write, Bash, etc.)Patrones para Read y Write
Archivo específico
"Read(./package.json)"
"Write(./README.md)"Solo aplica a ese archivo exacto.
Todos los archivos en una carpeta
"Read(./src/*)"
"Write(./tests/*)"El * no atraviesa directorios. Solo archivos directamente en esa carpeta.
./src/* coincide con:
✓ ./src/index.ts
✓ ./src/app.js
✗ ./src/utils/helper.ts (subcarpeta)Todos los archivos recursivamente
"Read(./src/**/*)"
"Write(./src/**/*)"El ** atraviesa todos los subdirectorios.
./src/**/* coincide con:
✓ ./src/index.ts
✓ ./src/utils/helper.ts
✓ ./src/components/ui/Button.tsxPor extensión
"Read(*.ts)"
"Read(**/*.ts)"
"Write(**/*.{ts,tsx})"*.ts → Solo .ts en raíz
**/*.ts → Todos los .ts del proyecto
**/*.{ts,tsx} → Todos los .ts y .tsxPatrones de exclusión comunes
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(**/*.env)",
"Read(**/*.key)",
"Read(**/*.pem)",
"Read(**/*.p12)",
"Read(**/*.pfx)",
"Read(**/credentials*)",
"Read(**/secrets/**)",
"Read(**/private/**)",
"Write(**/node_modules/**)",
"Write(**/.git/**)",
"Write(*.lock)"
]
}
}Patrones para Bash
Los patrones de Bash son especiales porque coinciden con comandos, no con archivos.
Comando exacto
"Bash(git status)"
"Bash(npm test)"Solo permite ese comando exacto, sin argumentos adicionales.
Comando con cualquier argumento
"Bash(git *)"
"Bash(npm run *)"git * coincide con:
✓ git status
✓ git commit -m "mensaje"
✓ git push origin mainComando con opciones específicas
"Bash(git log*)"
"Bash(git diff*)"git log* coincide con:
✓ git log
✓ git log --oneline
✓ git log -n 10
✗ git status (no empieza con "git log")Lista de subcomandos
"Bash(git {status,log,diff,add,commit,push,pull})"Permite solo esos subcomandos de git.
Comandos con argumentos posicionales
"Bash(npm run *)"
"Bash(npx * --write)"npm run * coincide con:
✓ npm run dev
✓ npm run build
✓ npm run test:unitPatrones avanzados
Negación implícita con deny
Para permitir todo excepto algo específico:
{
"permissions": {
"allow": ["Bash(git *)"],
"deny": [
"Bash(git push --force*)",
"Bash(git reset --hard*)",
"Bash(git clean -fd*)"
]
}
}Esto permite todos los comandos git excepto los destructivos.
Combinación de extensiones
"Read(**/*.{js,jsx,ts,tsx,json,md,css,scss,html})"Permite leer todos los archivos de código comunes.
Excluir carpetas específicas
{
"permissions": {
"allow": ["Read(**/*.ts)"],
"deny": [
"Read(**/node_modules/**)",
"Read(**/dist/**)",
"Read(**/.git/**)",
"Read(**/coverage/**)"
]
}
}Patrones para múltiples herramientas
{
"permissions": {
"allow": [
"Read(./src/**/*)",
"Write(./src/**/*)",
"Edit(./src/**/*)"
]
}
}Recetas comunes
Proyecto TypeScript/JavaScript
{
"permissions": {
"allow": [
"Read(**/*.{ts,tsx,js,jsx,json,md,css,scss})",
"Read(./package.json)",
"Read(./tsconfig.json)",
"Read(./.eslintrc*)",
"Read(./.prettierrc*)",
"Write(./src/**/*.{ts,tsx})",
"Write(./tests/**/*.{ts,tsx})",
"Write(./*.md)",
"Bash(npm run *)",
"Bash(npm test*)",
"Bash(npx prettier *)",
"Bash(npx eslint *)",
"Bash(git {status,diff,log,add,commit,push,pull})"
],
"deny": [
"Read(./.env*)",
"Write(./package*.json)",
"Write(./*.lock)",
"Bash(npm install*)",
"Bash(npm publish*)",
"Bash(rm *)"
]
}
}Proyecto Python
{
"permissions": {
"allow": [
"Read(**/*.{py,pyi,json,yaml,yml,md,txt})",
"Read(./pyproject.toml)",
"Read(./setup.py)",
"Read(./requirements*.txt)",
"Write(./src/**/*.py)",
"Write(./tests/**/*.py)",
"Bash(python *)",
"Bash(pytest *)",
"Bash(pip list)",
"Bash(black *)",
"Bash(ruff *)",
"Bash(git {status,diff,log,add,commit,push,pull})"
],
"deny": [
"Read(./.env*)",
"Read(**/*secret*)",
"Write(./requirements*.txt)",
"Bash(pip install*)",
"Bash(rm *)",
"Bash(sudo *)"
]
}
}Proyecto Go
{
"permissions": {
"allow": [
"Read(**/*.{go,mod,sum,json,yaml,md})",
"Write(**/*.go)",
"Write(./*.md)",
"Bash(go build*)",
"Bash(go test*)",
"Bash(go run*)",
"Bash(go fmt*)",
"Bash(go vet*)",
"Bash(golangci-lint *)",
"Bash(git {status,diff,log,add,commit,push,pull})"
],
"deny": [
"Read(./.env*)",
"Write(./go.mod)",
"Write(./go.sum)",
"Bash(go get*)",
"Bash(rm *)"
]
}
}Proyecto Rust
{
"permissions": {
"allow": [
"Read(**/*.{rs,toml,md})",
"Write(./src/**/*.rs)",
"Write(./tests/**/*.rs)",
"Bash(cargo build*)",
"Bash(cargo test*)",
"Bash(cargo run*)",
"Bash(cargo fmt*)",
"Bash(cargo clippy*)",
"Bash(git {status,diff,log,add,commit,push,pull})"
],
"deny": [
"Read(./.env*)",
"Write(./Cargo.toml)",
"Write(./Cargo.lock)",
"Bash(cargo install*)",
"Bash(cargo publish*)",
"Bash(rm *)"
]
}
}Debugging de patrones
El patrón no coincide
Si un patrón no funciona como esperas:
- Verifica la ruta: ¿Es relativa (
./) o absoluta? - Verifica el glob: ¿Necesitas
*o**? - Verifica las llaves:
{ts,tsx}no es lo mismo que{ts, tsx}(sin espacios)
Probar patrones
Puedes probar si un patrón coincide con un archivo:
# En terminal, no en Claude Code
# Usa el comando find o ls con glob
ls ./src/**/*.ts 2>/dev/null
# Si lista archivos, el patrón es correctoVer qué regla aplica
/permissionsMuestra todas las reglas activas y puedes identificar conflictos.
Puntos clave
*coincide con cualquier cosa excepto/**coincide con cualquier cosa incluyendo/(recursivo){a,b,c}coincide con una de las opciones- Para Bash, los patrones coinciden con el comando completo
- Combina
allowcondenypara permisos precisos - Usa recetas específicas para tu stack tecnológico
- Verifica patrones con
/permissions
Siguiente paso: En el punto 3.4 aprenderás sobre el modo peligroso y cuándo usarlo.
3.4 Modo peligroso
El flag --dangerously-skip-permissions elimina todas las confirmaciones de permisos, permitiendo que Claude ejecute cualquier acción sin pedir aprobación. El nombre incluye "dangerously" intencionalmente: es una señal de que debes saber exactamente lo que estás haciendo.
Qué hace exactamente
En modo normal, Claude pide confirmación antes de:
- Ejecutar comandos en terminal (Bash)
- Modificar archivos (Write, Edit)
- Cualquier herramienta que requiera aprobación
Con --dangerously-skip-permissions, todas esas confirmaciones desaparecen. Claude actúa directamente.
# Modo normal: Claude pide permiso antes de cada acción
claude
# Modo peligroso: Claude ejecuta todo sin preguntar
claude --dangerously-skip-permissionsCuándo usarlo
Este modo tiene sentido en entornos donde no hay riesgo real:
Contenedores desechables
# Docker con volumen temporal
docker run --rm -it mi-entorno-dev bash
claude --dangerously-skip-permissions -p "Configura el proyecto y ejecuta los tests"El contenedor se destruye al terminar. No hay datos que proteger.
Máquinas virtuales de CI/CD
# GitHub Actions
- name: Análisis con Claude
run: |
claude --dangerously-skip-permissions -p "Revisa el código y genera reporte"El runner es efímero y aislado.
Automatización sin supervisión
# Script que procesa múltiples archivos
for file in ./src/*.ts; do
claude --dangerously-skip-permissions -p "Añade tipos estrictos a $file"
doneCuando necesitas que Claude trabaje en lote sin interrupciones.
Entornos de desarrollo aislados
# VM de desarrollo sin acceso a producción
# Sin credenciales, sin datos sensibles
claude --dangerously-skip-permissionsCuándo NO usarlo
Proyectos de producción
# NUNCA hagas esto en un servidor de producción
claude --dangerously-skip-permissions -p "Limpia los logs antiguos"
# Claude podría ejecutar rm -rf en directorios importantesMáquinas con datos sensibles
Si tu máquina tiene:
- Archivos
.envcon credenciales - Claves SSH o GPG
- Tokens de API
- Bases de datos locales con datos reales
No uses este modo. Un prompt ambiguo podría llevar a Claude a leer o modificar estos archivos.
Entornos compartidos
# Servidor compartido con otros desarrolladores
# Claude podría modificar archivos de otros usuarios
claude --dangerously-skip-permissions # NOCuando no entiendes lo que vas a pedir
Si tu prompt es vago o experimental, el modo normal te protege:
# Prompt vago + modo peligroso = riesgo
claude --dangerously-skip-permissions -p "Arregla todo lo que encuentres mal"
# ¿Qué va a hacer Claude? No lo sabes. Mal momento para saltarse permisos.Modos de permisos relacionados
Claude Code ofrece varios modos de permisos que ofrecen distintos niveles de control:
| Modo | Comportamiento |
|---|---|
default | Pide confirmación la primera vez que usa cada herramienta |
acceptEdits | Acepta automáticamente ediciones de archivos |
plan | Solo lectura, no puede modificar ni ejecutar |
bypassPermissions | Salta todas las confirmaciones (equivalente al flag) |
# Solo lectura: Claude analiza pero no toca nada
claude --permission-mode plan
# Acepta ediciones automáticamente pero pide permiso para bash
claude --permission-mode acceptEditsInteracción con hooks
Los hooks siguen ejecutándose incluso con --dangerously-skip-permissions. Esto es importante: los hooks son una capa de seguridad independiente del sistema de permisos.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash(rm *)",
"hooks": [
{
"type": "command",
"command": "echo 'BLOCKED: intento de rm detectado' && exit 1"
}
]
}
]
}
}Con esta configuración, aunque uses --dangerously-skip-permissions, el hook bloqueará cualquier intento de ejecutar rm. Los hooks actúan como última línea de defensa.
Buenas prácticas
Combina con prompts específicos
# Mal: modo peligroso + prompt interactivo abierto
claude --dangerously-skip-permissions
# Bien: modo peligroso + tarea concreta y acotada
claude --dangerously-skip-permissions -p "Ejecuta npm test y muestra los resultados"Usa hooks como red de seguridad
Aunque saltes permisos, configura hooks que bloqueen acciones destructivas:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash(rm -rf*)",
"hooks": [{ "type": "command", "command": "exit 1" }]
},
{
"matcher": "Bash(sudo *)",
"hooks": [{ "type": "command", "command": "exit 1" }]
}
]
}
}Limita el alcance cuando sea posible
En lugar de --dangerously-skip-permissions completo, considera si --permission-mode acceptEdits es suficiente para tu caso.
Puntos clave
--dangerously-skip-permissionselimina todas las confirmaciones- Úsalo solo en entornos aislados y desechables
- Los hooks siguen funcionando como red de seguridad
- Combínalo con prompts específicos (
-p), no con sesiones interactivas abiertas - Considera
--permission-mode acceptEditscomo alternativa menos agresiva - Si tienes dudas sobre si usarlo: no lo uses
Siguiente paso: En el punto 3.5 aprenderás sobre los Trust Dialogs y cómo Claude gestiona la confianza por directorio.
3.5 Trust Dialogs
Cada vez que Claude necesita hacer algo que podría tener impacto en tu sistema, muestra un diálogo de confirmación. Estos "Trust Dialogs" son el mecanismo principal de seguridad interactiva de Claude Code.
Verificación de confianza por directorio
La primera vez que ejecutas claude en un directorio nuevo, Claude Code establece una relación de confianza con ese proyecto. Esto implica:
- Reconocer el directorio como espacio de trabajo
- Cargar los archivos de configuración del proyecto (
.claude/settings.json,CLAUDE.md) - Aplicar las reglas de permisos definidas para ese proyecto
La confianza es por directorio. Los permisos que concedes en un proyecto no aplican a otro.
~/proyecto-a/ → Permisos concedidos aquí
~/proyecto-b/ → Requiere sus propios permisosTipos de aprobación según la herramienta
No todas las acciones requieren el mismo nivel de aprobación:
| Tipo de acción | Ejemplo | Aprobación | Duración |
|---|---|---|---|
| Solo lectura | Leer archivos, Grep | No requiere | — |
| Comandos Bash | Ejecutar en terminal | Sí | Permanente por proyecto y comando |
| Modificación de archivos | Write, Edit | Sí | Solo durante la sesión |
Solo lectura: sin confirmación
> ¿Qué hace la función validateUser?
# Claude lee archivos libremente para responder
# No aparece ningún diálogoLas operaciones de lectura (Read, Grep, Glob) nunca piden permiso. Claude necesita leer para entender tu código.
Comandos Bash: aprobación permanente por proyecto
> Ejecuta los tests
┌─────────────────────────────────────────────────┐
│ Claude quiere ejecutar: │
│ │
│ npm test │
│ │
│ [Permitir] [Permitir siempre] [Denegar] │
└─────────────────────────────────────────────────┘Si eliges "Permitir siempre", el comando npm test queda aprobado permanentemente para ese directorio. La próxima vez que Claude necesite ejecutarlo, no preguntará.
Modificación de archivos: aprobación por sesión
> Añade validación al formulario de login
┌─────────────────────────────────────────────────┐
│ Claude quiere modificar: │
│ │
│ src/components/LoginForm.tsx │
│ │
│ [Permitir] [Denegar] │
└─────────────────────────────────────────────────┘La aprobación de edición de archivos dura solo hasta que termina la sesión. En la siguiente sesión, Claude volverá a pedir permiso.
Modos de permisos interactivos
Puedes cambiar el modo de permisos durante una sesión con Shift+Tab:
Default
El comportamiento estándar descrito arriba. Pide confirmación según el tipo de acción.
Accept edits
claude --permission-mode acceptEditsAcepta automáticamente todas las ediciones de archivos, pero sigue pidiendo confirmación para comandos Bash. Útil cuando confías en que Claude editará correctamente pero quieres controlar qué ejecuta.
Plan
claude --permission-mode planModo solo lectura. Claude puede analizar tu código pero no puede modificar archivos ni ejecutar comandos. Ideal para:
- Explorar un codebase nuevo
- Pedir explicaciones sin riesgo
- Revisar antes de dar permiso para cambios
Don't ask
claude --permission-mode dontAskDeniega automáticamente cualquier acción que no esté pre-aprobada en la configuración. Claude solo puede hacer lo que allowedTools permita explícitamente.
Pre-aprobar acciones con configuración
En lugar de responder diálogos uno a uno, puedes pre-aprobar acciones en .claude/settings.json:
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(git *)",
"Write(./src/**/*)"
]
}
}Con esta configuración, Claude nunca preguntará antes de ejecutar comandos npm/git o editar archivos en src/. Los diálogos solo aparecerán para acciones no cubiertas por estas reglas.
Orden de evaluación
Cuando Claude quiere ejecutar una acción, el sistema evalúa en este orden:
1. ¿Está en "deny"? → Bloqueado, sin diálogo
2. ¿Está en "allow"? → Permitido, sin diálogo
3. ¿El modo es plan? → Bloqueado, sin diálogo
4. ¿El modo es acceptEdits? → Permitido si es edición
5. ¿El modo es dontAsk? → Bloqueado, sin diálogo
6. Modo default → Muestra Trust DialogTrust y MCP servers
Los servidores MCP también requieren verificación de confianza. La primera vez que añades un MCP nuevo, Claude Code pide confirmación antes de activarlo:
┌─────────────────────────────────────────────────┐
│ Nuevo servidor MCP detectado: │
│ │
│ github (@modelcontextprotocol/server-github) │
│ │
│ ¿Confiar en este servidor? │
│ [Sí] [No] │
└─────────────────────────────────────────────────┘Gestionar permisos concedidos
Para ver qué permisos están activos en tu sesión:
/permissionsEsto muestra todas las reglas activas: las definidas en configuración y las concedidas interactivamente.
Para resetear permisos concedidos a un proyecto:
# Eliminar configuración local del proyecto
rm .claude/settings.local.json
# Eliminar toda la configuración del proyecto
rm -rf .claude/Ejecución no interactiva
Cuando usas Claude con el flag -p (prompt directo), la verificación de confianza del directorio se desactiva. Esto es necesario para que funcione en scripts y pipelines:
# No hay Trust Dialog en modo no interactivo
claude -p "Lista los archivos TypeScript del proyecto"Sin embargo, los permisos de herramientas siguen aplicando. Si un comando no está pre-aprobado y no usas --dangerously-skip-permissions, Claude no podrá ejecutarlo.
Puntos clave
- La confianza es por directorio: cada proyecto tiene sus propios permisos
- Las lecturas nunca piden permiso; los comandos Bash se aprueban permanentemente por proyecto; las ediciones se aprueban por sesión
- Usa
Shift+Tabpara cambiar entre modos de permisos durante la sesión - Pre-aprueba acciones frecuentes en
.claude/settings.jsonpara evitar diálogos repetitivos - Los servidores MCP también requieren verificación de confianza
- En modo no interactivo (
-p) se desactiva la verificación del directorio
Siguiente paso: En la práctica del módulo aplicarás todo lo aprendido configurando permisos para un proyecto real.
Práctica del módulo 3: Gestión de permisos y seguridad
En esta práctica configurarás permisos restrictivos para un proyecto, probarás los límites del sistema de permisos y crearás una configuración de seguridad adaptada a tu flujo de trabajo.
Objetivos
- Configurar permisos restrictivos para un proyecto
- Probar qué pasa cuando Claude intenta acceder a archivo denegado
- Crear lista de comandos bash permitidos para tu workflow
- Experimentar con los modos de permisos
Ejercicio 1: Preparar el entorno
Paso 1.1: Crear proyecto de prueba
Crea un proyecto con estructura realista para practicar:
mkdir -p ~/practica-permisos/src
mkdir -p ~/practica-permisos/tests
mkdir -p ~/practica-permisos/.claude
touch ~/practica-permisos/.env
touch ~/practica-permisos/.env.production
touch ~/practica-permisos/src/app.ts
touch ~/practica-permisos/src/config.ts
touch ~/practica-permisos/tests/app.test.tsPaso 1.2: Añadir contenido de prueba
Añade contenido al archivo .env:
DB_PASSWORD=super_secreto_123
API_KEY=sk-fake-key-para-practicaY al archivo src/app.ts:
export function hello(): string {
return "Hola desde la práctica de permisos";
}Verificación: La estructura del proyecto existe con archivos que contienen datos.
Ejercicio 2: Permisos restrictivos
Paso 2.1: Crear configuración de permisos
Crea el archivo ~/practica-permisos/.claude/settings.json:
{
"permissions": {
"allow": [
"Read(./src/**/*)",
"Read(./tests/**/*)",
"Write(./src/**/*)",
"Write(./tests/**/*)",
"Bash(npm test*)",
"Bash(npx tsc*)",
"Bash(git {status,diff,log})"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Write(./.env*)",
"Write(./package*.json)",
"Bash(rm *)",
"Bash(sudo *)",
"Bash(curl *)",
"Bash(wget *)"
]
}
}Paso 2.2: Verificar que la configuración se carga
cd ~/practica-permisos
claudeDentro de la sesión:
/permissionsVerificación: Ves las reglas de allow y deny que configuraste.
Ejercicio 3: Probar los límites
Paso 3.1: Intentar leer archivo protegido
Dentro de la sesión de Claude, pide:
Muéstrame el contenido del archivo .envClaude debería no poder leer el archivo porque está en la lista deny.
Paso 3.2: Verificar que la lectura permitida funciona
Muéstrame el contenido de src/app.tsClaude debería poder leerlo sin problemas.
Paso 3.3: Intentar comando denegado
Ejecuta curl https://example.comClaude debería rechazar la ejecución.
Paso 3.4: Verificar comando permitido
Ejecuta git statusClaude debería ejecutarlo sin diálogo de confirmación.
Paso 3.5: Probar comando no listado
Ejecuta ls -laComo ls no está en allow ni en deny, Claude debería mostrar un Trust Dialog pidiendo confirmación.
Verificación: Entiendes la diferencia entre acciones denegadas, permitidas y no configuradas.
Ejercicio 4: Modos de permisos
Paso 4.1: Modo plan (solo lectura)
Inicia Claude en modo plan:
cd ~/practica-permisos
claude --permission-mode planIntenta pedir una modificación:
Añade un comentario al archivo src/app.tsClaude debería explicar qué haría pero no ejecutar la modificación.
Paso 4.2: Modo acceptEdits
Sal y reinicia con:
claude --permission-mode acceptEditsPide una modificación:
Añade un comentario al inicio de src/app.tsClaude debería editar el archivo sin pedir confirmación para la escritura.
Ahora pide ejecutar un comando no pre-aprobado:
Ejecuta ls -laClaude debería pedir confirmación para el comando Bash.
Paso 4.3: Cambiar modo en sesión
Inicia una sesión normal y cambia el modo con Shift+Tab. Observa cómo cambia el comportamiento sin reiniciar.
Verificación: Entiendes cómo cada modo afecta el comportamiento de los diálogos.
Ejercicio 5: Configuración para tu workflow real
Paso 5.1: Identificar tu stack
Piensa en un proyecto real tuyo. Identifica:
- ¿Qué lenguaje/framework usas?
- ¿Qué comandos ejecutas frecuentemente? (build, test, lint, format)
- ¿Qué archivos contienen secretos?
- ¿Qué acciones destructivas quieres bloquear?
Paso 5.2: Crear configuración personalizada
Basándote en las recetas del punto 3.3, crea un .claude/settings.json para tu proyecto real. Ejemplo para un proyecto Node.js:
{
"permissions": {
"allow": [
"Read(./src/**/*)",
"Read(./tests/**/*)",
"Read(./package.json)",
"Read(./tsconfig.json)",
"Write(./src/**/*)",
"Write(./tests/**/*)",
"Bash(npm run *)",
"Bash(npm test*)",
"Bash(npx prettier *)",
"Bash(npx eslint *)",
"Bash(git {status,diff,log,add,commit,push,pull})"
],
"deny": [
"Read(./.env*)",
"Read(**/*secret*)",
"Read(**/*.pem)",
"Write(./package*.json)",
"Write(./*.lock)",
"Bash(npm install*)",
"Bash(npm publish*)",
"Bash(rm -rf*)",
"Bash(sudo *)"
]
}
}Paso 5.3: Probar la configuración
Inicia Claude en tu proyecto real y trabaja normalmente. Observa:
- ¿Aparecen demasiados Trust Dialogs? → Añade más reglas a
allow - ¿Claude hace algo que no debería? → Añade reglas a
deny - ¿El flujo es cómodo? → Tu configuración está bien calibrada
Verificación: Tienes una configuración de permisos funcional para tu proyecto real.
Ejercicio 6: Hooks como red de seguridad
Paso 6.1: Añadir hook protector
Añade al settings.json del proyecto de prueba un hook que bloquee comandos destructivos incluso si alguien usa --dangerously-skip-permissions:
{
"permissions": {
"allow": ["..."],
"deny": ["..."]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash(rm *)",
"hooks": [
{
"type": "command",
"command": "echo 'BLOQUEADO: intento de rm' && exit 1"
}
]
}
]
}
}Paso 6.2: Probar el hook
Inicia Claude con permisos saltados:
cd ~/practica-permisos
claude --dangerously-skip-permissions -p "Ejecuta rm -rf ./src"El hook debería bloquear la ejecución a pesar de --dangerously-skip-permissions.
Verificación: Los hooks funcionan como última línea de defensa.
Checklist de validación
Marca cada punto cuando lo hayas completado:
- He creado un proyecto con configuración de permisos restrictiva
- He verificado que Claude no puede leer archivos en
deny - He verificado que Claude puede leer archivos en
allowsin diálogo - He probado que comandos no listados generan un Trust Dialog
- He usado el modo
plany confirmado que es solo lectura - He usado
acceptEditsy confirmado que edita sin preguntar - He creado una configuración de permisos para mi proyecto real
- He configurado un hook como red de seguridad
Troubleshooting común
Claude ignora mis reglas de deny
- Verifica que el path es correcto (relativo con
./) - Revisa que no haya una regla en
allowmás específica que la contraiga - Recuerda:
denytiene prioridad sobreallow
Demasiados Trust Dialogs
Cada vez que Claude necesita un permiso no pre-aprobado, pregunta. Soluciones:
- Añade los comandos frecuentes a
allow - Usa
--permission-mode acceptEditssi confías en las ediciones - Usa patrones con
*para cubrir variantes de un comando
El hook no se ejecuta
- Verifica que el
matchercoincide con el patrón exacto - Recuerda que el matcher usa el formato
Tool(patrón) - Comprueba que el comando del hook tiene permisos de ejecución
"Permission denied" en modo no interactivo
Con -p, los Trust Dialogs no aparecen. Si una acción no está en allow, Claude no puede ejecutarla. Pre-aprueba lo necesario o usa --dangerously-skip-permissions en entornos seguros.
Reto adicional (opcional)
Crea un "perfil de seguridad" multinivel para tu equipo:
- Perfil junior — Solo lectura y tests:
{
"permissions": {
"allow": ["Read(**/*)", "Bash(npm test*)"],
"deny": ["Read(./.env*)", "Write(**/*)", "Bash(git push*)"]
}
}- Perfil senior — Lectura, escritura en src, git completo:
{
"permissions": {
"allow": [
"Read(**/*)",
"Write(./src/**/*)",
"Bash(npm *)",
"Bash(git *)"
],
"deny": ["Read(./.env*)", "Bash(rm -rf*)", "Bash(sudo *)"]
}
}- Perfil CI — Todo permitido en entorno aislado:
claude --dangerously-skip-permissions -p "Ejecuta build y tests"Guarda cada perfil como archivo separado y cárgalos según el contexto.
Siguiente módulo: Comandos slash y personalización