[Windows] Hook stdin corrupts Chinese UTF-8 in beforeSubmitPrompt JSON (BOM + mojibake)

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

On Windows, command hooks receive corrupted UTF-8 for Chinese text in the JSON payload on stdin, even though Cursor’s own Hooks output / UI shows the prompt correctly. This affects beforeSubmitPrompt and likely other hook events that include user text.

The issue appears to be UTF-8 bytes being misinterpreted as GBK (or similar code page) when Cursor writes hook stdin, not a problem in the hook script itself.

Steps to Reproduce

  1. On Windows, configure a user hook in ~/.cursor/hooks.json:
{
  "version": 1,
  "hooks": {
    "beforeSubmitPrompt": [{ "command": "./hooks/curl-notify.exe" }]
  }
}
  1. Implement the hook as a small program that:

    • Reads all bytes from stdin
    • Logs the raw body to stderr (so Cursor Hooks output channel shows it)
    • Does not transform encoding
  2. Restart Cursor.

  3. In Agent chat, submit a prompt containing Chinese, e.g. 中文测试.

  4. Open Cursor → Hooks output channel and inspect stderr from the hook.

Expected Behavior

The JSON on hook stdin should contain the same UTF-8 text as shown in Cursor, e.g.:

"prompt": "中文测试"

No BOM. Bytes for the prompt should be:

e4 b8 ad e6 96 87 e6 b5 8b e8 af 95

The hook receives valid UTF-8 JSON, but the Chinese content inside is already garbled before the hook process reads it.

Example stderr output:

curl-notify raw: 665 bytes
curl-notify: stripped UTF-8 BOM
curl-notify raw prompt="涓\ue15f枃娴嬭瘯" hex=e6b693ee859fe69e83e5a8b4e5acade798af

Observations:

  1. UTF-8 BOM (EF BB BF) is present before { in the stdin payload.
  2. prompt is mojibake, not the original Chinese.
  3. A Private Use Area character appears in the string (U+E15F, bytes EE 85 9F), suggesting bytes were lost or mis-decoded during conversion.
  4. This happens with:
    • bash + curl --data-binary @-
    • Go binary with direct io.ReadAll(os.Stdin) (no shell involved)

So the corruption occurs when Cursor passes data to the hook subprocess, not in HTTP forwarding or hook script encoding.

Operating System

Windows 10/11

Version Information

Version: 3.15.6 (user setup)
VS Code Extension API: 1.128.0
Commit: a1f686545fd0ce8917bbd2449f733551a9bce420
Date: 2026-08-06T01:41:03.876Z
Layout: IDE
Build Type: Stable
Release Track: Default
Electron: 40.10.3
Chromium: 144.0.7559.236
Node.js: 24.15.0
V8: 14.4.258.32-electron.0
xterm.js: 6.1.0-beta.291
OS: Windows_NT x64 10.0.26200

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey, thanks for the detailed report. The byte-level breakdown really helps.

This is a known issue with hooking stdin on Windows. When Cursor uses Windows PowerShell 5.1, a BOM-less UTF-8 payload gets read using the system ANSI code page GBK on Chinese Windows. That causes mojibake, and then a UTF-8 BOM gets added on output EF BB BF. What you’re seeing is exactly that, and it’s not an issue with your hook script.

A workaround that fixes both issues is to install PowerShell 7 pwsh and make sure it’s in PATH. Cursor prefers pwsh over powershell.exe, and PowerShell 7 defaults to UTF-8 without BOM, so both the mojibake and the BOM go away.

As an alternative, you can enable the Windows system beta setting Use Unicode UTF-8 for worldwide language support in Region settings → Administrative → Change system locale. That switches the ANSI code page to UTF-8. Just note this affects all legacy apps system-wide, so using pwsh is usually safer.

We’re tracking the issue already. I can’t share an ETA yet, but I’ll reply in the thread if there’s an update. If you still see mojibake after installing pwsh, let me know and we’ll dig in further.

Related threads on the same topic if you’re interested: Hook stdin pipe double-encodes non-ASCII on non-UTF-8 Windows, On Windows, Cursor’s hook stdin JSON payload includes a UTF-8 BOM that breaks standard JSON.parse(), causing security guards to silently degrade to allowing commands across all agent channels