Microsoft Threat Intelligence
disclosed that version 2.4.6 of the
mistralai Python package on PyPI has been
compromised. According to the disclosure, attackers injected code into
mistralai/client/__init__.py that executes on import,
downloads a second-stage payload from
hxxps://83[.]142[.]209[.]194/transformers.pyz
to /tmp/transformers.pyz, and runs it on Linux. The
second-stage filename deliberately mimics the Hugging Face
Transformers library to blend into ML and developer environments.
The main payload is a credential stealer, but it also carries a
geofenced destructive branch with a 1-in-6 chance of executing
rm -rf / when the system appears to be in Israel
or Iran; the malware separately avoids executing in Russian-language
environments. PyPI's cached listing shows the legitimate 2.x line
ending at 2.0.1 (March 12, 2026); a jump to 2.4.6 is
itself an anomaly, consistent with quarantine. Cap the
version at mistralai < 2.4.6 (or pin exactly to
2.0.1) in every environment that may have pulled the
package since the malicious release, hunt for the IOCs on Linux
hosts, and rotate any credentials reachable from those hosts.
Sourcing, in three buckets.
Confirmed by PyPI: the cached PyPI version history for the
legitimate mistralai project shows a 2.x release line
ending at 2.0.1 on March 12, 2026, with no 2.4.x
releases visible. A version jump from 2.0.1 directly to 2.4.6
(skipping 2.1, 2.2, 2.3, and 2.4.0 through 2.4.5) is itself anomalous;
legitimate Mistral releases would not version-jump this way.
The non-visibility of 2.4.6 in the cached listing is consistent with
PyPI quarantine action but is not by itself confirmation, the
bulletin will be updated when PyPI's project status page or its
JSON API is reachable to confirm quarantine, list the 2.4.6 sdist
and wheel hashes, and document any project-page banner PyPI has
added.
Reported by Microsoft Threat Intelligence: the injection
point in mistralai/client/__init__.py, the second-stage
URL and drop path, the Linux execution profile, the persistence
filenames, the credential-stealer payload, the Russian-environment
exclusion, and the Israel/Iran 1-in-6 destructive branch.
Not yet independently verified by this bulletin: SHA-256
hashes for the 2.4.6 wheel and sdist; SHA-256 for the dropped
second-stage and persistence artifacts; whether any earlier or
later version is also malicious; how the package or maintainer
pipeline was compromised; current CISA KEV status. A Microsoft
Defender Experts or Security Blog writeup is expected and will
shift items from the third bucket into the second.
Scope: the documented second-stage and destructive
branch are Linux-only. Developers on Windows or macOS who installed
2.4.6 should still treat any Python process that ran
import mistralai as having executed attacker-controlled
code, but should not assume the credential stealer ran (no
Linux-specific drops would have executed) without evidence of
the second-stage retrieving successfully.
Cap the version at mistralai < 2.4.6
(or pin exactly to the last known-good release, 2.0.1)
across every environment, block egress to
83.142.209.194, hunt
/tmp/transformers.pyz and
pgsql-monitor.service on every Linux host that could
have run import mistralai since 2.4.6 was published,
and rotate the credentials those hosts had access to. If any host
geolocates to Israel or Iran, verify filesystem integrity before
reusing it.
Three reasons this gets CRITICAL framing rather than HIGH.
First, execution on import: any process that runs
import mistralai or from mistralai import ...
triggers the dropper, so simply listing 2.4.6 in a
requirements.txt and running tests, a notebook, or a
deploy step is enough to compromise the host. Second, the package
name is the official Mistral AI client, not a
typosquat; Python and ML developers who explicitly want the Mistral
client install mistralai by name, so the affected
population is exactly the audience that runs untrusted model code on
well-credentialed dev workstations and CI runners. Third, the
destructive branch is non-deterministic: even
operators outside the geofenced regions cannot rely on conditional
logic to predict who got wiped; if the geofence is loose or the IP
geolocation flips, the 1-in-6 dice roll fires.
transformers.pyz naming is intentional camouflage,
the legitimate Hugging Face Transformers library is distributed
as the transformers wheel and is never written to
/tmp in normal use, so any file at
/tmp/transformers.pyz should be treated as a hit.
The pgsql-monitor.service unit and
pgmonitor.py are believed to be the persistence layer
for the credential stealer; the bulletin will be updated with
SHA-256 hashes for these artifacts once a primary writeup
publishes them.
Action priority by environment
| Priority | Environment | Action |
|---|---|---|
| Drop-everything | Linux CI runners, dev workstations, ML training boxes that ran import mistralai against 2.4.6 |
Isolate, hunt for IOCs, treat as compromised on any positive IOC hit, rotate every secret the process had access to regardless. If the machine is in (or geolocates to) Israel or Iran, also verify filesystem integrity before reusing the host. |
| Drop-everything | Linux containers / images built since 2.4.6 was published | Container images that resolved mistralai without a pinned ceiling during build (or pinned to 2.4.6 specifically) are exposed to malicious code. Treat as compromised only after confirming execution via build / runtime logs (import-time output, dropped artifacts on the build host, egress to the C2). Rebuild from a pinned mistralai < 2.4.6 regardless, rotate any baked-in credentials, and redeploy. |
| Drop-everything | Internet-egress from any host that ran 2.4.6 | Block 83.142.209.194 outbound at perimeter and at host firewall. Search egress logs retroactively for any connection to that IP from any source; the connection alone is sufficient evidence the dropper executed. |
| Same-day | Windows / macOS dev hosts that installed 2.4.6 | The dropper code in __init__.py would have executed in the Python interpreter on import, but the documented second-stage and credential stealer are Linux-only. Treat as exposed, not as confirmed-compromised: uninstall and pin below 2.4.6; check for any suspicious child processes, files in temp directories, or outbound connections to the C2 IP from the import window; rotate credentials only if those checks turn up evidence of execution beyond the Python interpreter, or per local policy. |
| Same-day | Pip mirrors / internal package proxies (devpi, Artifactory, Nexus) | Verify that mistralai 2.4.6 is not pinned, cached, or required by any internal build manifest. Add a deny entry for the exact version while the incident is open. |
| This week | Environments that never installed mistralai at any version | No direct action. Note the broader pattern: official-package supply-chain compromise of an AI/ML SDK with destructive payload semantics, the next one will not be on the same package or registry. |
Priority assignment reflects this bulletin's framing, not an external CVSS score. PyPI supply-chain compromises do not receive CVSS in the normal vendor sense.
Am I affected?
Check pip and poetry environments
On each Linux host, virtualenv, container, and CI runner that may have installed the Mistral client, check the resolved version:
pip show mistralai 2>/dev/null | grep -E '^(Name|Version|Location):' # or, across all environments visible to pip: pip list --format=freeze 2>/dev/null | grep -i '^mistralai=='
For Poetry projects, check the lockfile rather than the live environment,
because a fresh resolution from pyproject.toml can mask a
previously-locked malicious version:
grep -A1 '^name = "mistralai"' poetry.lock | head -4 # or, for any project using pip-compile / pip-tools: grep -i '^mistralai==' requirements*.txt
Hunt for the second-stage and persistence on Linux
Even if pip no longer shows 2.4.6, the dropper may have executed at least once. Look for the dropped second-stage and the persistence unit:
ls -la /tmp/transformers.pyz 2>/dev/null find / -xdev -name 'transformers.pyz' 2>/dev/null find / -xdev -name 'pgmonitor.py' 2>/dev/null systemctl list-unit-files | grep -i 'pgsql-monitor' systemctl status pgsql-monitor.service 2>/dev/null # review recent shell history and journal for the IP grep -r '83\.142\.209\.194' /var/log /root/.bash_history /home/*/.bash_history 2>/dev/null journalctl --since '30 days ago' | grep -E '83\.142\.209\.194|transformers\.pyz|pgsql-monitor'
Verify outbound egress to the C2
The single most reliable indicator that the dropper executed on a host
is an outbound connection to 83.142.209.194. Query
whatever flow / DNS / proxy telemetry you have:
conntrack -L 2>/dev/null | grep '83\.142\.209\.194' # zeek conn.log, suricata eve.json, palo alto / fortigate flow exports, etc. # any source IP that connected to 83.142.209.194 in the affected window # should be treated as a confirmed dropper execution.
Response steps
-
Cap the version and unstick locked environments.
For urgent operator response, pin exactly to the last known-good
release:
pip install 'mistralai==2.0.1'. As a policy ceiling that survives a clean 2.4.7 release, usemistralai < 2.4.6ormistralai != 2.4.6inrequirements.txt,pyproject.toml, and any Poetry / pip-tools constraint files. Rebuild lockfiles from clean. If 2.4.6 is currently installed in a venv, runpip uninstall -y mistralai && pip install 'mistralai==2.0.1'. Do not assume a downgrade in place cleans the host; treat downgrade as remediation only for the package, not for the host. -
Block the C2 IP at the perimeter and on hosts.
Add
83.142.209.194as a deny in firewall, egress proxy, and host iptables / nftables rules. Block before, not after, you start the host-triage step, so any retry attempts during triage cannot succeed. -
Isolate any Linux host with a positive IOC hit.
A confirmed hit is any of:
/tmp/transformers.pyzpresent,pgsql-monitor.serviceregistered,pgmonitor.pyon disk, or an outbound flow to83.142.209.194in retained logs. Pull the host off production network paths before continuing. Snapshot state for forensics if your environment supports it. -
Rotate every credential reachable from an affected host.
Cloud provider API keys and IAM session tokens in process env or
instance metadata; Hugging Face tokens; OpenAI / Anthropic /
Mistral API keys; npm / PyPI / GitHub tokens; SSH private keys and
any authorized_keys agent-forwarded into the host; database
passwords in
.env,.netrc, or shell history; browser-resident session cookies on dev workstations. Assume the credential stealer had read access to everything the Python process and the user could read. -
Remove persistence and the second-stage.
On each affected Linux host, after isolation, disable and remove
the systemd unit and delete the dropped files:
systemctl stop pgsql-monitor.service 2>/dev/null systemctl disable pgsql-monitor.service 2>/dev/null rm -f /etc/systemd/system/pgsql-monitor.service \ /usr/lib/systemd/system/pgsql-monitor.service \ /tmp/transformers.pyz find / -xdev -name 'pgmonitor.py' -delete 2>/dev/null systemctl daemon-reloadFor hosts geolocating to Israel or Iran specifically, before treating the host as recoverable, verify filesystem integrity (root directory still populated, package manager database intact, critical services present). Therm -rf /branch may have fired and partially completed before the OS aborted it. - Rebuild rather than clean where feasible. For ephemeral CI runners, container images, and disposable dev VMs, destroy and rebuild from a known-good base. For long-lived workstations, weigh the cost of reimaging against the difficulty of being confident every persistence path is gone, the credential stealer's persistence beyond the systemd unit is not fully enumerated in the initial disclosure.
-
Search retroactively for evidence of dropper execution before
any of the above ran.
Look back as far as your egress and DNS logs allow for connections
to
83.142.209.194from any source. Each unique source IP is a host to add to the isolation list. If you have CI build logs, search them formistralai-2.4.6install lines. -
Add a deny rule for mistralai 2.4.6 in your internal package
proxy.
If you run devpi, Artifactory, Nexus, or a similar pull-through
proxy, configure an explicit deny for
mistralai==2.4.6and any version that PyPI later marks malicious. This prevents reinstallation when a developer's local pip cache or a stale lockfile attempts to re-pull during the incident window.
The broader pattern: this is the fifth named-package supply-chain
compromise this project has tracked in 2026 (Lightning, xinference,
Bitwarden CLI, Checkmarx KICS, and now mistralai), and the second
where the malicious payload targets ML / AI developer environments
specifically. The chosen camouflage filename
(transformers.pyz, mimicking Hugging Face Transformers)
is a signal that attackers are building per-ecosystem tradecraft for
AI/ML toolchains rather than treating them as generic Python
installations. Operators in this audience should expect more of the
same: official-name packages, on-import execution, AI-themed
second-stage filenames, and credential exfil tuned to API-key-rich
developer hosts.
Bucket reminder: items confirmed by PyPI are in the framing block
at the top; items reported by Microsoft Threat Intelligence are
in the lede, callout, and IOC block; items not yet independently
verified are listed here. Pending primary-source confirmation:
SHA-256 hashes for the 2.4.6 wheel and sdist (PyPI assigns these
to every distribution and will list them on the project's JSON API
once project-page status is reachable); SHA-256 for the dropped
second-stage transformers.pyz and the persistence
artifacts pgmonitor.py and
pgsql-monitor.service; whether any version other
than 2.4.6 was malicious; the entry point for the compromise
(maintainer-account takeover, build-pipeline compromise, or
other); current CISA KEV status. The bulletin will be updated
when the Microsoft Defender Experts or Security Blog writeup
publishes, and when PyPI's project page or JSON API is reachable
to confirm quarantine and list hashes.
Time-relative note: "still active" claims and "expected writeup" are anchored to May 12, 2026. If you are reading this materially later, check the primary source and PyPI's project page for current status before acting on the priority table as written.