DeepJack: A cursor:// Deeplink Hid an MCP Install Command Off-Screen - One Click to Unsandboxed RCE
DeepJack, published by Adversa AI on July 15, 2026, turns a cursor:// deeplink into an attacker-controlled MCP server install on a developer's machine. Two tricks combine: nested, double-URL-encoded deeplinks that Cursor validates once but never recursively re-decodes, and whitespace padding that pushes the malicious trailing command off the right edge of the install dialog's single-line text box. The victim sees what looks like a pull-request link, clicks, confirms an install that reads as harmless, and gets unsandboxed code execution. Adversa reports Cursor confirmed the root cause internally on April 27, 2026 - roughly two months before publication - and that it remained reproducible in build 3.9.8. There is no CVE and no vendor advisory. This advisory covers the mechanism, why the confirm dialog was never a security control, and how to inventory and govern MCP installs across a fleet.
What happened
Cursor registers the cursor:// URL scheme, and among the actions it exposes is mcp/install - a convenience so a project or a docs page can offer one-click setup of an MCP server. The handler takes a url parameter. Adversa found that Cursor does not recursively decode or revalidate that parameter, so a deeplink can be nested inside another deeplink using double URL encoding. The outer link passes validation; the inner mcp/install URI rides through it untouched and reaches the install handler. In the researchers' demonstration the payload was embedded so that the victim appeared to be clicking an ordinary pull-request link.
Reaching the install handler still surfaces a confirmation dialog, which is where the second trick matters. The dialog renders the command to be installed in a single-line text box. Padding the arguments with whitespace pushes the real, malicious trailing command off the right edge of the visible area. The user reads a plausible install command, sees nothing amiss, and approves. Adversa characterises the outcome as one click and one confirmation to unsandboxed RCE; other coverage describes the same chain as a two-click developer-environment takeover. Either way the security decision was delegated to a text box that could not show the whole string.
An installed MCP server is not a sandboxed plugin. The client spawns it as a local child process with the developer's own permissions - no syscall filtering, no network policy, and access to whatever the shell environment carries. So the install is the whole exploit: once the server runs, it has the developer's file system, their tokens, their source, and their outbound network. That is why an install-dialog truncation bug reads as Critical rather than cosmetic.
The disclosure timeline is the part worth sitting with. Adversa reports the root cause was confirmed internally by Cursor on April 27, 2026, publication followed on July 15, 2026, and the issue was still reproducible in 3.9.8 at that point - with no CVE assigned and no vendor advisory to track. This is not the first Cursor issue in this family either: it sits alongside MCPoison, CurXecute, and the git-hooks sandbox escape. Treat the affected-version line as "through 3.9.8, status unconfirmed" and verify against your own build rather than assuming a silent fix landed.
| Detail | Value |
|---|---|
| Name | DeepJack |
| Identifier | No CVE assigned; no vendor advisory published |
| Product | Cursor IDE |
| Affected | Through build 3.9.8 (reproducible at publication) |
| Vector | Nested, double-URL-encoded cursor:// deeplink reaching the mcp/install handler |
| Why validation missed it | The url parameter is validated once and never recursively re-decoded |
| Why the dialog missed it | Single-line text box; whitespace padding pushes the trailing command off-screen |
| Impact | Attacker-controlled MCP server installed and run as a local child process with the developer's permissions - unsandboxed RCE |
| Interaction required | One click plus one confirmation (also described as a two-click chain) |
| Reported by | Adversa AI |
| Timeline | Root cause confirmed by Cursor internally Apr 27 2026; published Jul 15 2026; still reproducible in 3.9.8 |
Why this is an agentic-endpoint risk
The control that failed was a dialog. Not a policy engine, not a signature check, not an allowlist - a single-line text box that the user was expected to read. Install-time consent has quietly become the primary security boundary for the agent layer: MCP servers, extensions, skills, and hooks all arrive through a prompt that says *do you want this?* DeepJack shows what happens when that prompt can be made to display something other than what it will run. The user did consent. They consented to different text than the one that executed.
That makes this the same failure as PromptFiction in Claude Desktop, where the consent step was absent rather than misleading. Both are registered URL schemes - OS-level inbound channels from any web page, email, or chat into a local agent with a live session - and in both cases the exploit rides a legitimate, documented feature. There is no malicious binary for EDR to flag, no anomalous network request for a proxy to catch, and the resulting child process is a package manager fetching a package, which is the single most ordinary thing that happens on a developer machine.
So the durable question is not *is 3.9.8 patched*. It is which MCP servers are installed across your fleet, when each appeared, who approved it, and what it is allowed to do. MCP servers are one of the eight AI artifact types Anomity inventories per endpoint, and they get adopted exactly the way AI agents became the new shadow IT: one developer, one click, no record. Cisco's own framing is useful here - disclosure-to-weaponization has compressed to hours while enterprises still average 43 days to patch a critical vulnerability. For an issue with no CVE and no advisory, that patch clock never even starts.
How Anomity surfaces and governs it
First, inventory the servers, not just the IDE. Anomity's unprivileged Endpoint Sensor runs on Windows, macOS, and Linux and inventories MCP servers alongside AI agents, extensions, plugins, skills, secrets, hooks, and CLIs. Every server carries a first-seen timestamp and the endpoint it appeared on, so a server that installed itself via a deeplink shows up as a new artifact nobody requested - which is the detection DeepJack actually needs, because the install itself is the compromise. "Which endpoints gained an MCP server this week, and did anyone ask for it?" becomes one query.
Second, decide at the tool call. Install-time consent already failed by construction here, so the control has to sit after it. Where an agent exposes a hook - for example the PreToolUse event in Claude Code - Anomity evaluates each call against policy and returns allow, deny, or log before it runs. A freshly installed server that immediately reads ~/.aws/credentials, spawns a shell, or opens an outbound connection meets a boundary it cannot talk its way past, which is what runtime governance provides when the approval step itself is the thing being attacked.
Third, keep the record. Installs, version changes, and policy decisions land in a queryable 90-day audit trail, so you can answer which endpoints ran Cursor 3.9.8 or earlier, which MCP servers appeared during that window, and what those servers did - from a record rather than a guess. Anomity collects metadata only, with on-endpoint secret redaction, so the tokens a rogue server would reach for are never centralized. Findings route to SIEM, Slack, email, or Jira, the platform is SOC 2 Type II, and it complements EDR, DLP, network, and GRC tooling. See how it works.
You can't govern what you can't see.The Anomity principle
What to check across your fleet
- Inventory every endpoint running Cursor and record the build; treat anything at or below 3.9.8 as affected, and verify against the running build since there is no advisory to check and no CVE to track.
- Enumerate the MCP servers installed on every developer machine and reconcile each against something a human actually requested - an unexplained server is the primary indicator here, because installation is the exploit.
- Check when each server first appeared and correlate against link-click activity; a server that materialised without a corresponding ticket, PR, or setup task deserves investigation.
- Review what installed servers can reach: they run as local child processes with the developer's permissions, so treat each one as having the developer's files, tokens, source, and network egress.
- Rotate developer credentials reachable from any endpoint where an unexplained MCP server is found - cloud keys, npm and GitHub tokens, SSH keys, and anything in a shell profile.
- Treat every registered agent URL scheme as an inbound channel and review what each will do without recursive revalidation -
cursor://,claude://,claude-cli://,vscode://and equivalents. - Stop relying on the install dialog as a control. Move MCP servers to a reviewed set, per building an MCP server registry, and confirm tool calls are evaluated at a hook with allow/deny/log rather than trusted because someone once clicked Install.
- Review the wider Cursor configuration surface, which drifts independently of the IDE version, per Cursor's config surface and .cursorrules drift and auto-run limits.
DeepJack is a truncated text box escalating to code execution, and the uncomfortable part is that everything downstream of that box worked as designed: the deeplink was valid, the handler was legitimate, the user consented, and the server ran with exactly the permissions MCP servers get. When install-time consent is the boundary, anything that controls what the consent screen displays controls the machine. Verify your Cursor builds and reconcile your installed MCP servers against what a human actually asked for, then govern what those servers may do at the point of action. See the MCP Server Security guide for the full trust model, the sibling PromptFiction advisory for the same flaw class without a consent step, and securing AI coding agents and CLIs for the fleet-wide version. To see which endpoints carry MCP servers nobody requested and what runtime governance would deny, request early access.
Frequently asked questions
What is the DeepJack vulnerability in Cursor?
DeepJack, published by Adversa AI on July 15 2026, is a deeplink flaw in Cursor IDE that installs an attacker-controlled MCP server after one click and one confirmation. It combines two weaknesses. First, Cursor validates the url parameter of a cursor:// deeplink once but does not recursively decode or revalidate it, so an mcp/install URI can be nested inside another deeplink using double URL encoding and ride through validation - in the demonstration, disguised as an ordinary pull-request link. Second, the install confirmation dialog renders the command in a single-line text box, so padding the arguments with whitespace pushes the malicious trailing command off the right edge of the visible area. The user approves what looks like a harmless install and gets unsandboxed code execution. No CVE was assigned and no vendor advisory was published.
Which versions are affected, and has it been fixed?
Adversa reports the issue was still reproducible in Cursor build 3.9.8 at publication on July 15 2026, and that Cursor confirmed the root cause internally on April 27 2026 - roughly two months earlier. Because there is no CVE and no vendor advisory, there is no authoritative fixed-version to check against. Treat the affected line as through 3.9.8 with status unconfirmed, verify against the build actually running on your endpoints rather than assuming a silent fix shipped, and rely on inventory of installed MCP servers rather than version tracking as your primary control.
Why is installing an MCP server equivalent to code execution?
Because an MCP server is not a sandboxed plugin. The client spawns it as a local child process with the developer's own permissions - no capability restriction, no syscall filtering, no network policy - and over stdio it inherits environment variables from the shell. So a newly installed server has the developer's file system, their tokens and cloud credentials, their source code, and outbound network access from the moment it runs. That is why a dialog-truncation bug is rated Critical: the install is not a step toward the exploit, it is the exploit.
Why didn't the confirmation dialog stop this?
The dialog did exactly what it was built to do - it displayed the command and asked for approval. The problem is that it displayed it in a single-line text box with no wrapping, so a command padded with whitespace scrolls the dangerous part out of view. The user genuinely consented; they consented to different text than the text that executed. The general lesson is that install-time consent has become the main security boundary for the agent layer - MCP servers, extensions, skills and hooks all arrive through a do-you-want-this prompt - and any attack that controls what that prompt renders controls the machine. A control that depends on a human reading a truncated string is not a control.
How does DeepJack relate to PromptFiction and other deeplink attacks?
They are the same class against different products. Both abuse a registered custom URL scheme, which is an OS-level inbound channel letting any web page, email or chat message hand input to a local agent holding a live session - outside the browser's same-origin protections and invisible to a network proxy because the handoff is local. DeepJack in Cursor makes the consent step misleading; PromptFiction in Claude Desktop removed the consent step altogether, submitting a prompt from a claude:// link with no review at all. Envade in VS Code and a claude-cli:// deeplink issue in Claude Code, patched in 2.1.118, round out the pattern. Four named issues, four products, one root cause: nobody treats the install or prompt handoff as an untrusted input path.
What should we do if we find an MCP server nobody requested?
Treat it as a potential compromise of that endpoint rather than a misconfiguration. The server ran with the developer's permissions, so rotate the credentials it could reach - cloud keys, npm and GitHub tokens, SSH keys, and anything exported in a shell profile - and review the endpoint for follow-on activity such as outbound connections, new repositories, or unexpected publishes. Then close the gap that let it in: reconcile installed servers against a reviewed registry, and evaluate agent tool calls at a hook that can return allow, deny or log, so the next unrequested server meets a boundary at its first action instead of inheriting the machine at install time.




