The first sign was a credential that stopped working. Not dramatically — no 401 cascade, no workflow failing loudly across twelve executions. Just a single HTTP Request node returning an authentication error on an endpoint that had been working fine for three months. I swapped the credential, tested, it worked. I assumed the token had expired and the client’s system had rotated it without telling me, which happens more than it should. I logged it, moved on, and did not think about it again for two weeks.
The second sign was someone in the n8n Discord mentioning that their OpenAI credential had been used to run several hundred dollars of inference they had not authorised. They were not sure how. They had not shared the key. Their n8n instance was behind a reverse proxy with auth enabled. They were asking if anyone else had seen something similar.
Three other people said yes.
By the time the actual cause was identified — a community-maintained npm package that had been updated silently to include credential exfiltration code, targeting specifically the environment variables and stored credential objects that n8n uses to persist API keys — the package had been installed as a dependency in custom nodes across a non-trivial number of self-hosted instances. The malicious version had been live for somewhere between eighteen and twenty-six days depending on which account you read. Nobody had caught it during that window because the package had a legitimate prior history, a reasonable install count, and no obvious red flags at the point of installation. The code that did the exfiltration was not in the package’s main module. It was in a lifecycle script that ran on install and sent a compressed payload to an external endpoint using a native https call with no external dependencies that would have shown up in a dependency audit.
This is the attack surface that nobody talks about clearly when they recommend self-hosting n8n with community nodes enabled.
I want to be precise about what community nodes are, because the framing matters here. They are npm packages that extend n8n’s functionality, installable directly from the n8n interface if you have enabled the feature in your environment variables. The model is similar to a plugin ecosystem. The value is real — I have used community nodes to connect APIs that do not have native n8n integrations, and some of them are well-maintained and genuinely useful. The risk is also real, and it is the same risk that exists in any ecosystem where the publication barrier is low and the review process is either automated or absent.
The n8n documentation on community nodes tells you how to install them. It tells you to check the npm page and review what the node does. What it does not tell you, with sufficient directness, is that a package that was safe when you installed it can become unsafe after an update, and that n8n’s community node update mechanism does not include integrity verification against a signed manifest. If a package is updated to include malicious code, and you have auto-update behaviour enabled, or you manually update the package through the interface, you are running the new code without any checkpoint between npm’s registry and your production environment variable store.
I disabled community nodes on all client instances after this. That is probably an overcorrection and I know it. But I made that call because the alternative — maintaining an audit process for every community package I had installed across multiple instances — was more overhead than I was willing to add to what is already a significant management surface for self-hosted infrastructure.

The credential storage model in n8n is, to be direct about it, the part of the self-hosting architecture that I think most people underestimate when they are comparing it to cloud-hosted alternatives. On a managed platform like Zapier, your credentials are encrypted and stored in infrastructure you do not control, which is a different risk model but not necessarily a worse one for most use cases. On a self-hosted n8n instance, your credentials are encrypted at rest using a key derived from your N8N_ENCRYPTION_KEY environment variable, and that variable is sitting in your Docker Compose environment file or your system environment, depending on how you set it up. If someone gets access to your host, or your environment, or a process running inside your container with sufficient permissions, the credential store is not a meaningful barrier.
What the malicious package demonstrated is that you do not need to compromise the host directly. You just need code execution inside the n8n process, which a lifecycle script on an installed npm package achieves at install time.
CrewAI and LangChain advocates will tell you that the future is agentic workflows with broad tool access and environmental permissions. That is probably true. It is also a description of a system where this attack class becomes significantly more damaging, because the credentials being stolen are not just API keys for sending emails. They are credentials for systems the agent is authorised to take actions inside.
The fix for this specific incident is straightforward in retrospect: pin your community node versions, review changelog diffs before updating, run your n8n instance with the minimum permissions required, and treat the npm registry as an untrusted source the same way you would treat any third-party code. None of that is complicated. None of it is in the getting-started documentation in the place where it needs to be.
The n8n platform itself did not have a vulnerability here. The vulnerability was in the trust model that surrounds it, and that trust model is not something any platform can fully patch.
The package was safe until it wasn’t. That is not a reassuring sentence, but it is the accurate one.

Olaitan Oladipo holds a BSc in Sociology from Olabisi Onabanjo University. He is a self-taught automation builder who has spent years inside n8n doing the work that most tutorials skip: debugging OAuth errors at 2am, migrating client automations from Make.com mid-project, fighting reverse proxy misconfigurations on AWS EC2, and figuring out through trial and error what actually holds up in production versus what only looks clean in a demo.
He is not a developer by training and not a SaaS founder. He is the person in the Discord server who actually answers the question instead of linking to the docs.
His writing on n8n Automation Tutorial covers self-hosting, AI agent workflows, tool comparisons, and the security vulnerabilities the automation industry would rather not discuss. He has built AI-assisted invoice approval flows using OpenAI function calling, connected Claude via HTTP Request nodes, and holds considered opinions about Zapier, Make.com, LangChain, and CrewAI that their marketing teams would not appreciate.
He writes for people who are technical enough to follow a tutorial but experienced enough to want the honest version.

