Capturing Request Bodies for Forensics in Nuxt Without Leaking Secrets

Nuxt server middleware + h3 utilities give you a clean hook for body capture. Here's the redaction-aware pattern that works on Nuxt 3 and self-hosted Nitro.

May 9, 2026·4 min read

Capturing Request Bodies for Forensics in Nuxt Without Leaking Secrets

Nuxt 3 server routes (in server/api/) get the body via readBody(event). Add a server middleware that runs before route handlers to capture it once.

The redaction utility

// server/utils/redact.ts
const SENSITIVE = new Set([
  'password', 'pass', 'pwd', 'token', 'access_token', 'refresh_token',
  'api_key', 'apikey', 'secret', 'authorization', 'cookie', 'session',
  'creditcard', 'card_number', 'cvv', 'cvc', 'ssn',
]);

export function redact(obj: any, depth = 0): any {
  if (depth > 10) return '[max-depth]';
  if (obj == null || typeof obj !== 'object') return obj;
  if (Array.isArray(obj)) return obj.map(item => redact(item, depth + 1));

  const result: any = {};
  for (const [key, value] of Object.entries(obj)) {
    if (SENSITIVE.has(key.toLowerCase())) result[key] = '[REDACTED]';
    else if (typeof value === 'object') result[key] = redact(value, depth + 1);
    else result[key] = value;
  }
  return result;
}

The middleware

// server/middleware/forensics.ts
import { trace } from '@opentelemetry/api';
import { redact } from '../utils/redact';

export default defineEventHandler(async (event) => {
  const path = getRequestURL(event).pathname;
  if (!path.startsWith('/api/')) return;

  // Read body — must use a non-destructive method since route handler will also call readBody
  const body = await readBody(event).catch(() => null);
  const headers = getHeaders(event);

  const span = trace.getActiveSpan();
  if (span) {
    if (body) {
      const safe = JSON.stringify(redact(body)).slice(0, 8192);
      span.setAttribute('http.request.body', safe);
    }
    span.setAttribute('http.request.headers', JSON.stringify(redactHeaders(headers)));
  }
});

function redactHeaders(headers: Record<string, string | undefined>) {
  const result: Record<string, string> = {};
  for (const [key, value] of Object.entries(headers)) {
    if (!value) continue;
    const lower = key.toLowerCase();
    result[key] = (lower === 'authorization' || lower === 'cookie' || lower.startsWith('x-api-key'))
      ? '[REDACTED]'
      : String(value);
  }
  return result;
}

Caveat: body consumption

readBody() consumes the request stream. If the middleware reads it, the route handler can't read it again. Two workarounds:

  1. Tee the body: read it in middleware, attach to event context, route handler reads from context.
event.context.cachedBody = await readBody(event);

In your route handler:

const body = event.context.cachedBody ?? await readBody(event);
  1. Use the SecureNow preload, which handles this transparently.

Response capture

// server/middleware/forensics-response.ts
export default defineEventHandler((event) => {
  event.node.res.on('finish', () => {
    // Capture response metadata only; body is harder to intercept
    const span = trace.getActiveSpan();
    span?.setAttribute('http.response.status', event.node.res.statusCode);
  });
});

For full response body capture, use the SecureNow auto-instrumentation — manual response interception in Nitro is fiddly.

The automatic option

node -r securenow/register .output/server/index.mjs

Auto-captures bodies, headers, and response data with redaction across all Nuxt server routes. No middleware needed.

Related

Frequently Asked Questions

Does this work in Nuxt server routes (server/api)?

Yes. Capture happens in middleware that runs before the route handler, or inside the route handler using `readBody()`.

What about for Vercel-deployed Nuxt?

Same code works. The redaction logic doesn't depend on the runtime.

Is there an automatic option?

Yes — preload `securenow/register` and bodies are auto-captured with redaction across all Nuxt server routes.

Recommended reading

AI Security Auditing, Part 1: Set Up Your AI Agent to Audit Your Code

Part 1 of the AI Security Auditing series. Set up an AI coding agent to audit your application's security locally — install SecureNow, connect your account, and run your first threat-model pass in minutes.

Jul 24
How to Audit Your App's Security With AI: The 2026 Guide

A practical, end-to-end guide to auditing your application's security with an AI coding agent — find vulnerabilities at the code level, build detections at the runtime level, and never upload your codebase to do it.

Jul 24
AI Security Auditing, Part 2: Audit Authentication & Sessions With AI

Part 2 of the AI Security Auditing series. Use an AI agent to audit your login, session, MFA, password-reset and magic-link flows for account-takeover paths — then catch the attempts in live traffic.

Jul 23