Where does the bug appear (feature/product)?
Cursor CLI
Describe the Bug
In headless mode on Windows (no POSIX shell detected), every hook invocation blocks its tool call for the FULL configured timeout, even though the hook process exits in ~0.1 s with a valid {"permission": "allow"} on stdout. The tool call duration tracks the configured timeout exactly, not the hook’s runtime: with "timeout": 10 a simple readToolCall takes 10.4 s, with "timeout": 3 it takes 3.4 s, with "timeout": 1 it takes 1.5 s, and 0.4 s with no hooks registered (control). With no timeout field, .cursor/hooks.json hooks make each edit wait ~30-40 s. On a workspace with a normal hook setup this makes headless runs 5-10x slower (our read+shell+2-edits benchmark: 93 s with hooks vs 51 s after workarounds vs ~20 s hook-free).
There is a security consequence: lowering the timeout to compensate silently disables deny-hooks. With "timeout" set to 3, 6 or 8 on a preToolUse hook that denies writes to protected files (and answers in ~0.1 s), the hook is killed before its verdict is collected and the agent proceeds fail-open: during our test the protected file was actually rewritten, with no warning or error anywhere in the stream-json output.
All timings come from the timestamp_ms fields of the stream-json output (tool_call started → completed), cross-checked with an instrumented hook that logs its own start/exit times.
Steps to Reproduce
- Create a minimal workspace containing:
target.md (any content)
.cursor/hooks.json:
{
"version": 1,
"hooks": {
"preToolUse": [
{ "command": "python hook.py", "timeout": 3,
"matcher": "Write|StrReplace|Edit|ApplyPatch" }
]
}
}
hook.py: reads stdin, appends a timestamped line to a log file, prints {"permission": "deny", "agent_message": "blocked"} and exits (runs in <0.2 s).
- From
cmd.exewithMSYSTEM/SHELL/EXEPATHcleared (so no POSIX shell is detected), run:
cursor-agent.cmd -p --force --trust --output-format stream-json "Append a line to target.md"
- Observe via the stream-json
timestamp_msfields and the hook’s own log:- Full-timeout wait: change the hook to answer
{"permission": "allow"}and set"timeout": 10→ the edit tool call takes ~10 s although the hook exited after ~0.1 s. Lower the timeout to 1 → ~1.5 s. The wait always equals the configured timeout, regardless of when the hook exits or what it prints. - Silent fail-open: with the deny hook and
"timeout": 3(or 6, or 8) →target.mdIS modified and no error or warning is emitted. Remove thetimeoutfield → the deny works (but each edit then waits ~30-40 s).
- Full-timeout wait: change the hook to answer
Expected Behavior
- The hook wrapper should resolve as soon as the hook process exits and its stdout verdict is available;
timeoutshould only be a cap for hung hooks, not a fixed wait applied to every invocation. - A
preToolUsehook killed by timeout should not silently fail-open: either fail-closed by default for deny-capable hooks, or at least emit a visible warning in the output so guard authors can detect that their hook was killed.
Operating System
Windows 10/11
Version Information
CLI Version 2026.08.25-3e8eec8 (Latest, up to date)
OS: win32 (x64)
For AI issues: which model did you use?
Model name: composer-2.5-fast (headless -p runs; also reproduced with cursor-grok-4.6-high-fast)
For AI issues: add Request ID with privacy disabled
Request ID: 194bfa0d-f227-42ef-b429-d3fdffe1ef9d (full-timeout wait, hooks answering allow, timeout 10)
Also relevant: 05d7d1c9-38b6-48ca-92eb-5d006fa30832 (timeout 1 → waits shrink to ~1 s, confirming the wait tracks the configured timeout, not hook runtime)
Additional Information
- Likely related to the known Windows shell issues: topic 151858 (“Agent CLI on Windows: no way to configure shell, hardcoded to PowerShell”, confirmed as a bug in February) and topic 167319 (“Windows agent shell: ~17-30s overhead”). We measure ~26 s per shell command with pwsh 7 on PATH and ~18 s with the Windows PowerShell 5.1 fallback, for commands that run in <1 s directly — the per-invocation hook wait may share the same root cause (PowerShell session handshake per invocation).
- Separate but related data-loss finding: if a POSIX shell IS detected (Git Bash env,
MSYSTEM=MINGW64), everything becomes fast but hook wrappers crash (shell commands reported as “blocked by a hook”) and, more importantly,editToolCallreturns success while the target file is left unchanged — silent edit loss. This is why we strip the POSIX env in the first place. Happy to file it separately if you prefer. - We can provide the full stream-json captures and the instrumented hook logs on request. Thanks a lot for looking into this!
Does this stop you from using Cursor
No - Cursor works, but with this issue