securenow 8.12.0 → 8.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ // Request-header capture: credential-bearing headers are redacted by name. Fragments match
4
+ // substring-wise on the lowercased header name, so `x-csrf-token`, `x-xsrf-token`,
5
+ // `x-session-id` and `x-goog-api-key` are all caught. Configured `capture.sensitiveFields`
6
+ // apply too, compared without case or punctuation (`csrfToken` matches `x-csrf-token`).
7
+
8
+ const { OTP_SENSITIVE_FIELDS, matchesSensitiveField } = require('./otp-redaction');
9
+
10
+ const SENSITIVE_HEADER_EXACT = new Set(['cookie', 'set-cookie', 'authorization', 'proxy-authorization']);
11
+ const SENSITIVE_HEADER_FRAGMENTS = [
12
+ 'token', 'secret', 'password', 'passwd', 'csrf', 'xsrf', 'session', 'api-key', 'apikey',
13
+ 'api_key', 'credential', 'signature', 'private-key', 'x-auth',
14
+ ];
15
+
16
+ const canonicalName = (s) => String(s).toLowerCase().replace(/[^a-z0-9]/g, '');
17
+
18
+ function createHeaderNameRedactor(customSensitiveFields = []) {
19
+ const custom = customSensitiveFields.map(canonicalName).filter(Boolean);
20
+ return function isSensitiveHeaderName(name) {
21
+ const lower = String(name).toLowerCase();
22
+ if (SENSITIVE_HEADER_EXACT.has(lower)) return true;
23
+ if (SENSITIVE_HEADER_FRAGMENTS.some((f) => lower.includes(f))) return true;
24
+ if (matchesSensitiveField(lower, OTP_SENSITIVE_FIELDS)) return true;
25
+ const canon = canonicalName(lower);
26
+ return custom.some((f) => canon.includes(f));
27
+ };
28
+ }
29
+
30
+ module.exports = { createHeaderNameRedactor, SENSITIVE_HEADER_EXACT, SENSITIVE_HEADER_FRAGMENTS };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securenow",
3
- "version": "8.12.0",
3
+ "version": "8.12.1",
4
4
  "description": "OpenTelemetry instrumentation for Node.js, Next.js, and Nuxt - Send traces and logs to any OTLP-compatible backend",
5
5
  "type": "commonjs",
6
6
  "main": "register.js",
@@ -10,7 +10,7 @@
10
10
  "securenow-mcp": "mcp/server.js"
11
11
  },
12
12
  "scripts": {
13
- "test": "node test-app-config.js && node test-resolve-ip.js && node test-otel-defaults.js && node test-telemetry.js && node test-legacy-semconv.js && node test-otp-redaction.js && node test-internal-thread.js && node test-package-contents.js"
13
+ "test": "node test-app-config.js && node test-resolve-ip.js && node test-otel-defaults.js && node test-telemetry.js && node test-legacy-semconv.js && node test-otp-redaction.js && node test-header-redaction.js && node test-internal-thread.js && node test-package-contents.js"
14
14
  },
15
15
  "keywords": [
16
16
  "opentelemetry",
@@ -161,6 +161,7 @@
161
161
  "internal-thread.js",
162
162
  "legacy-semconv.js",
163
163
  "otp-redaction.js",
164
+ "header-redaction.js",
164
165
  "rate-limits.js",
165
166
  "rate-limits.d.ts",
166
167
  "firewall-only.js",
package/tracing.js CHANGED
@@ -433,6 +433,10 @@ const allSensitiveFields = [...DEFAULT_SENSITIVE_FIELDS, ...customSensitiveField
433
433
 
434
434
  const captureMultipart = appConfig.boolConfig('capture.multipart', true);
435
435
 
436
+ // Credential-bearing request headers (cookies, auth, CSRF/XSRF, session, API keys, and any
437
+ // configured capture.sensitiveFields) are redacted by name before capture.
438
+ const isSensitiveHeaderName = require('./header-redaction').createHeaderNameRedactor(customSensitiveFields);
439
+
436
440
  const BODY_CAPTURE_PATCH = Symbol.for('securenow.bodyCapture.emitPatch');
437
441
 
438
442
  function installRequestBodyObserver(span, request, contentType) {
@@ -599,11 +603,10 @@ const httpInstrumentation = new HttpInstrumentation(withLegacyHttpSemconv({
599
603
  }
600
604
 
601
605
  if (request.headers) {
602
- const SKIP_HEADERS = new Set(['cookie', 'authorization', 'proxy-authorization', 'set-cookie', 'x-api-key', 'x-auth-token']);
603
606
  const safe = {};
604
607
  for (const [k, v] of Object.entries(request.headers)) {
605
- if (SKIP_HEADERS.has(k.toLowerCase()) || matchesSensitiveField(k, OTP_SENSITIVE_FIELDS)) { safe[k] = '[REDACTED]'; continue; }
606
- safe[k] = redactOtpQuery(typeof v === 'string' ? v : String(v)).substring(0, 500);
608
+ if (isSensitiveHeaderName(k)) { safe[k] = '[REDACTED]'; continue; }
609
+ safe[k] = redactSensitiveValue(redactOtpQuery(typeof v === 'string' ? v : String(v))).substring(0, 500);
607
610
  }
608
611
  const serialized = JSON.stringify(safe);
609
612
  if (serialized.length <= 8192) {