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.

May 18, 2026·8 min read

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.5
  • next@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

10 Web Development Security Best Practices for Node.js

A prioritized checklist of web development security best practices for Node.js teams, from secure coding to production monitoring and incident response.

May 12
web development security best practices
What 1.2B Requests Look Like: Anomaly Patterns from the SecureNow Firewall Fleet

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 9
10 Best Application Security Monitoring Tools in 2026

An honest, side-by-side comparison of the ten most-deployed application security monitoring tools — from enterprise platforms to free open-source options.

May 9