[Security] Background subagent silently falls back to local machine execution when SSH remote connection degrades

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

When using Cursor Agent over SSH Remote and the SSH connection becomes degraded (shell commands returning empty output despite exit code 0), spawning a background subagent via the Task tool causes the subagent to execute on the local client machine instead of the remote host.

This happens silently — no error, no warning — and the subagent proceeds to read files, modify code, run git operations, and attempt pushes against the local filesystem.

What happened:

  • Parent agent was operating correctly on a remote Linux host via SSH (/home/user/work/repo on remote)
  • Shell commands started returning empty output (SSH degradation)
  • Parent agent spawned a generalPurpose background subagent with explicit remote path in the prompt
  • The subagent resolved its workspace to the local macOS client: /Users/user/.cursor/projects/empty-window/agent-transcripts/...
  • The subagent had full write permissions and was instructed to commit and push — it attempted these on the wrong machine
  • The subagent was searching through whole machine for local copy of repository triggering macos access alerts
  • The subagent found local copy with different branch and different unstaged changes - proceeded to overwrite it

Security impact: A subagent with full write/execute permissions operated on a completely different machine than intended, without user consent or any error indication. This is a trust boundary violation — the subagent could read sensitive local files, modify wrong repositories, or push to wrong remotes.

Steps to Reproduce

  1. Connect to a remote Linux host via Cursor SSH Remote extension
  2. Start an Agent session (e.g. Opus 4.6) with a multi-step task involving shell operations (gh CLI, git, file edits)
  3. Work through multiple tool calls until the SSH connection becomes unstable — observable as shell commands returning empty stdout despite exit code 0
  4. Have the agent spawn a background subagent (Task tool, generalPurpose type, run_in_background: true) with a prompt that explicitly references the remote workspace path (e.g., /home/user/work/repository)
  5. Observe the subagent scanning local machine (macOS) paths (/Users/user/.cursor/projects/empty-window/...) instead of the remote workspace
  6. The subagent proceeds with file read/write/git operations on the local machine

Note: The SSH degradation in step 3 may be timing-dependent. In my case it occurred after ~30+ tool calls in a long session with heavy gh CLI usage.

Expected Behavior

  1. If the SSH remote context cannot be propagated to the subagent, the Task tool should fail with an explicit error — not silently fall back to local execution
  2. A subagent should never gain write access to a different machine than the one the parent agent was operating on
  3. Shell tool should surface SSH connection failures explicitly (returning empty output with exit code 0 masks the real error and makes the parent agent unable to detect the problem)
  4. The user should be notified immediately if any agent/subagent execution context changes from remote to local

Screenshots / Screen Recordings

Operating System

macOS (local)
Linux (remote)

Version Information

Version: 3.3.30
VSCode Version: 1.105.1
Commit: 3dc559280adc5f931ade8e25c7b85393842acf30
Date: 2026-05-09T18:28:42.332Z
Layout: glass
Build Type: Stable
Release Track: Default
Electron: 39.8.1
Chromium: 142.0.7444.265
Node.js: 22.22.1
V8: 14.2.231.22-electron.0
OS: Darwin arm64 25.4.0

For AI issues: which model did you use?

Parent agent: Opus 4.6 (claude-opus-4-6)
Subagent: generalPurpose (default model, inherited from parent)

For AI issues: add Request ID with privacy disabled

Conversation ID: 24c44386-fd74-4501-a57b-094601d14121

(Request ID not available — privacy was not disabled at time of incident. The conversation transcript is available locally for Cursor team inspection if needed.)

Additional Information

Preceding symptoms (SSH degradation signals):

  • Multiple shell tool calls returned empty stdout with exit code 0
  • Affected commands: gh run view, gh run list, git log, ls, echo
  • This happened for several consecutive tool calls before the subagent was spawned

Subagent invocation details:

  • Tool: Task with subagent_type: "generalPurpose", run_in_background: true
  • Prompt explicitly contained info in format of: “Repository: /home/user/work/repo on branch branchname”
  • The subagent was looking for similar paths on local machine

Related existing forum reports (similar but less severe):

None of these describe the full scenario: a background subagent silently executing its entire tool chain with write permissions on the local machine.

Suggested mitigations:

  1. Subagent spawning must verify it inherits the same execution context (local vs SSH remote) as the parent
  2. If remote context cannot be established, Task tool must return an error
  3. Shell tool must not mask SSH failures as empty-output success
  4. Consider a hard workspace boundary check that blocks any agent from operating outside its configured root

Does this stop you from using Cursor

No - Cursor works, but with this issue

+1, hitting a related but distinct failure mode on the same Cursor build you reported on (3.3.30, commit 3dc559280adc5f931ade8e25c7b85393842acf30). Same local/remote architecture (macOS → Linux EC2 via Cursor Remote-SSH, Opus 4.5 parent agent).

In my case the subagent itself executes remotely correctly — the PARENT’s shell routing flips to local after the subagent returns.

Concrete sequence:

  1. Parent spawns a background subagent (“Launched. Report will be at…”)
  2. Subagent writes scratch/mr-reviews/<n>/charter-audit-v3.md and returns a summary
  3. I verified the report file is on the EC2, not on the local Mac (local has no scratch/mr-reviews/ tree at all — it would have had to be created from nothing)
  4. Parent receives summary, attempts a follow-up Shell call, reports “Having trouble accessing files”
  5. Asked parent for its current cwd — it returns /Users/<my-mac-username>/... (Mac path)
  6. One or two tool calls later, cwd flips back to /home/ubuntu/repos/<repo> and the agent itself reports “shell state was stale”

Differences from your repro:

  • No empty-stdout / exit-0 SSH-degradation precursor in my sessions
  • Subagent’s own execution was correct; the parent was the wrong-machine actor on follow-up

Security implication: Same trust-boundary class as your report. The parent agent has full read/write/exec permissions and silently operates on the wrong machine after the subagent returns. If asked to act on the audit findings (commit, push, modify files, run scripts), those operations would land on the local Mac instead of the EC2 — wrong-machine git ops, reads of sensitive local files, modifications to whatever local repo clones happen to exist. Exposure surface is equivalent to the subagent-fallback case you described; only the trigger differs.

Workaround: explicit working_directory=<remote absolute path> on every Shell call appears to pin routing. Quit + restart reliably re-anchors.

Possible underlying model (inferred from observed behavior — I don’t have visibility into Cursor’s internals): the pattern is consistent with the agent running structurally local. File reads/writes route through Remote-SSH; Shell tool calls and subagent orchestration default to local unless remote anchoring is explicitly maintained on each call. Under this read, the failure isn’t “the agent forgot where it is” — the agent is always-local, and remote anchoring has to be re-applied per call. Any code path that drops it (SSH degradation, subagent spawn, subagent return, prompt-driven shell calls without explicit cwd) produces silent local execution. That would explain why the workaround is per-call working_directory, why the failure can flip mid-session, and why your repro (subagent fallback under degradation) and mine (parent state corruption after subagent return) produce the same outcome through different triggers. If this model is accurate, the structural fix is enforcing remote anchoring on every shell-routed operation — or raising explicit errors when it can’t be applied — rather than propagating context on subagent spawn alone.

Recurring since the forced migration off ms-vscode-remote.remote-ssh a couple weeks ago.

Version: 3.3.30 (Universal)
VSCode Version: 1.105.1
Commit: 3dc559280adc5f931ade8e25c7b85393842acf30
Local: macOS 15 Sequoia (Darwin 24.6.0, arm64)
Remote: Ubuntu 24.04.4 LTS (kernel 6.17.0-1013-aws), EC2
Parent agent model: Opus 4.5

Conversation IDs available on request.

This is a known bug that our team is actively investigating and working to fix. The root cause has been identified. A fix is in progress that pins the workspace context to an immutable identity per chat session, which should prevent the local fallback entirely.

Workaround until the fix ships: On every Shell call, explicitly set working_directory to the remote absolute path (e.g., /home/user/work/repo). This forces remote routing on each call. If the session becomes unstable (empty stdout with exit code 0), quitting and restarting Cursor reliably re-anchors the remote context.

@gus-at-fsp — thanks for the additional data point. Your variant (parent shell context flipping after subagent returns) is part of the same underlying issue. The same workaround applies.

Let me know if you run into anything else.