Skip to content

Security & Redaction

vite-plugin-monitor applies several security measures by default to prevent accidental leakage of sensitive user data into your logs and backend.

HTTP Header Redaction

Sensitive HTTP headers are always stripped from captured request and response headers, regardless of configuration. This cannot be disabled.

Always-Redacted Request Headers

authorization
cookie
x-api-key
x-auth-token
x-csrf-token
x-access-token
proxy-authorization
x-forwarded-for
x-real-ip

Always-Redacted Response Headers

set-cookie

Adding Custom Headers to Redact

typescript
track: {
  http: {
    captureRequestHeaders: true,
    excludeHeaders: [
      'x-internal-trace-id',
      'x-company-id',
      'x-employee-token',
    ],
  },
}

Cannot un-redact built-in headers

You can add headers to the exclusion list, but you cannot remove the built-in sensitive headers from it. There is no includeHeaders option.


HTTP Body Redaction

When captureRequestBody or captureResponseBody is enabled, JSON bodies are parsed and any keys matching a built-in or custom pattern are replaced with '[REDACTED]' recursively through nested objects and arrays.

Always-Redacted Body Keys

The following key substrings are always redacted (case-insensitive):

password    passwd      pass
token       secret      apikey      api_key
credential  auth        authorization
card        cardnumber  cvv         cvc         ccv
expiry      expiration
iban        ssn         sin
taxid       tax_id      nationalid

Adding Custom Redaction Patterns

typescript
track: {
  http: {
    captureRequestBody: true,
    redactKeys: [
      'fiscalCode',   // matches "fiscalCode", "userFiscalCode", "FISCALCODE"
      'vatNumber',
      'nationalId',
      'pinCode',
      'motherMaiden', // substring match: "motherMaidenName" is also redacted
    ],
  },
}

Redaction Example

Given a request body:

json
{
  "user": {
    "email": "alice@example.com",
    "password": "hunter2",
    "profile": {
      "fiscalCode": "RSSMRA80A01H501T",
      "address": "Via Roma 1"
    }
  },
  "paymentMethod": {
    "type": "card",
    "number": "4111111111111111",
    "cvv": "123"
  }
}

After redaction (with redactKeys: ['fiscalCode']):

json
{
  "user": {
    "email": "alice@example.com",
    "password": "[REDACTED]",
    "profile": {
      "fiscalCode": "[REDACTED]",
      "address": "Via Roma 1"
    }
  },
  "paymentMethod": {
    "type": "card",
    "number": "[REDACTED]",
    "cvv": "[REDACTED]"
  }
}

Non-JSON bodies are not redacted

Body redaction only applies to JSON-parseable content (Content-Type: application/json). Binary data, form data, and other content types are stored as a truncated string without redaction. Avoid enabling body capture for endpoints that handle sensitive non-JSON payloads.


window.__TRACKER_CONFIG__

The plugin injects the resolved tracker configuration into the page as window.__TRACKER_CONFIG__. This object is:

  • Frozen via Object.freeze() — cannot be mutated at runtime
  • Non-writable and non-configurable via Object.defineProperty() — cannot be overwritten or deleted
  • Set at head-prepend before any application code runs
typescript
// Generated by the plugin — you cannot modify this from app code
Object.defineProperty(window, '__TRACKER_CONFIG__', {
  value:        Object.freeze({ appId: 'my-app', ... }),
  writable:     false,
  configurable: false,
  enumerable:   false,
})

Config is visible in page source

window.__TRACKER_CONFIG__ is visible in the browser's DevTools and in the HTML page source. Do not put secrets in tracker configuration options that end up in the client-side config (e.g. apiKey, auth credentials).


Dashboard Credentials

When dashboard.auth is configured, the credentials are never stored in plaintext in window.__TRACKER_CONFIG__.

The plugin computes:

hashedUsername = HMAC-SHA256(appId, username)
hashedPassword = HMAC-SHA256(appId, password)

Only the hashed values are injected into the page. The login form hashes the user's input with the same algorithm client-side and compares the results.

typescript
dashboard: {
  auth: { username: 'admin', password: 'mySecretPassword' },
}
// → window.__TRACKER_CONFIG__.dashboard.auth = {
//     username: 'a3f...8b2',   // HMAC hash
//     password: '7c1...4e9',   // HMAC hash
//   }

Limitations

This is client-side authentication only and provides friction, not security:

  • The hashed credentials are visible in the page source
  • Anyone with access to the page can extract them
  • For production: protect the dashboard route at the proxy/server level instead

API Key Security

The storage.apiKey is sent as X-Tracker-Key on all requests and is also stored in window.__TRACKER_CONFIG__. It is suitable for:

  • Distinguishing tracker traffic from other traffic in your backend logs
  • Basic rate-limiting or routing by key
  • Development/staging environment separation

It is not suitable as a secret authentication mechanism, since it is visible in the browser.


Custom Event Data

When using tracker.track(), you are responsible for the security of the data you pass:

typescript
// ❌ Don't do this
tracker.track('user:login', {
  email:    user.email,
  password: credentials.password,  // Never include passwords
  token:    authToken,              // Never include auth tokens
})

// ✅ Do this instead
tracker.track('user:login', {
  userId:    user.id,
  loginMethod: 'email',
  success:   true,
})

The automatic redaction pipeline (for HTTP bodies) does not apply to tracker.track() data.


Production Security Checklist

ItemRecommendation
Dashboard accessProtect /_dashboard at the reverse proxy level (Basic Auth, IP allowlist, VPN)
API keyRotate regularly; treat as a weak shared secret, not a strong auth mechanism
HTTP body captureEnable only for specific endpoints; always review redactKeys for your data model
Log file permissionsEnsure log directories have appropriate OS-level permissions
Log retentionSet maxFiles according to your data retention policy
track.userIdNever serialize functions that reference sensitive values
Custom eventsReview all tracker.track() calls for PII before deploying

Released under the MIT License.