In September 2025 a package called postmark-mcp appeared on npm. It was a
near-exact copy of a legitimate MCP server for the Postmark email service, with one line
added. That line blind-copied every message the agent sent to an address the author
controlled. Security researchers reported it as the first confirmed malicious MCP server
found in the wild.
Then it was removed. Here is what npm's registry returns for that package name today:
$ curl -s https://registry.npmjs.org/postmark-mcp
"versions": {}
"time": { "unpublished": { ... } }
That is the correct thing for a registry to do. Leaving a live backdoor installable would be worse. But notice what it costs: the package is not just uninstallable, it is unexaminable. Every question a defender asks afterwards now has no primary source to answer it.
- Which versions carried the backdoor, and which were clean?
- Exactly when did the added line first appear?
- Did the published tarball match the public repository, or did they diverge?
- You installed it in August. Were you exposed, or not?
All of those are answerable from the bytes. None of them are answerable once the bytes are withdrawn. You are left with secondary reporting and your own lockfile.
This is not a bug in npm. It is what a registry is.
A package registry is a distribution system. Its job is to serve the current, correct, installable version of a thing. Every registry that does this well overwrites yesterday to do it, because yesterday is not what it is for.
So a registry answers exactly one question: what is published right now? It is not built to answer what was published in August, and it is not built to answer what changed between then and now. Those are historical questions, and no registry keeps history you can query, because keeping it is not the job.
For ordinary software this is mostly tolerable. For MCP servers it is not, for a
specific structural reason: an MCP server is a thing an AI agent is handed
credentials and told to act with. The postmark-mcp case is
a neat illustration. The added line did not exploit a memory bug or escape a sandbox.
It used the server's ordinary, sanctioned ability to send email, and added a recipient.
The agent did exactly what it was built to do, on behalf of someone else.
When that is the shape of the risk, "what code did this thing contain on the day I gave it my API key" stops being an academic question.
What we do instead
MCPSearch asks the registries and catalogues the same questions every day, writes down the answers, and never overwrites them. Where an artifact can be retrieved, its bytes are stored and addressed by the SHA-256 of those bytes, so a stored object cannot disagree with its own address.
The record, as of 29 September 2026
- Collection began
- 8 August 2026
- Daily snapshots
- 51
- Servers observed
- 71,595
- Versions recorded
- 402,077
- Artifacts archived
- 533,110
- Bytes held
- 5.60 TB
- Sources observed daily
- Official MCP Registry, GitHub, Docker, Smithery, Cline, npm, PyPI
Every one of those figures is a count of things actually observed, not an estimate. You can check any of them in the portal.
The part we have to say out loud
We could not have caught postmark-mcp. That incident was September 2025.
This archive started collecting on 8 August 2026, eleven months later. There was no record
then, and we cannot make one now.
That is not a caveat we are burying at the bottom. It is the single most important property of a historical record: it cannot be back-filled. Every day the collection does not run is a day that is gone permanently, which is why the daily crawl is the one job in this system that everything else is allowed to be sacrificed for.
It is also why "we started" is the whole of the pitch. If the next
postmark-mcp ships tomorrow, the questions at the top of this page will have
answers that are dated, hashed and checkable, because today's bytes were written down today.
A worked example of how we can get this wrong
While writing this post we searched our own index for the incident and found a live
record for activecampaign/postmark-mcp: five versions recorded, five artifacts
archived, first observed 17 August 2026. The obvious sentence to write was "we have the
malicious package archived."
That sentence would have been false. The malicious package was published by an unrelated npm account impersonating Postmark. ActiveCampaign owns Postmark, so the record we hold is the legitimate repository, the party that was impersonated. Publishing that claim would have connected a real company to a backdoor it was the target of.
We are telling you this because it is the failure mode of every security blog that sits on top of a large dataset. A string matches, the dates look close, and a plausible sentence writes itself. So there is a rule here, and it is a checklist item rather than a principle: no record from this archive is named alongside a security incident until the identity is confirmed against the primary disclosure: publisher account, package name and registry, not a matching string.
What this archive does not do. It records observations. It does not assess whether software is safe, and a difference between two observations is a fact about bytes, not a conclusion about intent. Where this blog reports an incident, the finding belongs to the researchers who disclosed it and is linked to their work. Where it reports an observation, the observation is ours and you can verify it in the portal. The two are never blended.
Wider context, and what we will not repeat
The postmark-mcp case is not isolated. Researchers have reported a
substantial wave of MCP-related vulnerability disclosures through 2026, and formal guidance
has started to appear, including a
security design document published via the US Department of Defense
and a Cloud Security Alliance research note.
Authzed maintains a running timeline
of publicly reported MCP incidents, which is a good place to start if this is new to you.
We deliberately have not quoted the headline percentages circulating about how many MCP servers contain a given flaw. We went looking for the primary source behind one widely repeated pair of figures and could not confirm them in the paper they were attributed to. Numbers on this site come with somewhere to check them, or they do not appear.
What comes next
This blog will run weekly, in two strands. One is the record itself: what appeared, what changed, what stopped being listed, drawn straight from the daily observations. The other is what is happening in MCP security more broadly, with the archive brought to bear where it genuinely has something to add, and an explicit note where it does not.
If you want to look at the data behind any of this, the portal is open and needs no account. If you want to know exactly how the observations are made and what they cannot tell you, that is on the methodology page, including the limitations.