Sponsored by

TL;DR: MCP is the standard that lets an AI assistant call tools someone else runs: read a file, query a database, run a shell command. A Linux botnet called N4D now speaks MCP. It finds servers that answer from the internet, asks each one for its list of tools, picks one that runs commands, and runs something. There's no bug in any of this and no patch to install. If the server is reachable and asks for no password, the attack is the protocol doing its job. Also inside: why hardly anyone can list the MCP servers running in their own company, and three Rust packages that ran malware during cargo build.

What's new this week is proof. Datadog watched the current version connect to an MCP server, ask what tools it had, pick the one that runs commands, and call it. The quieter half of the problem sits on our side: most of us couldn't list the MCP servers running inside our own company, or say what those servers are allowed to do.

Attack of the Week: the botnet reads your tool list

Datadog didn't find this first. German Fernandez wrote N4D up back in June: a toolkit built to attack MCP servers, eight interchangeable modules, more than 30 aimed at specific services, and a clear focus on AI infrastructure. What Datadog added last week is a newer build of the malware, the servers now running it, the exact files it drops, and "direct runtime evidence that the current agent enumerates MCP tools, invokes a command-execution tool, and reports the result to its controller."

One scanner works on all of them. Every MCP server does something different. Every one of them answers the same handful of requests. That's the whole advantage, and Mackie says it plainly: "Instead of needing a distinct exploit for every MCP implementation, its scanner initializes a session, requests tools/list, classifies the returned tools, and invokes anything that looks dangerous (most notably execute_command) through tools/call."

There's a limit on that. Datadog saw both the old scanner and the current agent "negotiate protocol version 2024-11-05", which means N4D is hunting servers that still accept that older version.

What Datadog saw. They pointed the malware at a decoy server of their own, one that offers a single fake execute_command tool and never runs anything it's handed. The malware "completed initialize → tools/list → tools/call, selected execute_command, attempted id, and exfiltrated the structured result." Three ordinary requests and one shell command. Nothing real was broken to get that recording.

No exploit needed. Mackie: "An unauthenticated server that intentionally exposes a command execution tool doesn't need a memory corruption bug or a CVE to be compromised; the dangerous capability is already there, and N4D supplies automated discovery and abuse." We built the tool. We advertised it. The scanner just asked.

Once a command runs, it digs in. It writes a cron job to /etc/cron.d/.sys-health and a startup script to /etc/profile.d/.sys_alias.sh, installs a service called sys-resource.service, and adds its own key to /root/.ssh/authorized_keys.

It also hides in plain sight, naming its processes kworker* so they read as kernel threads, and running them out of /dev/shm, /tmp or /var/tmp. Before reaching for a cleanup script, note what Datadog says to rotate: "cloud credentials, SSH keys, database credentials, API tokens, and any secrets available to the MCP process or stored on the host."

One number to read carefully. Datadog's test run made 22,831 connection attempts to 742 addresses. That came from a test rig built to say yes to everything, and Datadog says so plainly: "The request totals are not campaign scan rates." The figure proves the malware really works this way. It says nothing about how much of the internet is being hit.

Ship This Week. Find every MCP server we run that answers on anything other than localhost. Datadog's fix, short version: "require authentication, bind local-only services to loopback, and put remote access behind an authenticated proxy." Then cut the tool list back. Drop anything that runs commands, reads any file, or queries a whole database when the server has no need for it. Where a command tool genuinely has to exist, Datadog asks for per-tool permission plus a strict allowlist, running inside "a short-lived, unprivileged sandbox with a read-only root filesystem." And if one of ours turns out to have been reachable, rotate whatever that process could touch before closing the ticket.

Rule of the Week

Names change, so alert on behavior. The older N4D scanner calls itself n4d-vps. The current one just calls itself n. Datadog's advice on that second one is to "treat n as an IOC only with other N4D behavior," because n is a single letter and will match noise on its own. The X-Mesh-Auth and X-Operator-Key headers belong to the malware's own control channel, so they're worth a separate rule and won't show up in MCP logs at all. Use all of it for a quick win this week, then build something that survives the attacker renaming things.

On every MCP server we run, record who called and what they asked for. Then alert on three patterns:

  • someone calling a tool that runs commands, when they're not on our list of approved callers

  • a caller that connects, asks for the tool list, and never calls anything, which is somebody taking inventory

  • any request for the tool list from outside our own network

Do this week. Pick one MCP server and check whether it writes down who called and which tool they used. If it records neither, that's the finding.

Defender's Corner

Datadog says to inventory the tools we hand out. Elastic went and answered that question from the inside, across more than 1,100 machines and nearly 900 people, logging over 13 million tool calls. They found more than 300 different MCP servers in use. 86% of them were used by only one or two people, which is a good description of software that isn't being tracked.

The collector is 280 lines of plain bash. Cursor can run it at 13 points in the agent's loop: before a shell command, before a file read, before an MCP call. Each time, Cursor hands it a description of what's about to happen. The script writes that down and Elastic Agent ships it off. Ready-made queries come with it: who read a credentials file, who piped curl straight into a shell, and which MCP servers are in use across the fleet.

Van der Meulen is honest about the gaps. Anyone with admin rights on their own laptop can delete the config. Hooks pushed from the console only reach the company tenant, so on those machines a personal Cursor login stays invisible. And it only ever sees actions: "We see tool calls, and we do not see the prompt or the model's reasoning, so intent stays out of frame."

This only covers our own machines. It won't find a server we've left open to the internet. What it does give us is a real list of which MCP servers our developers use, which is the half we can start on today.

Agent Bench: inventory your own MCP tool surface

Datadog's advice is to know what we're handing out. That isn't something anyone can answer from memory, because the answer is scattered across config files that have never been collected in one place.

Point a coding agent at every file where an MCP server gets set up: .mcp.json, .cursor/mcp.json, .codex/config.toml, Claude Code settings, plus docker-compose.yml and any Kubernetes manifests that start one. Ask it for four things:

  1. Every server we run, how it's connected, and what address it listens on, with the file and line for each.

  2. For each server, the tools it offers, marked by what they can do: run commands, read any file, query a database.

  3. Which servers are handed credentials, and what those credentials open.

  4. Any server reachable from outside its own machine, and whether anything checks who's calling.

What you get out of it: one table you can hand to someone else, every row pointing at the file and line it came from.

Plan for it being wrong in one specific way. Config files say what was intended; the running server is the one that decides. An agent reading YAML will list tools the live server doesn't offer, and miss any added while it runs. Connect and ask the server yourself before you call the list finished.

Try it this week: run question 4 and skip the rest. A server listening on 0.0.0.0 with a command tool on it is the whole finding.

Also on the Radar

[email protected], [email protected] and [email protected] were published from a maintainer account whose "computer or credentials are likely compromised," in the words of Rust's security team. The packages themselves look clean. Each one quietly added a dependency called proc-macro1, one character off the real proc-macro2, and that package carries the malware. Wiz: "Because Cargo executes build scripts at compile time, building a project that depends on proc-macro1 is sufficient to trigger the payload." You never have to run the program. Compiling it is enough.

Wiz points out the detail worth copying into your own reviews: proc-macro1 was the first dependency arrayref had taken on in ten years.

The bad versions were up for 86, 90 and 107 minutes, per Manish Goregaokar's writeup for the Rust security team. Short windows sound reassuring. They shouldn't here, because the attacker deleted the good versions to push everyone forward onto the bad ones. Wiz's warning is to stop treating a withdrawn version as a reason to upgrade: "this attack used yanking to drive upgrades." Several stable releases of a ten-year-old package disappearing at once is worth a look before you upgrade.

Wiz also says it finds arrayref in "over 35% of all environments" it looks at, and in three quarters of the ones running Rust, so this is worth the search. Check Cargo.lock across every repo for those three versions and for the attacker's other packages: proc-macro1, proc-macro-en, aovine, arone, aronenao and tinymember. Then check ~/.cargo/registry/cache on developer machines. Wiz says any machine that built one "must be treated as compromised." Rotate every credential, token and key it could reach, CI secrets and signing keys included. Cargo has no way to skip build scripts the way npm's --ignore-scripts does, and sandboxing them has been an open request since 2018.

Wiz says the servers behind this overlap with campaigns Microsoft and Mandiant have tied to North Korea, and is careful to call that overlap rather than proof. Same here.

N4D never found a bug in anyone's MCP server. It asked what tools were available, then used one. Go ask our own servers the same question before it does.

Until next Tuesday,
R.K.

Pass the Kubernetes exam on your first attempt.

RBAC. Networking. Storage. KodeKloud breaks these complex Kubernetes concepts down into hands-on practice, until you are ready to ace your exam.

Provision live clusters, drain nodes, debug failing pods, fix networking, set up storage. Every concept is explained in plain language before you type a command.

The curriculum is built backwards from the exam objectives and the work you will do on the job. Nothing extra. The scenarios you practice are the ones the exams test, and the ones you hit in production.

Challenges, hands-on labs, and crash courses teach beginners to think like a Kubernetes engineer from day one. Advanced labs go deeper into security, scaling, and complex troubleshooting. Every lab runs on real infrastructure with automated validation.

You're not memorizing answers. You're solving real Kubernetes problems. Starting from zero or sharpening what you have, this is certification prep that sticks.