Skip to content

Mihawii/vscodeforks_vulnerability

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cursor Device-Identifier Reset / Hook Toolkit

Security research artifact — disclosed to Cursor / Windsurf engineering for review of the editors' trial-validation and device-telemetry vector. Provided for reproduction and remediation discussion; not for redistribution.

Cursor

Overview

This repository demonstrates two complementary techniques that, together, bypass per-device trial / abuse identifiers used by the Cursor editor (and by extension other VS Code / Electron forks that inherit the same telemetry stack):

  1. Static configuration spoofing — overwriting the editor's storage.json with fabricated identifiers and locking it read-only so the editor cannot self-correct on next boot. See scripts/run/.
  2. Runtime execution hooking — patching the Electron main.js to load a CommonJS shim (cursor_hook.js) that intercepts child_process.execSync (registry / ioreg / /etc/machine-id reads), crypto.createHash (SHA-256 of the platform UUID), @vscode/deviceid, @vscode/windows-registry, and os.networkInterfaces. See scripts/hook/.

The two stages reinforce each other: the static pass prevents the editor from rewriting the spoofed file at startup, and the runtime hook ensures that any code path which re-derives an ID from hardware queries still returns the spoofed value.

Targeted fields

The toolkit rotates the following identifiers consumed by the editor's trial-tracking and analytics pipelines:

  • telemetry.machineId
  • telemetry.macMachineId
  • telemetry.devDeviceId
  • telemetry.sqmId
  • MachineGuid (Windows: HKLM\SOFTWARE\Microsoft\Cryptography)
  • IOPlatformUUID (macOS: ioreg -d2 -c IOPlatformExpertDevice)
  • /etc/machine-id (Linux)
  • Primary interface MAC address (os.networkInterfaces)

Files

scripts/
  hook/
    cursor_hook.js          # Runtime hook: intercepts ID-deriving Node APIs
    inject_hook_unix.sh     # Patches Cursor's main.js on macOS / Linux
    inject_hook_win.ps1     # Patches Cursor's main.js on Windows
  run/
    cursor_mac_id_modifier.sh    # Static spoof + permission lock (macOS)
    cursor_linux_id_modifier.sh  # Static spoof + permission lock (Linux)
    cursor_win_id_modifier.ps1   # Static spoof + registry update (Windows)
    lib/
      read_existing_ids.py       # Reads current telemetry IDs from storage.json
      b6_patcher.py              # Rewrites the b6() machineId helper in main.js

Configuration file locations modified

  • Windows: %APPDATA%\Cursor\User\globalStorage\storage.json
  • macOS: ~/Library/Application Support/Cursor/User/globalStorage/storage.json
  • Linux: ~/.config/Cursor/User/globalStorage/storage.json

Hook behavior (cursor_hook.js)

The shim is injected near the top of the editor's main.js (after Sentry init). On load it generates — or reads from ~/.cursor_ids.json — a stable set of fake identifiers, then monkey-patches:

Module Hooked surface Effect
child_process execSync, execFileSync Returns synthetic output for reg query … MachineGuid, ioreg … IOPlatformExpertDevice, and machine-id / hostname reads
crypto createHash('sha256'), randomUUID Returns the spoofed machineId when input looks like a platform UUID; returns spoofed devDeviceId for the first two randomUUID() calls
os networkInterfaces Returns a single fabricated Ethernet adapter with the spoofed MAC
@vscode/deviceid getDeviceId Returns the spoofed devDeviceId directly
@vscode/windows-registry GetStringRegKey Spoofs MachineId / MachineGuid registry reads

Override via env vars (CURSOR_MACHINE_ID, CURSOR_MAC_MACHINE_ID, CURSOR_DEV_DEVICE_ID, CURSOR_SQM_ID, CURSOR_MAC_ADDRESS) or by editing ~/.cursor_ids.json. Set __cursor_hook_config__.debug = true for verbose [CursorHook] logging.

Reproduction (from the local tree)

macOS

sudo bash scripts/run/cursor_mac_id_modifier.sh
# optional runtime hook:
bash scripts/hook/inject_hook_unix.sh

Linux

sudo bash scripts/run/cursor_linux_id_modifier.sh
bash scripts/hook/inject_hook_unix.sh

Windows (admin PowerShell)

.\scripts\run\cursor_win_id_modifier.ps1
.\scripts\hook\inject_hook_win.ps1

inject_hook_* accept --rollback / -Rollback to restore the original main.js from the auto-saved backup, and --force / -Force to re-inject after a Cursor update overwrites the patched file.

What gets backed up

  • main.js<resources>/app/out/backups/main.js.original (plus timestamped copies)
  • Windows MachineGuid%APPDATA%\Cursor\User\globalStorage\backups\MachineGuid.backup_YYYYMMDD_HHMMSS

Restore paths are documented inline in each script.

Sample output

A successful end-to-end run on macOS looks like this (truncated; the Linux and Windows transcripts are structurally identical):

========================================
   Cursor device-ID reset (macOS)
========================================

[INFO] Target user: olzhas
[INFO] Target user Home: /Users/olzhas
[INFO] Target user's primary group: staff
[INFO] Found Cursor app: /Applications/Cursor.app
[INFO] Found Cursor main.js: /Applications/Cursor.app/Contents/Resources/app/out/main.js
[INFO] Config file path: /Users/olzhas/Library/Application Support/Cursor/User/globalStorage/storage.json

[Check] Cursor process...
[Close] Closing Cursor process so the file can be modified...
[INFO] Cursor processes stopped

[Backup] Backing up original configuration...
[INFO] Created original backup:    .../backups/storage.json.original
[INFO] Created timestamped backup: .../backups/storage.json.backup_20260524_222342

[Prepare] Device identifiers ready
   machineId:     0157e4b48fc7573057235f3be7e5275eaf09411a0f9836b...
   machineGuid:   7368873d-8ee0-43f4-a47a-d61cb22fadfd
   devDeviceId:   03491173-9cc4-44ac-8463-c0f73c44ad88
   macMachineId:  a6d80553-cdde-43eb-91d8-39c089a4f06d
   sqmId:         {C23EF132-7B7E-4C6B-B003-C0FF7CB44A88}

[Inject] Injecting hook into main.js...
[INFO] Hook injected successfully

[Save] New ID config saved to: /Users/olzhas/.cursor_ids.json
[Hook] External hook deployed: /Users/olzhas/.cursor_hook.js

[Complete] All device-ID modifications complete
[INFO] You can now launch Cursor
[INFO] ID config file location: ~/.cursor_ids.json

Tips:
  - To roll back:        bash scripts/hook/inject_hook_unix.sh --rollback
  - To force re-inject:  bash scripts/hook/inject_hook_unix.sh --force
  - To enable debug log: bash scripts/hook/inject_hook_unix.sh --debug

Identifier values shown above are illustrative; each run generates a fresh set and persists them to ~/.cursor_ids.json.

Suggested mitigations (for the receiving team)

  • Move trial / abuse signals to server-derived attestation rather than client-reported telemetry fields that any user-space process can rewrite.
  • Treat storage.json as untrusted on read; verify against a server-side record bound to the account, not the device.
  • Detect main.js integrity drift at startup (signed hash check on packaged resources) and refuse to boot — or fall back to a server check — when modified.
  • Cross-check device IDs against multiple independent OS surfaces (TPM-backed where available) rather than a single registry/ioreg/machine-id source.
  • Flag accounts whose first-session telemetry rotates devDeviceId more frequently than physical hardware change rates would predict.

License

MIT — see LICENSE. This repository is shared with vendor security teams for review of the disclosed vector; please do not redistribute.

About

this is only for testing purposes and made to showcase the potential way of bypassing electron based apps to prevent similar attempts/methodologies in the future.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors