For years, supply chain attackers focused their efforts on npm, PyPI, and RubyGems. That perimeter has now expanded. Researchers at Aikido have disclosed what is believed to be the first confirmed campaign using the centralized HashiCorp Terraform Registry as a malware distribution vector, delivering Go-based payloads through two malicious Terraform providers and two malicious Go modules.
Among the packages identified is the Go module gocommunity-io/dockerd (which had accumulated 222 downloads at the time of disclosure) and packages abusing the kreuzwenker/ namespace — a naming pattern consistent with typosquatting against a well-known, legitimate Docker provider namespace. This is significant for two reasons:
- Terraform runs in privileged contexts. Providers execute during
terraform init,plan, andapply— frequently inside CI/CD runners holding cloud credentials with broad permissions (IAM admin, subscription owner, or worse). A malicious provider does not need to exploit a vulnerability; it inherits the trust you already granted your pipeline. - The trust model is the vulnerability. Engineers routinely pull community providers and Go modules with little or no vetting. Attackers know this, and typosquatting a recognizable namespace is cheap and effective.
If your organization uses Terraform with community providers, or Go modules fetched from public proxies, you need to treat this as an active threat — audit your dependency trees, hunt for anomalous provider behavior, and harden your pipelines today.
Technical Analysis
What Happened
According to Aikido's disclosure, threat actors published malicious packages across two ecosystems:
- Two malicious Terraform providers hosted on the HashiCorp Terraform Registry (registry.terraform.io), including packages abusing the
kreuzwenker/namespace. - Two malicious Go modules, including
gocommunity-io/dockerd, which had already been downloaded 222 times.
The payloads are written in Go — a deliberate choice. Go compiles to self-contained, statically-linked binaries that are trivial to cross-compile for Linux, Windows, and macOS, and Go-based loaders have historically had lower static detection rates than script-based malware.
How the Attack Works
Terraform provider vector: When an engineer or CI/CD pipeline runs terraform init, Terraform downloads the declared providers from the registry into the .terraform/providers/ directory. Providers are native executables (typically written in Go using the Terraform Plugin SDK). During terraform plan and terraform apply, the provider binary is executed as a child process of Terraform and communicates over gRPC. A malicious provider therefore achieves code execution:
- With the identity of whoever ran Terraform — often a CI/CD service principal with cloud admin rights.
- Inside the build environment, where environment variables frequently contain
ARM_CLIENT_SECRET,AWS_SECRET_ACCESS_KEY,GOOGLE_CREDENTIALS, or equivalent. - With network access to exfiltrate those credentials or pivot into the cloud control plane.
Go module vector: When a developer or build system runs go build or go mod download, modules are fetched through the Go module proxy (proxy.golang.org by default) and cached locally. A malicious module can execute code via init() functions the moment it is imported, or drop and run a second-stage payload during build/test execution (go generate, go test).
Why Typosquatting Works Here
The abuse of a namespace resembling kreuzwenker/ is textbook typosquatting — registering a name visually similar to a legitimate, trusted provider so that a hasty required_providers block, a copy-pasted snippet from a forum, or a mistaken terraform init resolves to the attacker's package. This mirrors the same technique we have seen for years on npm and PyPI (MITRE ATT&CK T1195.001 — Compromise Software Dependencies and Development Tools).
Exploitation Status
- Actively distributed in the wild: Yes — the packages were live on public registries with confirmed download counts.
- CVE assigned: None at the time of writing. This is a malicious-package campaign, not a product vulnerability, so no CVE applies. Do not wait for a CVE to act.
- CISA KEV: Not listed (no CVE exists).
Who Is at Risk
- Any organization that has run
terraform init/applyagainst configurations referencing community providers without pinning or verification. - Go developers and build systems that fetch modules without
GOPRIVATE/GONOSUMCHECKdiscipline or vendoring. - CI/CD platforms (GitHub Actions, GitLab CI, Azure DevOps, Jenkins, Atlantis, Terraform Cloud/Enterprise) executing Terraform with cloud credentials.
Detection & Response
The highest-fidelity detections for this threat focus on behavioral anomalies around the Terraform toolchain: Terraform spawning unexpected child processes, providers making outbound network connections unrelated to cloud APIs, and unexpected executables appearing in provider plugin directories. Audit your .terraform.lock.hcl files and go.mod/go.sum for the named malicious packages immediately.
Sigma Rules
---
title: Terraform Process Spawning Suspicious Child Process
id: 3f9a1b72-6c4e-4d21-9a8b-5e7c2d40f1a9
status: experimental
description: Detects the terraform binary spawning shells, script interpreters, or download utilities. Malicious Terraform providers executing payloads during plan/apply often launch child processes outside normal provider gRPC behavior.
references:
- https://thehackernews.com/2026/09/attackers-use-malicious-terraform.html
- https://attack.mitre.org/techniques/T1195/001/
author: Security Arsenal
date: 2026/09/15
tags:
- attack.supply_chain_compromise
- attack.t1195.001
- attack.execution
logsource:
category: process_creation
product: windows
detection:
selection_parent:
ParentImage|endswith:
- '\terraform.exe'
selection_child:
Image|endswith:
- '\powershell.exe'
- '\pwsh.exe'
- '\cmd.exe'
- '\wscript.exe'
- '\cscript.exe'
- '\mshta.exe'
- '\curl.exe'
- '\rundll32.exe'
- '\regsvr32.exe'
- '\certutil.exe'
condition: selection_parent and selection_child
falsepositives:
- Terraform external data sources or local-exec provisioners intentionally invoking scripts
level: high
---
title: Malicious Go Module or Terraform Provider Package Reference
id: 8c2e4d19-1a5b-4f67-b3d2-9f0e6a21c7b4
status: experimental
description: Detects references to known malicious package identifiers disclosed in the Aikido research, including the gocommunity-io/dockerd Go module and the abused kreuzwenker Terraform provider namespace, in process command lines or file content tooling.
references:
- https://thehackernews.com/2026/09/attackers-use-malicious-terraform.html
author: Security Arsenal
date: 2026/09/15
tags:
- attack.supply_chain_compromise
- attack.t1195.001
logsource:
category: process_creation
product: windows
detection:
selection:
CommandLine|contains:
- 'gocommunity-io/dockerd'
- 'kreuzwenker'
condition: selection
falsepositives:
- The legitimate kreuzwenker/docker provider may be in authorized use; verify provider source registry and lock file hashes before treating as benign
level: high
---
title: Terraform Provider Plugin Execution From Nonstandard Path
id: 5b1d7e36-8f42-4a90-c6e1-2d8b9f03a5c7
status: experimental
description: Detects execution of executables with terraform-provider naming conventions from user-writable or temporary directories rather than the standard .terraform/providers or plugin cache paths, a pattern consistent with dropped second-stage Go payloads.
references:
- https://thehackernews.com/2026/09/attackers-use-malicious-terraform.html
- https://attack.mitre.org/techniques/T1195/001/
author: Security Arsenal
date: 2026/09/15
tags:
- attack.supply_chain_compromise
- attack.t1195.001
- attack.execution
logsource:
category: process_creation
product: windows
detection:
selection_name:
Image|contains: 'terraform-provider'
filter_legit:
Image|contains:
- '\.terraform\providers\'
- '\terraform.d\plugin-cache\'
- '\.terraform.d\'
condition: selection_name and not filter_legit
falsepositives:
- Custom-built providers under development executed from GOPATH or build directories
level: medium
KQL (Microsoft Sentinel / Defender)
// Hunt 1: Terraform spawning suspicious child processes (endpoints + CI runners with MDE)
let suspiciousChildren = dynamic(["powershell.exe","pwsh.exe","cmd.exe","curl.exe","wget.exe","mshta.exe","rundll32.exe","bash","sh","python","python3"]);
DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where InitiatingProcessFileName has "terraform" or FileName has "terraform"
| where FileName in~ (suspiciousChildren)
| project TimeGenerated, DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, SHA256
| order by TimeGenerated desc;
// Hunt 2: Any reference to the disclosed malicious packages across process and command telemetry
union DeviceProcessEvents, DeviceFileEvents, DeviceImageLoadEvents
| where TimeGenerated > ago(30d)
| where ProcessCommandLine has_any ("gocommunity-io/dockerd", "kreuzwenker")
or FileName has_any ("gocommunity-io", "dockerd")
or FolderPath has "gocommunity-io"
| project TimeGenerated, DeviceName, ActionType, FileName, FolderPath, ProcessCommandLine, SHA256;
// Hunt 3: Terraform provider binaries making unexpected outbound network connections
// (Linux CI runners forwarded via Syslog/CEF, or MDE network events)
DeviceNetworkEvents
| where TimeGenerated > ago(14d)
| where InitiatingProcessFileName has "terraform-provider" or InitiatingProcessFileName =~ "terraform"
| where not (RemoteUrl has_any ("amazonaws.com","azure.com","microsoftonline.com","googleapis.com","cloudflare.com","releases.hashicorp.com","registry.terraform.io","checkpoint-api.hashicorp.com"))
| summarize Connections=count(), UniqueDestinations=dcount(RemoteIP), Destinations=make_set(RemoteUrl, 20) by DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by Connections desc;
// Hunt 4: Syslog-ingested Linux runners — go toolchain fetching modules then spawning shells
Syslog
| where TimeGenerated > ago(14d)
| where ProcessName has_any ("go", "terraform")
| where SyslogMessage has_any ("gocommunity-io", "/bin/sh -c", "/bin/bash -c")
| project TimeGenerated, Computer, ProcessName, SyslogMessage;
Velociraptor VQL
-- Hunt: Rogue Terraform provider binaries and references to malicious packages
-- Searches plugin directories for recently created executables and enumerates
-- terraform/go child processes and outbound connections.
-- 1. Recently written executables in Terraform provider/plugin paths
SELECT FullPath, Size, Mtime, Ctime,
hash(path=FullPath) AS Hash
FROM glob(globs=[
'C:/Users/*/.terraform.d/**/*',
'C:/Users/*/go/pkg/mod/github.com/gocommunity-io*/**',
'/home/*/.terraform.d/**/*',
'/root/.terraform.d/**/*',
'/home/*/go/pkg/mod/github.com/gocommunity-io*/**',
'/root/go/pkg/mod/github.com/gocommunity-io*/**',
'**/.terraform/providers/**/*.exe'
])
WHERE NOT IsDir
AND Mtime > now() - 60 * 24 * 3600
ORDER BY Mtime DESC
-- 2. Live processes: terraform or go spawning interpreters, plus their network connections
SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime
FROM pslist()
WHERE (Name =~ '(?i)terraform|go(\.exe)?$|dockerd'
AND CommandLine =~ '(?i)kreuzwenker|gocommunity-io')
OR (Ppid IN (SELECT Pid FROM pslist() WHERE Name =~ '(?i)terraform')
AND Name =~ '(?i)powershell|cmd|bash|sh|python|curl|wget')
-- 3. Outbound connections from terraform/provider processes (exfil / C2 check)
SELECT Pid, Name, ProcessName, DestIP, DestPort, Status
FROM netstat()
WHERE ProcessName =~ '(?i)terraform|dockerd|gocommunity'
AND Status =~ 'ESTAB'
AND DestIP !~ '^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.|127\.)'
Remediation & Audit Script
Run the following in your repositories, build agents, and developer workstations to audit for the disclosed malicious packages and unverified provider usage:
#!/usr/bin/env bash
# audit-terraform-go-supplychain.sh
# Audits Terraform configs/lock files and Go modules for the malicious packages
# disclosed by Aikido (Sept 2026). Run at repo root or against a build agent.
set -euo pipefail
FOUND=0
MALICIOUS_PATTERNS=(
"gocommunity-io/dockerd"
"gocommunity-io"
)
echo "=== [1/4] Scanning Terraform configurations and lock files ==="
for pat in "${MALICIOUS_PATTERNS[@]}" "kreuzwenker"; do
if grep -rIn --include='*.tf' --include='.terraform.lock.hcl' "$pat" . 2>/dev/null; then
echo "[ALERT] Suspicious reference found: $pat"
FOUND=1
fi
done
echo "=== [2/4] Scanning Go module files ==="
if grep -rIn --include='go.mod' --include='go.sum' "gocommunity-io" . 2>/dev/null; then
echo "[ALERT] Malicious Go module reference in go.mod/go.sum"
FOUND=1
fi
echo "=== [3/4] Checking Go module cache for malicious modules ==="
GOMODCACHE=$(go env GOMODCACHE 2>/dev/null || echo "")
if [[ -n "$GOMODCACHE" && -d "$GOMODCACHE" ]]; then
if ls "$GOMODCACHE"/github.com/ 2>/dev/null | grep -i "gocommunity-io"; then
echo "[ALERT] Malicious module present in local Go module cache — purge and investigate host"
FOUND=1
fi
fi
echo "=== [4/4] Listing all community (non-hashicorp/non-official) providers in use ==="
grep -rhA2 'required_providers' --include='*.tf' . 2>/dev/null | \
grep -E 'source\s*=' | sort -u | grep -vE 'hashicorp/|integrations/github|terraform-aws-modules' || \
echo "No non-official provider sources detected (verify manually)."
echo ""
echo "=== Provider verification status ==="
find . -name '.terraform.lock.hcl' -exec sh -c 'echo "--- {} ---"; grep -E "^provider|^ \"registry" {} | head -40' \; 2>/dev/null || true
if [[ $FOUND -eq 1 ]]; then
echo ""
echo "!!! MALICIOUS PACKAGE INDICATORS FOUND — ISOLATE HOST, ROTATE ANY CLOUD CREDENTIALS USED BY THIS PIPELINE, AND OPEN AN IR CASE !!!"
exit 2
else
echo ""
echo "No indicators of the disclosed malicious packages found. Continue with hardening steps in the accompanying advisory."
exit 0
fi
For Windows-based build agents and developer machines:
# Audit-TerraformSupplyChain.ps1 — run at repo root or against an agent
$ErrorActionPreference = 'SilentlyContinue'
$found = $false
Write-Host '=== [1/3] Scanning Terraform and Go files for malicious package references ==='
$hits = Get-ChildItem -Recurse -Include *.tf,.terraform.lock.hcl,go.mod,go.sum |
Select-String -Pattern 'gocommunity-io','gocommunity-io/dockerd','kreuzwenker'
if ($hits) { $hits | Format-Table Path, LineNumber, Line -AutoSize; $found = $true }
Write-Host '=== [2/3] Checking Go module cache ==='
$modCache = (& go env GOMODCACHE) 2>$null
if ($modCache -and (Test-Path "$modCache\github.com")) {
Get-ChildItem "$modCache\github.com" -Directory |
Where-Object Name -match 'gocommunity-io' |
ForEach-Object { Write-Host "[ALERT] Malicious module cached: $($_.FullName)"; $script:found = $true }
}
Write-Host '=== [3/3] Enumerating non-HashiCorp provider sources ==='
Get-ChildItem -Recurse -Filter *.tf |
Select-String -Pattern 'source\s*=\s*"' |
Where-Object { $_.Line -notmatch 'hashicorp/' } |
Select-Object Path, Line -Unique | Format-Table -AutoSize
if ($found) {
Write-Host '`n!!! INDICATORS FOUND — isolate host, rotate pipeline cloud credentials, open IR case !!!' -ForegroundColor Red
exit 2
} else {
Write-Host '`nNo disclosed malicious package indicators found.' -ForegroundColor Green
exit 0
}
Remediation
This campaign is not a patchable vulnerability — it is a trust and hygiene failure in the dependency supply chain. There is no vendor patch and no CVE. Remediation is procedural and architectural:
Immediate (0–24 hours)
- Audit for the disclosed packages. Run the scripts above across all Terraform repositories, CI/CD agents, developer workstations, and Go module caches. Check
.terraform.lock.hcl,go.mod,go.sum, and any vendored dependencies. - If a malicious package is found, treat it as a confirmed compromise: isolate the host/agent, capture forensic images before cleanup, and rotate every credential accessible to that pipeline — cloud IAM keys, service principal secrets, registry tokens, VCS tokens. Assume they are exfiltrated.
- Review cloud audit logs (CloudTrail, Azure Activity Log, GCP Audit Logs) for activity by pipeline identities during the exposure window. Look for IAM enumeration, key creation, and role assumption from unfamiliar IPs.
Short-Term (1–2 weeks)
- Enforce provider pinning and lock-file discipline. Commit
.terraform.lock.hclto version control and runterraform init -lockfile=readonlyin CI so providers cannot be silently substituted or updated. - Restrict provider sources. Use an explicit allowlist of provider namespaces (e.g., only
hashicorp/*and vetted partners). On Terraform Cloud/Enterprise or viaterraformrcCLI configuration, use theprovider_installationblock withdirectlimited to approved namespaces or an internal network mirror (filesystem_mirror/network_mirror) so all provider downloads flow through a controlled, reviewed copy. - Vet community providers before adoption. Review the provider's source repository, signing status (GPG-signed providers in the registry), download counts, and maintainer history. Treat any provider resembling an existing trusted namespace (the
kreuzwenkerpattern) with heightened suspicion. - Harden Go consumption: set
GOPRIVATE/GONOSUMDBfor internal modules, keepGOFLAGS=-mod=readonlyin CI, verifygo.sumentries againstsum.golang.org, and consider a module proxy such as Athens or JFrog Artifactory with blocking rules for unreviewed modules.
Long-Term (30–90 days)
- Remove cloud credentials from provider-execution context where possible. Use OIDC-based short-lived federation (GitHub Actions → AWS/Azure/GCP workload identity) instead of long-lived secrets in environment variables, so a compromised provider has a narrow, time-boxed window.
- Isolate Terraform execution. Run
plan/applyin ephemeral, egress-restricted containers with no inbound access and outbound rules limited to required cloud API endpoints and the approved provider mirror. A malicious provider that cannot reach the internet cannot exfiltrate. - Deploy the detections above and add dependency-change alerting: any PR that adds a new provider or Go module should trigger a security review gate and an automated SBOM diff.
- Continuously monitor advisories from Aikido, HashiCorp's registry security notices, and the OpenSSF for newly disclosed malicious packages — this campaign will not be the last to abuse the Terraform Registry.
The deeper lesson: infrastructure-as-code toolchains are production attack surface. The same rigor you apply to runtime workloads — least privilege, egress control, allowlisting, and behavioral detection — must extend to the pipelines that build and deploy them.
Related Resources
Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.