Hook beforeReadFile does not work in the agent

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

I created a hook to block readings of the .env file using beforeReadFile, but it doesn’t work in the Cursor IDE agent. However, if I try to echo the file by running the script that blocks the reading, it works fine. I’ve tried creating other hooks with different events, and they work fine.

Steps to Reproduce

config hook:
{
“version”: 1,
“hooks”: {
“beforeReadFile”: [
{
“command”: “python3 .cursor/hooks/block_env_read.py”
}
]
}
}
create file hook:
#!/usr/bin/env python3
“”"
Hook para bloquear la lectura de archivos .env por parte del agente.

Este script implementa el hook beforeReadFile de Cursor para evitar que
el agente acceda a archivos de configuración sensibles que puedan contener
credenciales, claves API u otra información confidencial.
“”"
import json
import sys
from pathlib import Path

def main() → None:
“”"
Procesa la solicitud de lectura de archivo y determina si debe permitirse.

Lee el input JSON desde stdin, verifica si el archivo es un .env,
y responde con la decisión de permitir o denegar el acceso.
"""
try:
    # Leer el input JSON desde stdin
    payload = json.load(sys.stdin)
    file_path = payload.get("file_path", "")
    
    # Crear objeto Path para facilitar el análisis del archivo
    path = Path(file_path)
    
    # Verificar si el archivo es .env o termina con .env
    # Esto capturará: .env, .env.local, .env.production, etc.
    is_env_file = (
        path.name == ".env" or 
        path.name.startswith(".env.") or
        path.name.endswith(".env")
    )
    
    # Preparar la respuesta
    response = {}
    
    if is_env_file:
        # Bloquear el acceso a archivos .env
        response = {
            "permission": "deny",
            "user_message": (
                f"Acceso bloqueado: El archivo '{path.name}' contiene variables de entorno "
                "y credenciales sensibles. Por seguridad, el agente no puede leer este archivo. "
                "Si necesitas compartir configuración específica, cópiala manualmente o "
                "usa un archivo de ejemplo sin credenciales reales."
            )
        }
        # Log para debugging (se mostrará en el output channel de Hooks)
        sys.stderr.write(f"[BLOQUEADO] Intento de lectura de archivo sensible: {file_path}\n")
    else:
        # Permitir el acceso a otros archivos
        response = {
            "permission": "allow"
        }
    
    # Enviar la respuesta como JSON a stdout
    print(json.dumps(response))
    sys.exit(0)
    
except Exception as e:
    # En caso de error, el hook usa fail-closed, por lo que bloqueará el acceso
    sys.stderr.write(f"[ERROR] Hook fallido: {str(e)}\n")
    # Devolver un deny explícito en caso de error
    error_response = {
        "permission": "deny",
        "user_message": "Error al procesar la solicitud de lectura. Acceso denegado por seguridad."
    }
    print(json.dumps(error_response))
    sys.exit(1)

if name == “main”:
main()

Operating System

MacOS

Version Information

Cursor IDE: Agent send message: “Read file .env and tell me all info into file”

For AI issues: which model did you use?

Sonnet 4, Composer1, Codex5.2

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey, thanks for the report. This is a known issue: hooks do trigger, but permission: deny and other response fields aren’t always handled correctly by the agent.

It’s documented in detail here: Hooks in 2.4.7 are still not working properly

The team is aware of the bug. For now, the workaround is to add .env to your .cursorignore file so the agent can’t see the file at all:

# .cursorignore
.env
.env.*

This prevents the agent from reading the contents of .env files. Not ideal, but it works until hooks are fixed.

1 Like

Thank you so much for your feedback; I’ll use that solution in the meantime. Thanks.

1 Like