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-ipAlways-Redacted Response Headers
set-cookieAdding Custom Headers to Redact
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 nationalidAdding Custom Redaction Patterns
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:
{
"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']):
{
"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-prependbefore any application code runs
// 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.
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:
// ❌ 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
| Item | Recommendation |
|---|---|
| Dashboard access | Protect /_dashboard at the reverse proxy level (Basic Auth, IP allowlist, VPN) |
| API key | Rotate regularly; treat as a weak shared secret, not a strong auth mechanism |
| HTTP body capture | Enable only for specific endpoints; always review redactKeys for your data model |
| Log file permissions | Ensure log directories have appropriate OS-level permissions |
| Log retention | Set maxFiles according to your data retention policy |
track.userId | Never serialize functions that reference sensitive values |
| Custom events | Review all tracker.track() calls for PII before deploying |
