<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Armor1</title>
    <description>The latest articles on DEV Community by Armor1 (@armor1ai).</description>
    <link>https://dev.to/armor1ai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3872517%2F7c87f9cb-f324-4762-8d2b-3f00c4cb97f0.png</url>
      <title>DEV Community: Armor1</title>
      <link>https://dev.to/armor1ai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/armor1ai"/>
    <language>en</language>
    <item>
      <title>How to Check Your MCP Server for CVE-2026-5603's Vulnerability Pattern (And Why shellQuote Isn't Enough)</title>
      <dc:creator>Armor1</dc:creator>
      <pubDate>Wed, 22 Apr 2026 00:08:34 +0000</pubDate>
      <link>https://dev.to/armor1ai/how-to-check-your-mcp-server-for-cve-2026-5603s-vulnerability-pattern-and-why-shellquote-isnt-gdn</link>
      <guid>https://dev.to/armor1ai/how-to-check-your-mcp-server-for-cve-2026-5603s-vulnerability-pattern-and-why-shellquote-isnt-gdn</guid>
      <description>&lt;p&gt;CVE-2026-5603 is a Critical command injection in &lt;code&gt;@elgentos/magento2-dev-mcp&lt;/code&gt;, but the vulnerability pattern it represents shows up in community MCP servers regularly. This post explains what the vulnerability is, why the sanitizer fails on Windows, how to check your own MCP server code for the same issue, and what the correct fix looks like.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Is CVE-2026-5603?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@elgentos/magento2-dev-mcp&lt;/code&gt; is an NPM package that exposes Magento 2 development operations as MCP tools: database queries, cache management, module operations, configuration commands. AI coding assistants can call these tools on behalf of developers.&lt;/p&gt;

&lt;p&gt;The vulnerability: 16 of these tools pass user-supplied parameters into shell commands. A single-quote sanitizer is applied before insertion, but it fails to protect Windows deployments. The result: an attacker who can manipulate an AI agent into calling one of these tools with crafted parameters can execute arbitrary commands on the machine running the server.&lt;/p&gt;

&lt;p&gt;Affected versions: 1.0.2 and earlier. Patched in PR #5.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why shellQuote Fails on Windows&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;shellQuote&lt;/code&gt; uses single-quote escaping designed for Bourne-compatible shells. In &lt;code&gt;bash&lt;/code&gt; and &lt;code&gt;sh&lt;/code&gt;, everything between single quotes is treated as a literal string. Special characters have no effect.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cmd.exe&lt;/code&gt; does not use single quotes as quoting characters. They pass through the command line unchanged. Metacharacters like &lt;code&gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;&lt;/code&gt; retain their command-separator semantics regardless of surrounding single quotes.&lt;/p&gt;

&lt;p&gt;The server documentation confirms Windows as a supported deployment environment. Magento 2 developers running Docker-based local environments (Warden, DDEV) on Windows are the target population.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Audit Your Own MCP Server&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you maintain or use a community MCP server that wraps shell operations, check for this pattern:&lt;/p&gt;

&lt;p&gt;Identify any shell execution calls in the server code. For each one, trace where the values fed into the command come from. If any value originates from MCP tool parameters (what the AI agent sends), check whether any sanitization is applied and whether that sanitizer covers all deployment platforms, including Windows.&lt;/p&gt;

&lt;p&gt;String-escaping libraries designed for Unix shells typically do not protect against Windows &lt;code&gt;cmd.exe&lt;/code&gt;. If a user on Windows deploys your server, escaping that worked in your Linux test environment may be silently ineffective on theirs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix pattern&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The correct approach uses &lt;code&gt;execFile&lt;/code&gt; (Node.js) or equivalent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;execFile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;promisify&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;util&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;execFileAsync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;promisify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;execFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// args is an array, not a concatenated string&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt;
&lt;span class="nf"&gt;execFileAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;magerun2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userQuery&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works safely on both Linux and Windows. No sanitizer needed because no shell interprets the arguments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Armor1 Detects This&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Armor1's MCP server source code scanning performs taint flow analysis: it traces user input from MCP tool parameters through the call graph to execution sinks, and checks whether any sanitizers along the path adequately handle the target environment.&lt;/p&gt;

&lt;p&gt;When run against magento2-dev-mcp, the scan identified both vulnerable code paths and flagged the sanitizer as inadequate for Windows &lt;code&gt;cmd.exe&lt;/code&gt;. The findings were classified as high-severity code execution risks. The scan doesn't depend on CVE databases: it reads the code and evaluates what the code does.&lt;/p&gt;

&lt;p&gt;This is the difference between reactive and proactive scanning. CVE-based dependency scanning tells you a vulnerability exists after a researcher files an advisory and the databases index it (typically 24-72 hours after disclosure). Source code analysis tells you the pattern exists from the moment it appears in the codebase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two things you can do right now, both free:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. See the risk of any MCP server in your environment&lt;/strong&gt; &lt;a href="https://mcp.armor1.ai/mcp-directory/magento-2-mcp-server-efe4d78?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=cve-2026-5603&amp;amp;utm_content=devto-post" rel="noopener noreferrer"&gt;in Armor1's public catalog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Cover your entire agentic stack&lt;/strong&gt; (every app, MCP, tool, skill, and plugin) by signing up free at &lt;a href="https://app.armor1.ai?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=cve-2026-5603&amp;amp;utm_content=devto-post" rel="noopener noreferrer"&gt;app.armor1.ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remediation Summary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Package Affected&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;@elgentos/magento2-dev-mcp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Versions&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;= 1.0.2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Patched (PR #5)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Action&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;npm update @elgentos/magento2-dev-mcp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Verify your version: &lt;code&gt;npm list @elgentos/magento2-dev-mcp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For your own MCP servers: replace string-based shell command construction with &lt;code&gt;execFile(command, [userInput])&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>security</category>
      <category>ai</category>
      <category>vulnerabilities</category>
    </item>
    <item>
      <title>CVE-2026-35030 (CVSS 9.4): How LiteLLM's JWT Cache Fails and How to Rotate Credentials After the Supply Chain Attack</title>
      <dc:creator>Armor1</dc:creator>
      <pubDate>Thu, 16 Apr 2026 01:04:19 +0000</pubDate>
      <link>https://dev.to/armor1ai/cve-2026-35030-cvss-94-how-litellms-jwt-cache-fails-and-how-to-rotate-credentials-after-the-4b4f</link>
      <guid>https://dev.to/armor1ai/cve-2026-35030-cvss-94-how-litellms-jwt-cache-fails-and-how-to-rotate-credentials-after-the-4b4f</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two critical CVEs in LiteLLM landed this week. CVE-2026-35030 is CVSS 9.4. CVE-2026-35029, CVSS 8.7, chains into remote code execution on the proxy. Both are patched in 1.83.0. Running alongside them: the LiteLLM supply chain attack that has been active since mid-March claimed its first named victim, Mercor, with 4 TB of data exfiltrated and 33,185 unique secrets compromised.&lt;/p&gt;

&lt;p&gt;This covers the mechanics of both CVEs, how to verify your exposure, and a credential rotation checklist if you installed the compromised versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CVE-2026-35030: The JWT Cache Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;LiteLLM caches OIDC userinfo to avoid querying the identity provider on every request. The cache key is the first 20 characters of the JWT token.&lt;/p&gt;

&lt;p&gt;JWT tokens from the same OIDC provider share algorithm metadata in the header, which means their base64 representations often start with the same characters. Two tokens from the same provider frequently share the same first 20 characters and therefore the same cache key. An authenticated low-privilege user can obtain a token from the same identity provider and have their requests served as a cached high-privilege user. No credential theft needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conditions:&lt;/strong&gt; Requires &lt;code&gt;enable_jwt_auth:&lt;/code&gt;true. Not enabled by default. The fix in 1.83.0 uses a full token hash as the cache key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CVE-2026-35029: The Config Endpoint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/config/update&lt;/code&gt; endpoint manages proxy settings, environment variable overrides, and pass-through handler registration. Handlers are Python callables the proxy executes during request processing.&lt;/p&gt;

&lt;p&gt;The endpoint was documented as admin-only. Authorization was not enforced. Any authenticated user could call it.&lt;/p&gt;

&lt;p&gt;The full attack chain combining both CVEs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use CVE-2026-35030 to impersonate an admin via cache collision&lt;/li&gt;
&lt;li&gt;Call /config/update as that admin to register a malicious handler&lt;/li&gt;
&lt;li&gt;The handler executes arbitrary Python on the LiteLLM proxy&lt;/li&gt;
&lt;li&gt;Read credentials, move laterally&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both CVEs are fixed in 1.83.0.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check and Patch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip show litellm&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If below 1.83.0:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install --upgrade litellm&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you cannot upgrade immediately: disable &lt;code&gt;enable_jwt_auth&lt;/code&gt; and restrict &lt;code&gt;/config/update&lt;/code&gt; to trusted network segments only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Supply Chain Attack: 1.82.7 and 1.82.8&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Separate from the CVEs, but overlapping the same window. TeamPCP published trojanized versions 1.82.7 and 1.82.8 to PyPI in mid-March. The infostealer targeted credential storage specific to AI dev environments: &lt;code&gt;.env&lt;/code&gt; files, &lt;code&gt;~/.aws/credentials&lt;/code&gt;, shell profiles, terminal history, IDE settings, and agent memory files.&lt;/p&gt;

&lt;p&gt;Scope as of April 6: 6,943 compromised developer machines, 33,185 unique secrets extracted, 3,760 still valid. 59% CI/CD runners. Mercor confirmed as the first named victim: 4 TB including source code, databases, cloud storage, and verification workflows.&lt;/p&gt;

&lt;p&gt;LiteLLM is a dependency for 1,705 PyPI packages including dspy (5M monthly downloads), opik (3M), and crawl4ai (1.4M). A developer who installed any of these in a fresh environment during March may have pulled the trojanized code indirectly.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip show litellm | grep Version&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you see 1.82.7 or 1.82.8, proceed to credential rotation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Credential Rotation Checklist&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud credentials:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AWS: create a new access key, delete the old one, review CloudTrail for unusual API calls&lt;/li&gt;
&lt;li&gt;GCP: rotate service account keys, check audit logs&lt;/li&gt;
&lt;li&gt;Azure: rotate Key Vault secrets, check activity logs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;API keys and shell history:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check every &lt;code&gt;.env&lt;/code&gt; file in repositories the machine accessed. Rotate anything there.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cat ~/.bash_history&lt;/code&gt; and cat &lt;code&gt;~/.zsh_history&lt;/code&gt;. Any key in either file should be considered compromised.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;SSH keys:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;ssh-keygen -t ed25519 -C "new-key"&lt;/code&gt;, remove the old public key from &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; on all servers, update in GitHub/GitLab.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;CI/CD:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rotate all secrets in your CI/CD system.&lt;/li&gt;
&lt;li&gt;Audit pipeline execution history for March. Look for unusual outbound network calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;How Armor1 Catches This&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the kind of vulnerability Armor1's dependency scanner catches automatically. For MCP servers listing LiteLLM as a dependency, the dependency risk scan flags CVE-2026-35030 (CVSS 9.4) and CVE-2026-35029 (CVSS 8.7) for any server running litellm &amp;lt; 1.83.0.&lt;/p&gt;

&lt;p&gt;Run a scan on your MCP servers: &lt;a href="https://dub.sh/ltQxgD8" rel="noopener noreferrer"&gt;https://dub.sh/ltQxgD8&lt;/a&gt;, free, no credit card.&lt;/p&gt;

</description>
      <category>security</category>
      <category>python</category>
      <category>ai</category>
      <category>vulnerabilities</category>
    </item>
    <item>
      <title>NomShub: How to Check If Your Mac Was Affected by the Cursor Sandbox Escape</title>
      <dc:creator>Armor1</dc:creator>
      <pubDate>Fri, 10 Apr 2026 22:09:51 +0000</pubDate>
      <link>https://dev.to/armor1ai/nomshub-how-to-check-if-your-mac-was-affected-by-the-cursor-sandbox-escape-2bif</link>
      <guid>https://dev.to/armor1ai/nomshub-how-to-check-if-your-mac-was-affected-by-the-cursor-sandbox-escape-2bif</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In January 2026, Straiker AI disclosed a three-stage attack chain against Cursor, the AI coding editor, on macOS. They named it NomShub. Cursor patched it in version 3.0 on April 2, 2026.&lt;/p&gt;

&lt;p&gt;If you use Cursor on macOS and worked with any external or untrusted repositories before that date, there are specific things on your machine to check. This article walks through the attack mechanism, how to look for indicators of compromise, what to do if you find them, and what the fix in Cursor 3.0 actually changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How the Attack Works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NomShub chains three distinct stages. Each stage depends on the previous one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 1: Indirect Prompt Injection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cursor reads repository content as AI context. README files, configuration files, code comments, documentation. This is by design: the AI needs to understand the project to help with it.&lt;/p&gt;

&lt;p&gt;An attacker embeds natural language instructions in any of these files. Not as executable code. As text, the same way a developer would write a comment. When you open the repository and ask the AI anything, the agent processes those instructions as part of its context and follows them.&lt;/p&gt;

&lt;p&gt;This is indirect prompt injection. The payload is in content the agent reads as part of its job, not in anything the user typed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 2: Sandbox Escape via Shell Builtins&lt;/strong&gt;&lt;br&gt;
Cursor implements a filter called &lt;code&gt;shouldBlockShellCommand&lt;/code&gt; to prevent the AI agent from running dangerous commands outside the intended workspace. The filter blocks patterns it recognizes as dangerous.&lt;/p&gt;

&lt;p&gt;It does not block shell builtins: &lt;code&gt;export, cd, source, eval.&lt;/code&gt; These are built into the shell interpreter itself, not commands the filter tracks.&lt;/p&gt;

&lt;p&gt;The NomShub attack chains builtins to achieve what the filter is designed to prevent:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;export CWD=~ &amp;amp;&amp;amp; echo $CWD &amp;amp;&amp;amp; cd $CWD &amp;amp;&amp;amp; echo '/tmp/run.sh' &amp;gt; .zshenv&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Each component of this passes the filter individually. Together, they navigate from the project directory to the home directory and write a line into &lt;code&gt;~/.zshenv.&lt;/code&gt; That file is a shell startup script: every terminal session that opens afterward executes &lt;code&gt;/tmp/run.sh.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 3: Persistent C2 via cursor-tunnel&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cursor ships with cursor-tunnel, a binary used for remote development via Microsoft Dev Tunnels. It is Apple-signed and notarized. macOS trusts it. Endpoint security tools trust it. Its traffic goes to Microsoft's Azure infrastructure over HTTPS on port 443.&lt;/p&gt;

&lt;p&gt;The injected instructions tell Cursor to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Kill any existing tunnel sessions&lt;/li&gt;
&lt;li&gt;Clear cached GitHub credentials&lt;/li&gt;
&lt;li&gt;Start a new tunnel session&lt;/li&gt;
&lt;li&gt;Print the GitHub device authorization code to the terminal&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cursor does all of this. The authorization code appears in terminal output. The attacker's payload reads it from the output and sends it to attacker-controlled infrastructure. The attacker enters the code into GitHub's OAuth device flow, registers the tunnel under their account, and gains authenticated shell access to your machine via the &lt;code&gt;spawn&lt;/code&gt; RPC method.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;.zshenv&lt;/code&gt; entry reruns this sequence automatically if the connection drops. The access survives reboots. To anything monitoring your network traffic, it looks like normal Cursor remote development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who Is Affected&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cursor users on macOS, running versions prior to 3.0, who opened a repository containing the NomShub payload.&lt;/p&gt;

&lt;p&gt;This is macOS-specific. The attack uses cursor-tunnel and shell startup behavior that does not apply in the same way on Windows.&lt;/p&gt;

&lt;p&gt;Repositories that could contain the payload include: public GitHub repositories crafted by an attacker, pull requests from external contributors, and dependency repositories that an AI agent reads as context while working on a project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Check Your Machine&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run these checks now if you were on a Cursor version earlier than 3.0 on macOS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check 1: ~/.zshenv&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;cat ~/.zshenv&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you see any entries that reference &lt;code&gt;/tmp/&lt;/code&gt; paths, shell scripts you don't recognize, or lines you didn't write, treat that as a potential indicator of compromise. Document what you find before removing anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check 2: GitHub Device Authorizations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;github.com/settings/connections.&lt;/code&gt; Look for any Dev Tunnel entries you didn't set up yourself. If you see an unrecognized tunnel registration, revoke it immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check 3: Running Processes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ps aux | grep cursor-tunnel&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If cursor-tunnel is running and you haven't intentionally started a remote development session, investigate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check 4: Shell History&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cat ~/.zsh_history | grep .zshenv&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Look for any commands that wrote to &lt;code&gt;.zshenv&lt;/code&gt; during your Cursor sessions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to Do If You Find Something&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If any of the above checks returns unexpected results, treat the machine as potentially compromised.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove the suspicious &lt;code&gt;.zshenv&lt;/code&gt; entries. Open the file in a text editor and delete the lines you don't recognize.&lt;/li&gt;
&lt;li&gt;Revoke all GitHub device authorizations under Settings &amp;gt; Connections.&lt;/li&gt;
&lt;li&gt;Rotate credentials stored in locations the Cursor process could access: environment variables, any &lt;code&gt;.env&lt;/code&gt; files in projects you worked on during the affected period, SSH keys, and cloud credentials if Cursor had access to terminal sessions where those were active.&lt;/li&gt;
&lt;li&gt;Check for processes running from &lt;code&gt;/tmp/&lt;/code&gt; paths and terminate them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you cannot account for the source of a &lt;code&gt;.zshenv&lt;/code&gt;entry, rotate the credentials accessible from that machine before relying on it for sensitive work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Cursor 3.0 Changed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The patch in Cursor 3.0 strengthens &lt;code&gt;shouldBlockShellCommand&lt;/code&gt; to address the builtin chaining gap. The specific &lt;code&gt;export + cd + source + eval&lt;/code&gt; combination that NomShub uses no longer passes the filter.&lt;/p&gt;

&lt;p&gt;Cursor has not published a detailed changelog for the security fix as of this writing. The Straiker AI disclosure was coordinated, and the patch was in the April 2 release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why This Problem Is Bigger Than the Patch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The NomShub fix closes a specific sandbox gap in Cursor 3.0. The structural problem it documents is not closed anywhere.&lt;/p&gt;

&lt;p&gt;AI coding tools read repository content as instructions. They run commands autonomously. They ship with legitimate remote access binaries used for real product features. Every repository that an AI agent reads as context is a potential attack surface.&lt;/p&gt;

&lt;p&gt;Palo Alto's Unit 42 documented Chinese APT Stately Taurus using VS Code's remote tunnel feature for persistent access against Southeast Asian government targets in September 2024. NomShub demonstrates that the technique does not require the attacker to compromise the machine first. It can be delivered through natural language in a file the agent reads as part of doing its job.&lt;/p&gt;

&lt;p&gt;The broader practice this points to: treat repository content as potentially untrusted input, the same way you treat user input in applications you build.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Armor1 Prevents This&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Armor1 enforces local runtime policies via hooks inside Cursor, positioned directly in the execution path. This is where NomShub's kill chain is stopped.&lt;/p&gt;

&lt;p&gt;Shell execution hooks evaluate command chains before they run. The &lt;code&gt;export+cd+eval&lt;/code&gt; sequence NomShub uses to escape the workspace and write to &lt;code&gt;~/.zshenv&lt;/code&gt; is blocked at the hook layer before the shell interpreter sees it. File access policies prevent writes to sensitive system paths, so even if a command chain reaches that stage, the &lt;code&gt;~/.zshenv&lt;/code&gt; modification is denied.&lt;/p&gt;

&lt;p&gt;These hooks enforce independently of Cursor's native &lt;code&gt;shouldBlockShellCommand&lt;/code&gt; filter, which is what NomShub bypassed. The hook layer sits inside the execution path and applies regardless of whether execution is inside or outside the sandbox boundary.&lt;/p&gt;

&lt;p&gt;Armor1's AI coding client catalog covers 30+ tools across 16 security categories including Sandbox Isolation, Filesystem Isolation, Script Hooks, and Network Egress, giving teams a governance baseline alongside the runtime enforcement layer.&lt;br&gt;
For teams managing AI coding client security: &lt;a href="https://tinyurl.com/Armor1AIMCP3" rel="noopener noreferrer"&gt;https://tinyurl.com/Armor1AIMCP3&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>agents</category>
      <category>appsec</category>
      <category>cursor</category>
    </item>
  </channel>
</rss>
