IDebug is experimental. Prefer enabling only in development.
GuidesSecurity posture

Security posture

IDebug is a dev-only debugger. When enabled, /__idebug can expose full request bodies, headers, cookies, and function arguments that already passed redaction defaults. Treat the inspector like a local secrets viewport — not a public dashboard.

Threat model

RiskWhy it matters
Accidental production enableAnyone who can hit your app origin can read recent traffic
Server bound to 0.0.0.0LAN peers (or the whole internet if the port is exposed) can open /__idebug
DNS rebindingA malicious site can try to make the browser call http://evil.com/__idebug/... after rebinding evil.com to 127.0.0.1
Shared machines / screensharesSession list may contain auth headers (redacted by default) and PII you sent in bodies

IDebug is not multi-tenant, has no user accounts, and is not a production APM.

Defaults (maximize safety)

ControlDefaultRole
enabledfalseEntire middleware + UI no-op until you opt in
hostChecktrueHost must be loopback / localhost (DNS rebinding bar)
localRemoteOnlytrueTCP peer must be loopback
accessTokennullOptional shared secret (strongly recommended on non-loopback binds)
Redactiononauthorization, password, tokens, … → *** before store
IDebug.configure({
  enabled: process.env.NODE_ENV !== 'production',
  appName: 'my-api',
  // Security (these are the defaults — shown for clarity)
  hostCheck: true,
  localRemoteOnly: true,
  // accessToken: process.env.IDEBUG_TOKEN, // recommend setting one
});

Prefer binding the HTTP server itself to loopback when you only need local debugging:

app.listen(3000, '127.0.0.1');

Host check (DNS rebinding protection)

Browsers send a Host header for every request. A DNS rebinding attack loads JS from an attacker-controlled name, then rebinds that name to your machine and calls your local app with Host: evil.com.

IDebug’s mitigation (default on): reject /__idebug unless Host is:

  • localhost
  • 127.0.0.0/8 (e.g. 127.0.0.1)
  • ::1 / [::1]
  • or a name you explicitly list in allowedHosts (e.g. /etc/hosts entries like myapp.local)

This matches the industry bar used by local debug sidecars (for example Spotlight documents DNS rebinding protections on its local server). Rebinding to loopback is useless if the Host is still evil.com and we refuse it.

IDebug.configure({
  enabled: true,
  allowedHosts: ['myapp.local'], // custom local DNS / hosts file
});

Denied requests return HTTP 403 with reason: "host_not_allowed".

Local remote guard (bind guard)

Even with a correct Host, a process listening on 0.0.0.0:3000 can be reached from the network. When localRemoteOnly: true (default), IDebug also checks the socket peer address and rejects non-loopback clients (HTTP 403, reason: "remote_not_local").

Disable only when you intentionally debug from another device on LAN/VPN:

IDebug.configure({
  enabled: true,
  localRemoteOnly: false,
  accessToken: process.env.IDEBUG_TOKEN, // require a token if not loopback-only
  allowedHosts: ['192.168.1.20'], // Host header as the device uses it
});

Set accessToken to require a shared secret on every UI/API request:

MechanismHeader / query
BearerAuthorization: Bearer <token>
Custom headerX-IDebug-Token: <token>
Query (SSE / SPA)?idebug_token=<token>

EventSource cannot set Authorization headers, so the SPA uses the query param (and stores it in sessionStorage when opened as /__idebug?idebug_token=...).

IDebug.configure({
  enabled: true,
  accessToken: process.env.IDEBUG_TOKEN ?? 'change-me',
});

Open: http://127.0.0.1:3000/__idebug?idebug_token=change-me

Missing/invalid token → HTTP 401.

Redaction is not access control

Default redaction scrubs common secret keys before events hit the ring buffer. It does not:

  • remove arbitrary PII in free-text bodies
  • replace your need for Host / remote / token gates
  • make production exposure safe

Add domain keys via redactKeys: ['ssn', 'taxId']. See Redaction.

Response hardening

All /__idebug responses set:

  • X-Frame-Options: DENY
  • X-Content-Type-Options: nosniff
  • Referrer-Policy: no-referrer
  • Cache-Control: no-store

There is still no multi-user auth and no CSRF cookie model — same-origin browser access from a page that can already talk to your origin is in scope of “you enabled a local debugger.”

Production checklist

  • enabled: false (or unset) in production builds
  • Prefer app.listen(port, '127.0.0.1') for local-only debug sessions
  • Leave hostCheck: true and localRemoteOnly: true unless you know you need otherwise
  • Set accessToken if the process is reachable beyond loopback
  • Do not put /__idebug behind a public reverse proxy without your own auth
  • Assume captured traffic may include credentials that escaped redaction keys

React overlay

@idebug/react runs in the page (no server UI). It does not open a network listener, but it still stores network payloads in memory in the tab. Keep enabled: import.meta.env.DEV (or equivalent) and never ship the overlay to production users.