A platform engineer typed terraform init on a Tuesday and pulled a provider that looked like Docker tooling. The name sat on HashiCorp’s public registry. Two hundred twenty-two other teams had already fetched gocommunity-io/dockerd. Researchers at Aikido later said that pull was Go malware, and it was the first time anyone had caught threat actors using HashiCorp’s centralized repository as a distribution path. If your cybersecurity program still treats infrastructure-as-code registries as a content CDN, that moment is now your incident.

You already let that registry talk to runners that resemble production. Terraform does that by design. The new part is a payload riding a provider namespace that looked operational, not criminal.
HashiCorp already sat inside your change window
Most shops review application pull requests. Far fewer people review the provider objects that terraform init writes into .terraform on a build agent. That gap is the whole campaign. Aikido’s write-up described Go-based malware split across two Go modules and two Terraform providers, with the dockerd listing collecting 222 downloads before anyone treated it as hostile. The other listings used community-looking namespaces, including a kreuzwenker prefix that would slide past a tired glance at a lock file.
Your firewall never saw a “malware host.” It saw the same HashiCorp endpoints your pipelines have been allowed to reach for years. Brute-force dashboards stayed quiet. There was no spray against VPN, no smashed RDP, no noisy auth farm. The attacker skipped the front door you staff on weekends and used the install path you already blessed in CI.
That is why this one stings. A public registry is a software supply chain with a nicer logo. Teams pin module versions when a past scare taught them to, then leave provider source addresses floating because “it’s HashiCorp.” Cyber security programs that still equate a known vendor domain with a known binary are volunteering for this exact miss. The registry served what it was asked for. Your process never asked who published it, whether the namespace matched a real org, or why a Docker-sounding provider needed to execute as a Go binary on the runner that also holds cloud keys.
Once that binary runs, you are past the interesting part of the story for the attacker. Credentials in environment variables, OIDC tokens for the job, SSH agents left in the workspace, state backends with write access; those are the prize. Incident response that starts with “block the provider URL” is already late if the runner kept going for twenty minutes.
The implant does not need the APIs your sensors hooked
Same week, researchers described a process parameter-poisoning trick that injects into process initialization structures without calling the Windows APIs most endpoint tools instrument. Read that next to the Terraform campaign and the sequence writes itself. Stage one arrives as a trusted fetch. Stage two wants to look like a normal process start.

Defense in depth on a slide deck is a firewall, then threat-protection on the endpoint, then a SOC. In the environment you actually run, the first layer trusts registry.terraform.io and proxy.golang.org, and the second layer trusts a hook list that malware authors now treat as a map of places not to walk. Process injection that poisons initialization data is built for that map. Your EDR still records a parent, a child, a command line. The command line and the real start parameters can disagree. If nobody hunts that disagreement, the alert never fires.
Build agents make this worse. They execute unsigned-looking helper binaries all day, they talk to package registries, and they hold the keys to every account the pipeline can assume. Threat detection tuned for laptops will classify a Terraform provider as “dev tools.” That classification is how 222 pulls become a quiet beachhead instead of a ticket.
Where cybersecurity still assumes terraform init is plumbing
The real problem here is a control you never named. You inventory laptops, servers, SaaS apps, maybe even GitHub Apps. You probably do not inventory Terraform provider addresses as production software. You do not expire them. You do not require two-person review when a new source appears in a lock file. You treat terraform init as plumbing, like DHCP.
Plumbing that executes code is a software publisher. HashiCorp’s registry just became a demonstrated distribution vector, which means typosquat and impersonation rules you already apply to npm and PyPI now apply to .tf files. Waiting for the vendor to “add more scanning” is not a control. Scanning helps. Your allowlist is the control.
Security hardening here is boring on purpose. Named namespaces. Pinned versions. Checksums in lock files that CI refuses to ignore. Runners that cannot reach the public internet except for a documented registry mirror you operate. Those are the same habits that stopped the last five language-ecosystem worms, applied to the tool that builds your VPC.
Make provider pulls survive the same review as a deploy
Today, export every Terraform lock file and Go module file your org has committed in the last year. Search for gocommunity-io/dockerd, unexpected publisher prefixes, and any provider source that is not on a short internal list. If a runner pulled a suspect object, treat that runner identity as compromised: rotate the cloud roles, the state-backend credentials, and the VCS tokens attached to the job. Pull disk or container snapshots before you recycle the agent. Incident response for a poisoned provider is credential and artifact work, not a single IP block.
This week, freeze new provider sources. Require a change ticket that names the publisher, the registry, the version, and the hash. Mirror approved providers internally so pipelines never resolve a live public name at job time. Turn on egress filters so build agents can reach your mirror and nothing else. If someone needs a one-off community provider, they get a reviewed copy in your mirror, not a casual init against the internet.
Keep going after the freeze. Diff lock files in pull requests the way you diff IAM. Alert when a pipeline resolves a publisher it has never seen. On Windows runners, hunt process creation where the logged command line does not match initialization data, and treat that mismatch as a first-class signal. On Linux runners, watch unexpected child processes of Terraform and Go test harnesses, especially outbound connections that are not your mirror or your cloud API. Rehearse the playbook until on-call can answer two questions without a vendor screen: which identities did this job hold, and which state files could it write.
You cannot brute-force your way out of a trusted fetch, and you cannot firewall a name you already allow. You can stop treating HashiCorp’s shelf as a safe aisle. The 222 pulls were a price list. Pay it in review time, or pay it later in rotation work.
Sources
- Attackers Use Malicious Terraform Providers to Deliver Go Malware via HashiCorp Registry
- EDR Evasion Stack Helps Process Injection Slip Past Defenses
Take Control of Your Server Security
Don't let brute-force attacks slow you down. Try IPBan Pro risk-free for 30 days.
Secure. Automated. Lightweight.
Take Control of Your Server Security
Don't let brute-force attacks slow you down. Try IPBan Pro risk-free for 30 days.
Secure. Automated. Lightweight.
