Safeguard
Incident Analysis

ctx and colourama PyPI typosquat malware incident

The ctx and colourama PyPI typosquatting malware incident shows how account takeover and name-squatting delivered credential-stealing code to devs.

Nayan Dey
Security Researcher
7 min read

May 22, 2022 — PyPI Security Desk. A security researcher's routine dependency audit turned up something that shouldn't have been there: a version bump on a six-year-old, largely dormant Python utility package called ctx, quietly pushed with code that read a developer's environment variables and mailed them off to a Heroku app. Within hours, a second, related package — colourama, a near-perfect typo of the wildly popular colorama — was found doing something similar, this time paired with a Windows clipboard hijacker built to swap out cryptocurrency wallet addresses. Both packages were pulled from the Python Package Index the same day, but the incident became one of the most cited case studies in open-source supply chain security, precisely because of how mundane the attack was. No zero-day, no sophisticated obfuscation — just a stale email domain, a password reset form, and a userbase that trusted a package it had installed for years.

Four years on, the ctx/colourama incident is still worth dissecting in detail, because the exact mechanics — account takeover via an expired maintainer domain, secret exfiltration disguised as a routine network call, and a typosquat riding on a popular package's name recognition — are still the three most common ingredients in PyPI supply chain attacks today.

What Happened: A Timeline

ctx was a small, single-purpose package (a dictionary-like object that supports attribute access) that had been on PyPI since 2014 and had accumulated a modest but steady download count — reporting at the time put its lifetime installs somewhere in the hundreds of thousands, largely as a transitive dependency pulled in by other tooling rather than something developers deliberately chose. It had not been meaningfully updated in years.

On or around May 14, 2022, new versions of ctx — 0.1.2, then 0.2.2 and 0.2.6 — appeared on PyPI. Unlike the original package, these versions shipped a setup.py and runtime hook that collected the contents of os.environ, base64-encoded them, and sent them out as a query parameter in an HTTP GET request to a Heroku-hosted endpoint under a domain the attacker controlled. Because os.environ on most CI runners and developer machines contains AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY whenever AWS tooling is configured, the payload was effectively a credential harvester wearing a utility package's clothing.

Independently, researcher Somdev Sangwan flagged the anomaly on May 21–22, 2022, noting that the exfiltration domain resolved to infrastructure that was also serving a strikingly similar payload from a package called colourama. That package had been squatting on PyPI under a name one keystroke away from colorama — one of the most heavily depended-upon terminal-formatting libraries in the Python ecosystem, pulled in by everything from pip itself to countless CLI tools. Where ctx targeted environment variables broadly, colourama's payload was tuned for Windows victims: a background script that monitored the clipboard and silently replaced any string matching a cryptocurrency wallet address pattern with an attacker-controlled address, banking on victims not double-checking a paste before hitting "send" on a crypto transfer.

PyPI administrators removed both packages within roughly a day of the public disclosure. By the standards of supply chain incidents, the response was fast — but "fast" in ecosystem terms still means every CI pipeline, developer laptop, and container build that happened to resolve one of the malicious versions in that window had already executed the payload.

Anatomy of the Attack: Two Techniques, One Playbook

What made this incident notable wasn't novelty — it was that it demonstrated two distinct, durable attack patterns operating side by side:

1. Legitimate-package takeover. ctx was not a fake package built to look legitimate — it was legitimate, with years of clean history, real GitHub activity, and organic download traffic. The attacker didn't need to build trust; they inherited it. This is the more dangerous variant of supply chain compromise, because every signal a security team typically checks — package age, download count, existing reverse dependencies, absence of prior CVEs — looks fine right up until the malicious release.

2. Typosquatting. colourama relied on the opposite mechanism: manufacturing false trust by resembling a name developers already knew. Typosquats don't need long histories or organic adoption; they need one moment of pip install colourama instead of pip install colorama, one auto-complete miss, one copy-paste from a blog post with a typo in it. PyPI, like most public package registries, has historically placed few structural barriers between a legitimate package name and an adversary registering something a few characters off from it.

Pairing both techniques from what researchers assessed as likely the same operator is the detail that elevated this from "another typosquat" to a case study: it showed that a single actor could run both playbooks concurrently, hedging between patient account takeover and opportunistic name-squatting, with the same exfiltration infrastructure serving both.

The Root Cause: An Expired Domain, Not a Broken Password

The mechanism widely reported for the ctx takeover is one of the more instructive parts of the story, because it isn't a PyPI vulnerability at all — it's an identity hygiene failure. The maintainer's PyPI account was tied to an email address at a personal domain the maintainer no longer controlled. Domains lapse; when they do, anyone can re-register them and, from that point forward, receive mail sent to any address at that domain — including a PyPI "forgot password" link. That is understood to be how control of the account changed hands: not a credential leak, not a phishing email, but the quiet expiration of a domain the maintainer had stopped paying attention to years earlier.

This pattern — abandoned infrastructure becoming an attacker's entry point — recurs constantly in open-source supply chain incidents, from expired maintainer domains to orphaned npm accounts to unmaintained GitHub Actions. It is rarely detected by scanning package code, because at the moment of takeover the code is still clean. It is detected, if at all, by monitoring publishing behavior: a maintainer who hasn't shipped a release in years suddenly pushing three versions in a week is a stronger signal than anything in the diff itself.

Why It Matters Beyond 2022

It would be convenient to file ctx/colourama away as a historical curiosity, but the same two techniques — dormant-package takeover and typosquatting — have reappeared in essentially every major PyPI and npm incident since, from the event-stream npm compromise to a steady drumbeat of typosquats mimicking requests, boto3, and discord.py variants. Sonatype, Checkmarx, and other registry-monitoring efforts have reported thousands of malicious or typosquatted packages pulled from PyPI in the years since 2022, with credential and cryptocurrency theft remaining the two most common payload objectives. What made ctx distinctive is that it packaged both techniques, and both objectives (broad credential harvesting plus targeted clipboard-jacking), into one incident — a preview of the multi-pronged campaigns that followed.

For security teams, the enduring lesson is that neither "this package is old and trusted" nor "this package name looks right" is a sufficient trust signal on its own. A dependency's risk profile has to be evaluated continuously — at install time, at build time, and in production — not established once and assumed to hold.

How Safeguard Helps

Safeguard is built around the assumption that incidents like ctx/colourama will keep happening, and that the goal isn't to eliminate every malicious publish — it's to shrink the blast radius and the time-to-detection. Safeguard's SBOM generation and ingest capabilities give teams a continuously updated inventory of every open-source package in use, including transitive dependencies like ctx, so a compromised or typosquatted package version surfaces as a flagged component the moment it's pulled into a build rather than being discovered weeks later in a security bulletin. Reachability analysis then determines whether the vulnerable or malicious code path is actually invoked by your application, cutting through alert fatigue so teams can prioritize the packages that genuinely execute attacker-controlled code over the ones sitting inert in the dependency tree. Griffin AI correlates unusual publishing behavior, suspicious network egress patterns, and typosquat-style naming similarity to known-good packages, catching the kind of anomaly — a stale package suddenly shipping new releases with exfiltration logic — that traditional signature-based scanning misses. And when a fix is available, Safeguard's auto-fix PRs open the dependency bump or pin directly against the affected repository, so remediation happens in minutes rather than during the next scheduled dependency review.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.