<?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>Forem: Armor1</title>
    <description>The latest articles on Forem by Armor1 (@armor1ai).</description>
    <link>https://forem.com/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>Forem: Armor1</title>
      <link>https://forem.com/armor1ai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/armor1ai"/>
    <language>en</language>
    <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://forem.com/armor1ai/cve-2026-35030-cvss-94-how-litellms-jwt-cache-fails-and-how-to-rotate-credentials-after-the-4b4f</link>
      <guid>https://forem.com/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://forem.com/armor1ai/nomshub-how-to-check-if-your-mac-was-affected-by-the-cursor-sandbox-escape-2bif</link>
      <guid>https://forem.com/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>
