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.
- package/header-redaction.js +30 -0
- package/package.json +3 -2
- package/tracing.js +6 -3
|
@@ -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.
|
|
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 (
|
|
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) {
|