A Next.js AWS App That Investigates And Blocks Its Own Attack
We deployed a real Next.js app to AWS, connected SecureNow traces, logs, body capture, multipart metadata, and firewall, then used an AI-assisted MCP workflow to block the attacker IP.
A Next.js AWS App That Investigates And Blocks Its Own Attack
We wanted a proof that feels like a customer demo, not a slide. So we built a small Next.js App Router application, deployed it to AWS EC2, installed the latest SecureNow npm package, and pushed both normal traffic and hostile traffic through the live public URL.
The goal was end to end:
- traces for every request
- logs tied to the same app and environment
- redacted JSON request body evidence
- multipart upload metadata
- firewall sync from SecureNow
- AI-assisted forensics through MCP
- an app-scoped blocklist decision
- a real browser-facing 403 after the block
The Stack
The lab used:
securenow@7.7.5next@16.2.6- Node.js
22.22.3 - Amazon Linux 2023
- nginx on port 80
- Next.js standalone server on port 3000
- PM2 process management
The SecureNow app was named nextjs-aws-lab-20260518, scoped to production, and deployed at http://35.180.126.67.
The Instrumentation
The Next.js app uses the SecureNow Next.js integration from instrumentation.ts:
export async function register() {
if (process.env.NEXT_RUNTIME !== "nodejs") return;
const securenowNext = await import("securenow/nextjs");
const registerSecureNow =
securenowNext.registerSecureNow ||
securenowNext.default?.registerSecureNow;
registerSecureNow({ captureBody: true });
await import("securenow/nextjs-auto-capture");
}
The deployed logs confirmed the important startup path:
[securenow] OpenTelemetry started for Next.js
[securenow] Logging: ENABLED
[securenow] Automatic body capture: ENABLED
[securenow] Firewall: ENABLED
[securenow] Firewall: Layer 1 (HTTP 403) active
To make the evidence reliable on Next.js 16, the lab also records redacted request body attributes in the shared JSON parsing helper after request.text() and JSON parsing. That gave us trace attributes like:
{
"http.request.body": "{\"orderId\":\"ord_lab_1001\",\"sku\":\"starter\",\"amount\":49,\"card\":\"[REDACTED]\"}",
"http.request.body.type": "json"
}
And for the attack payload:
{
"securenow.lab.security_signal": "sql_injection",
"http.request.body": "{\"username\":\"admin' OR 1=1--\",\"password\":\"[REDACTED]\"}"
}
Multipart evidence was captured on the upload route after request.formData():
{
"http.request.body.type": "multipart",
"http.request.body.fields_count": 2,
"http.request.body.files_count": 1,
"securenow.lab.badFile": "../../shell.php",
"securenow.lab.security_signal": "multipart_abuse"
}
The Attack Simulation
The simulator sent normal app traffic first:
- health check
- whoami
- product search
- login
- checkout
- receipt upload
Then it sent hostile traffic:
- SQL injection search
- SQL injection login
- XSS comment
- path traversal for
../../../../etc/passwd - SSRF to
169.254.169.254 - multipart upload with
../../shell.php /admin/wp-login.php/.env
The live app returned the expected mix of 200, 400, 403, and 404, and every request landed in traces and logs.
The Investigation
SecureNow MCP pulled the trace list, logs, and detailed spans. The important trace IDs from the latest run were:
- checkout body with redacted card:
31fcae599fbcf449409b8fdd45706f34 - SQL injection login body with redacted password:
7275c481bed6efcc67438357fbeece44 - multipart abuse:
fffc1d270b45734a9cfd0cd04c06bdb7 - SSRF metadata probe:
7744afd08a9fc5eec2d1c27e77ce6c7f - path traversal:
a19b3e3660fb052c8a839897b24ebeb0 - XSS comment:
8e3940020eec144b956b602bcbdc52a0
Then the agent ran a forensics query for the operator IP and the production app. The forensics job completed and returned the request timeline and trace IDs for the attack window.
One practical detail surfaced: the generated forensics SQL focused on server spans, while body capture attributes were attached to the internal Next.js route handler spans. That is a useful product-learning point: forensics gives the request timeline, and the trace detail carries the body and multipart attributes.
The Block
Before blocking, SecureNow said the IP was allowed:
{
"blocked": false,
"totalBlockedIps": 20983
}
The agent then added a production, app-scoped block for the test IP. In this account, an older removed exact IP row already existed, so the block used a semantically equivalent /32 entry:
{
"ip": "88.162.129.xxx/32",
"applicationKey": "156609bd-3074-4857-8659-f86039051aeb",
"environment": "production",
"source": "manual"
}
After the block:
{
"blocked": true,
"matchedEntry": "88.162.129.xxx/32",
"totalBlockedIps": 20984
}
The deployed firewall picked up the change:
[securenow] Firewall: re-synced 20984 blocked IPs (20983 exact + 1 CIDR ranges)
[securenow] Firewall: blocked 88.162.129.xxx via HTTP
And the public app returned 403 from the same network:
{"error":"Forbidden","ip":"88.162.129.xxx"}
For browser requests, the page changed from the app UI to SecureNow's Access Blocked - Security Alert screen.
The Evidence Chain
By the end of the run, the lab had a complete response path tied to one SecureNow app key. The current package was installed, the AWS process was serving the Next.js app, normal and hostile requests were visible in traces and logs, and body capture showed redacted JSON and multipart payloads without exposing secrets.
The investigation then moved from evidence to action. Forensics reconstructed the attack window, MCP checked that the source IP was not already blocked, the blocklist received a production-scoped /32, and the deployed firewall enforced that decision on the next browser request. The same workflow moved from request telemetry to a real 403 without adding a separate WAF or proxy layer.
Why This Matters
The important part is not that a demo app can reject obvious payloads. It is that one app key carried the entire response path:
- the request came in
- the trace showed route, status, user agent, IP, and body evidence
- the logs showed structured security signals
- forensics assembled the timeline
- the agent made a scoped response decision
- the firewall enforced the decision on the next browser request
That is the workflow customers need when they ask, "Can this actually protect my running Node app?"
Recommended reading
A prioritized checklist of web development security best practices for Node.js teams, from secure coding to production monitoring and incident response.
May 12
Aggregated, anonymized data from 1.2B requests across the SecureNow customer fleet. Top anomaly types, peak hours, and the day-of-week patterns nobody publishes.
May 9An honest, side-by-side comparison of the ten most-deployed application security monitoring tools — from enterprise platforms to free open-source options.
May 9