@gcunharodrigues/wrxn 0.18.0 → 0.18.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gcunharodrigues/wrxn",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"description": "WRXN Kernel — installable AI operating system. Two profiles (project | workspace), pull-based updates, managed/seeded/state file classes.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"wrxn": "bin/wrxn.cjs"
|
|
@@ -15,21 +15,38 @@ const path = require('path');
|
|
|
15
15
|
// secretScan — replicated here because each self-contained install-only module imports no shared
|
|
16
16
|
// kernel-lib (node stdlib only), exactly as it is duplicated across dream.cjs / sync.cjs. CASE-SENSITIVE:
|
|
17
17
|
// the token shapes are case-specific. A coalesced sidecar must never harden a credential onto disk.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/
|
|
18
|
+
// The CANONICAL secret-shape set (#39) — kept BYTE-IDENTICAL across every copy (dream / sync / harvest /
|
|
19
|
+
// memory-synth + this one), drift-pinned by adapter-drift-guard.test.cjs. Each self-contained module
|
|
20
|
+
// replicates the set (the install-only adapters import no shared module — node stdlib only), so the pin is
|
|
21
|
+
// what keeps the copies honest. CASE-SENSITIVE except where a shape carries its own /i flag.
|
|
22
|
+
const SECRET_PATTERNS_CANON = [
|
|
23
|
+
/AKIA[0-9A-Z]{16}/, // AWS access key id
|
|
24
|
+
/gh[pousr]_[A-Za-z0-9]{20,}/, // GitHub token (ghp_/gho_/ghu_/ghs_/ghr_); {20,} covers the 36-char + CI forms
|
|
25
|
+
/github_pat_[A-Za-z0-9_]{22,}/, // GitHub fine-grained PAT
|
|
26
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/, // Slack token
|
|
27
|
+
/sk-[A-Za-z0-9]{20,}/, // OpenAI-style secret key
|
|
28
|
+
/sk-proj-[A-Za-z0-9_-]{20,}/, // OpenAI project-scoped key (underscore form sk-… misses)
|
|
29
|
+
/AIza[0-9A-Za-z._-]{10,}/, // Google / Gemini API key
|
|
30
|
+
/sk_(?:live|test)_[A-Za-z0-9]{20,}/, // Stripe live/test secret key
|
|
31
|
+
/npm_[A-Za-z0-9]{20,}/, // npm publish / automation token
|
|
32
|
+
/\bey[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{3,}\.[A-Za-z0-9_-]{3,}\b/, // JWT (incl. Bearer payloads); the eyJ… header gates it
|
|
33
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/, // PEM block (FULL — must precede the header fallback so redaction eats the body)
|
|
34
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/, // PEM header (fallback: a lone/truncated header with no END)
|
|
35
|
+
/Bearer\s+[A-Za-z0-9._~+/=-]{20,}/, // opaque Bearer token (non-JWT)
|
|
36
|
+
/\b[A-Za-z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD)\b\s*[:=]\s*\S+/i, // KEY/TOKEN/SECRET/PASSWORD = value
|
|
37
|
+
];
|
|
38
|
+
// sidecar-LOCAL extras (#38) the canonical set does not subsume — broader / hooks-layer-specific, so they
|
|
39
|
+
// are NOT part of the drift-pinned core. Kept so sidecar never weakens (no pre-existing match is lost).
|
|
40
|
+
const SIDECAR_EXTRA = [
|
|
41
|
+
/Bearer\s+[A-Za-z0-9\-._~+/]{16,}=*/i, // case-insensitive bearer scheme, 16-char floor (broader than the canonical Bearer)
|
|
26
42
|
// password=/pwd= assignment (=, :, quoted JSON/YAML). The keyword is EITHER fully quoted ("password":)
|
|
27
43
|
// OR bare (password=) — never a lone trailing quote, so a path ending in "passwd" used as a JSON key
|
|
28
44
|
// (e.g. "../../etc/passwd": …) is NOT misread as an assignment (it would falsely refuse a sidecar write).
|
|
29
45
|
/(?:["'](?:password|passwd|pwd)["']|(?:password|passwd|pwd))\s*[:=]\s*["']?[^\s"',;)&}{]+/i,
|
|
30
46
|
/[a-z][a-z0-9+.\-]+:\/\/[^\s:/@]+:[^\s/@]+@\S+/i, // URI connection string with inline creds (scheme://user:pass@host)
|
|
31
|
-
/eyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}/, // JWT
|
|
47
|
+
/eyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}/, // JWT (eyJ header; shorter min than the canonical JWT)
|
|
32
48
|
];
|
|
49
|
+
const SECRET_PATTERNS = [...SECRET_PATTERNS_CANON, ...SIDECAR_EXTRA];
|
|
33
50
|
|
|
34
51
|
function secretScan(text) {
|
|
35
52
|
const s = String(text || ''); // NOT lowercased — the token shapes are case-sensitive.
|
package/payload/.wrxn/dream.cjs
CHANGED
|
@@ -421,11 +421,20 @@ function negativeFilter(text) {
|
|
|
421
421
|
// token shapes are case-specific). Evidence quotes are audit-only (never written to a page) so they
|
|
422
422
|
// stay out of scope here, like the negative filters.
|
|
423
423
|
const SECRET_PATTERNS = [
|
|
424
|
-
/AKIA[0-9A-Z]{16}/,
|
|
425
|
-
/gh[pousr]_[A-Za-z0-9]{
|
|
426
|
-
/
|
|
427
|
-
/
|
|
428
|
-
|
|
424
|
+
/AKIA[0-9A-Z]{16}/, // AWS access key id
|
|
425
|
+
/gh[pousr]_[A-Za-z0-9]{20,}/, // GitHub token (ghp_/gho_/ghu_/ghs_/ghr_); {20,} covers the 36-char + CI forms
|
|
426
|
+
/github_pat_[A-Za-z0-9_]{22,}/, // GitHub fine-grained PAT
|
|
427
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/, // Slack token
|
|
428
|
+
/sk-[A-Za-z0-9]{20,}/, // OpenAI-style secret key
|
|
429
|
+
/sk-proj-[A-Za-z0-9_-]{20,}/, // OpenAI project-scoped key (underscore form sk-… misses)
|
|
430
|
+
/AIza[0-9A-Za-z._-]{10,}/, // Google / Gemini API key
|
|
431
|
+
/sk_(?:live|test)_[A-Za-z0-9]{20,}/, // Stripe live/test secret key
|
|
432
|
+
/npm_[A-Za-z0-9]{20,}/, // npm publish / automation token
|
|
433
|
+
/\bey[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{3,}\.[A-Za-z0-9_-]{3,}\b/, // JWT (incl. Bearer payloads); the eyJ… header gates it
|
|
434
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/, // PEM block (FULL — must precede the header fallback so redaction eats the body)
|
|
435
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/, // PEM header (fallback: a lone/truncated header with no END)
|
|
436
|
+
/Bearer\s+[A-Za-z0-9._~+/=-]{20,}/, // opaque Bearer token (non-JWT)
|
|
437
|
+
/\b[A-Za-z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD)\b\s*[:=]\s*\S+/i, // KEY/TOKEN/SECRET/PASSWORD = value
|
|
429
438
|
];
|
|
430
439
|
|
|
431
440
|
function secretScan(text) {
|
|
@@ -653,11 +653,20 @@ function isKebab(s) {
|
|
|
653
653
|
// A merged survivor must never harden a session secret into recalled prose. Same patterns + case-sensitive
|
|
654
654
|
// scope as dream/sync — replicated because each install-only adapter is self-contained (node stdlib only).
|
|
655
655
|
const SECRET_PATTERNS = [
|
|
656
|
-
/AKIA[0-9A-Z]{16}/,
|
|
657
|
-
/gh[pousr]_[A-Za-z0-9]{
|
|
658
|
-
/
|
|
659
|
-
/
|
|
660
|
-
|
|
656
|
+
/AKIA[0-9A-Z]{16}/, // AWS access key id
|
|
657
|
+
/gh[pousr]_[A-Za-z0-9]{20,}/, // GitHub token (ghp_/gho_/ghu_/ghs_/ghr_); {20,} covers the 36-char + CI forms
|
|
658
|
+
/github_pat_[A-Za-z0-9_]{22,}/, // GitHub fine-grained PAT
|
|
659
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/, // Slack token
|
|
660
|
+
/sk-[A-Za-z0-9]{20,}/, // OpenAI-style secret key
|
|
661
|
+
/sk-proj-[A-Za-z0-9_-]{20,}/, // OpenAI project-scoped key (underscore form sk-… misses)
|
|
662
|
+
/AIza[0-9A-Za-z._-]{10,}/, // Google / Gemini API key
|
|
663
|
+
/sk_(?:live|test)_[A-Za-z0-9]{20,}/, // Stripe live/test secret key
|
|
664
|
+
/npm_[A-Za-z0-9]{20,}/, // npm publish / automation token
|
|
665
|
+
/\bey[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{3,}\.[A-Za-z0-9_-]{3,}\b/, // JWT (incl. Bearer payloads); the eyJ… header gates it
|
|
666
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/, // PEM block (FULL — must precede the header fallback so redaction eats the body)
|
|
667
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/, // PEM header (fallback: a lone/truncated header with no END)
|
|
668
|
+
/Bearer\s+[A-Za-z0-9._~+/=-]{20,}/, // opaque Bearer token (non-JWT)
|
|
669
|
+
/\b[A-Za-z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD)\b\s*[:=]\s*\S+/i, // KEY/TOKEN/SECRET/PASSWORD = value
|
|
661
670
|
];
|
|
662
671
|
|
|
663
672
|
function secretScan(text) {
|
|
@@ -187,6 +187,51 @@ const THINK_MAX = 600;
|
|
|
187
187
|
const TOOL_USE_MAX = 300;
|
|
188
188
|
const TOOL_RESULT_MAX = 200;
|
|
189
189
|
|
|
190
|
+
// Hook-injected framework-context sentinels. SessionStart emits <wrxn-orientation> (which embeds the
|
|
191
|
+
// ENTIRE prior baton as the resume surface); UserPromptSubmit emits <synapse-rules>/<recall-surface>/
|
|
192
|
+
// <reference-candidate> each turn; <system-reminder> wraps harness notes. All land verbatim in the
|
|
193
|
+
// transcript. Left in, they out-mass a light session's real turns → the synth re-emits the embedded
|
|
194
|
+
// prior baton (fresh `wrote`, frozen content) — the content-channel rot of #62. Strip them BEFORE
|
|
195
|
+
// chunking. The blob builder is the ONE shared surface, so the claude and gemini paths both benefit.
|
|
196
|
+
const INJECTED_SENTINELS = ['wrxn-orientation', 'synapse-rules', 'recall-surface', 'reference-candidate', 'system-reminder'];
|
|
197
|
+
// ReDoS bound (#62): the phase-1 closed-block strip is ~quadratic on a pathological part (many opens, no
|
|
198
|
+
// closes). A real injected block (orientation embeds a ≤400-word baton) is a few KB; this cap sits far
|
|
199
|
+
// above that yet below the multi-second regex range, so the strip stays effectively linear.
|
|
200
|
+
const INJECTED_STRIP_MAX = 65536;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Strip hook-injected framework-context blocks from one transcript text part BEFORE chunking. Two phases:
|
|
204
|
+
* 1. every well-delimited `<tag>…</tag>` block, anywhere (multi-line via [\s\S]; nested/sequential safe);
|
|
205
|
+
* 2. a part-LEADING unclosed `<tag>…` (transcript truncated mid-block) → stripped to end-of-part.
|
|
206
|
+
* The phase-2 strip is ANCHORED to part-leading (`^\s*` — after optional whitespace, incl. the newline a
|
|
207
|
+
* phase-1 removal leaves) because real framework injections are always part-leading. A sentinel merely
|
|
208
|
+
* MENTIONED mid-prose is therefore NOT a leading match, so its trailing text survives (Finding A). PURE
|
|
209
|
+
* and FAIL-OPEN: any fault returns the input unchanged — a filter fault must NEVER break the blob. Node
|
|
210
|
+
* stdlib only. Mirrors the redactSecrets scrub discipline. (#62)
|
|
211
|
+
* @param {string} text
|
|
212
|
+
* @returns {string}
|
|
213
|
+
*/
|
|
214
|
+
function stripInjectedContext(text) {
|
|
215
|
+
try {
|
|
216
|
+
let out = String(text || '');
|
|
217
|
+
// ReDoS guard (Finding B): skip a part far larger than any real injected block — it is ordinary content
|
|
218
|
+
// (a pasted file/log) with nothing part-leading to strip, so returning it as-is can never hang.
|
|
219
|
+
if (out.length > INJECTED_STRIP_MAX) return out;
|
|
220
|
+
// Phase 1 — remove every well-delimited block anywhere (low risk; sequential + nested blocks collapse).
|
|
221
|
+
for (const tag of INJECTED_SENTINELS) {
|
|
222
|
+
out = out.replace(new RegExp(`<${tag}>[\\s\\S]*?</${tag}>`, 'g'), '');
|
|
223
|
+
}
|
|
224
|
+
// Phase 2 — remove a part-LEADING unclosed remainder to end-of-part (after phase 1, any leading injected
|
|
225
|
+
// block left dangling by truncation is part-leading). Anchored so a mid-prose mention keeps its tail.
|
|
226
|
+
for (const tag of INJECTED_SENTINELS) {
|
|
227
|
+
out = out.replace(new RegExp(`^\\s*<${tag}>[\\s\\S]*$`), '');
|
|
228
|
+
}
|
|
229
|
+
return out;
|
|
230
|
+
} catch {
|
|
231
|
+
return String(text || ''); // a filter fault never breaks the blob
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
190
235
|
/**
|
|
191
236
|
* Build a bounded plain-text blob from a Claude Code transcript (JSONL string).
|
|
192
237
|
* @param {string} jsonlText the raw transcript file contents
|
|
@@ -208,12 +253,12 @@ function buildTranscriptBlob(jsonlText) {
|
|
|
208
253
|
const c = m.content;
|
|
209
254
|
const parts = [];
|
|
210
255
|
if (typeof c === 'string') {
|
|
211
|
-
parts.push(c);
|
|
256
|
+
parts.push(stripInjectedContext(c)); // a SessionStart-injected orientation often arrives as string content
|
|
212
257
|
} else if (Array.isArray(c)) {
|
|
213
258
|
for (const p of c) {
|
|
214
259
|
if (!p || typeof p !== 'object') continue;
|
|
215
260
|
if (p.type === 'text') {
|
|
216
|
-
parts.push(p.text || '');
|
|
261
|
+
parts.push(stripInjectedContext(p.text || '')); // UserPromptSubmit sentinels prepend the user's text part
|
|
217
262
|
} else if (p.type === 'thinking') {
|
|
218
263
|
parts.push('[thinking] ' + String(p.thinking || '').slice(0, THINK_MAX));
|
|
219
264
|
} else if (p.type === 'tool_use') {
|
|
@@ -627,22 +672,31 @@ function stripPreamble(text) {
|
|
|
627
672
|
// becomes the durable baton. Pattern-based (high-signal vendor token shapes, JWTs incl. Bearer
|
|
628
673
|
// payloads, and `KEY/TOKEN/SECRET/PASSWORD=value` assignments); each match → `[REDACTED]`. Conservative
|
|
629
674
|
// by design: it never rewrites ordinary prose, only well-known credential shapes.
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
/\
|
|
675
|
+
// The ONE canonical secret-shape set — drift-pinned byte-identical to the dream / sync / harvest copies
|
|
676
|
+
// by adapter-drift-guard.test.cjs. Non-global base: redaction derives a g-flagged clone below. (Dropping
|
|
677
|
+
// the older inline \b boundaries is deliberate and fail-safe — a redactor erring broader never under-scrubs.)
|
|
678
|
+
const SECRET_PATTERNS = [
|
|
679
|
+
/AKIA[0-9A-Z]{16}/, // AWS access key id
|
|
680
|
+
/gh[pousr]_[A-Za-z0-9]{20,}/, // GitHub token (ghp_/gho_/ghu_/ghs_/ghr_); {20,} covers the 36-char + CI forms
|
|
681
|
+
/github_pat_[A-Za-z0-9_]{22,}/, // GitHub fine-grained PAT
|
|
682
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/, // Slack token
|
|
683
|
+
/sk-[A-Za-z0-9]{20,}/, // OpenAI-style secret key
|
|
684
|
+
/sk-proj-[A-Za-z0-9_-]{20,}/, // OpenAI project-scoped key (underscore form sk-… misses)
|
|
685
|
+
/AIza[0-9A-Za-z._-]{10,}/, // Google / Gemini API key
|
|
686
|
+
/sk_(?:live|test)_[A-Za-z0-9]{20,}/, // Stripe live/test secret key
|
|
687
|
+
/npm_[A-Za-z0-9]{20,}/, // npm publish / automation token
|
|
688
|
+
/\bey[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{3,}\.[A-Za-z0-9_-]{3,}\b/, // JWT (incl. Bearer payloads); the eyJ… header gates it
|
|
689
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/, // PEM block (FULL — must precede the header fallback so redaction eats the body)
|
|
690
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/, // PEM header (fallback: a lone/truncated header with no END)
|
|
691
|
+
/Bearer\s+[A-Za-z0-9._~+/=-]{20,}/, // opaque Bearer token (non-JWT)
|
|
692
|
+
/\b[A-Za-z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD)\b\s*[:=]\s*\S+/i, // KEY/TOKEN/SECRET/PASSWORD = value
|
|
644
693
|
];
|
|
645
694
|
|
|
695
|
+
// Redaction form: every shape made global so EVERY occurrence on a line is scrubbed (not just the first).
|
|
696
|
+
// Each clone PRESERVES its own flags (e.g. the /i assignment shape) and only ADDS g — so detection and
|
|
697
|
+
// redaction never diverge. String#replace resets a global regex's lastIndex per call → reuse is safe.
|
|
698
|
+
const REDACTIONS = SECRET_PATTERNS.map((re) => new RegExp(re.source, re.flags.includes('g') ? re.flags : re.flags + 'g'));
|
|
699
|
+
|
|
646
700
|
/**
|
|
647
701
|
* Redact common secret shapes from `text`, replacing each match with `[REDACTED]`. PURE. Ordinary prose
|
|
648
702
|
* is preserved verbatim — only credential-looking substrings are scrubbed.
|
|
@@ -969,7 +1023,7 @@ async function run(args, { invoke = defaultInvoke, out = process.stdout, err = p
|
|
|
969
1023
|
return 2;
|
|
970
1024
|
}
|
|
971
1025
|
const root = rootArg || findInstallRoot(path.dirname(path.resolve(file))) || process.cwd();
|
|
972
|
-
const blob = readTranscriptBlob(file);
|
|
1026
|
+
const blob = redactSecrets(readTranscriptBlob(file)); // scrub BEFORE the blob egresses to the external model — parity with runHandoff:729 / runDream:866 (#63).
|
|
973
1027
|
const config = loadConfig(root);
|
|
974
1028
|
const apiKey = loadEnv(root).GEMINI_API_KEY;
|
|
975
1029
|
const text = await synthesize({ task, prompt, blob, config, apiKey, invoke });
|
package/payload/.wrxn/sync.cjs
CHANGED
|
@@ -264,11 +264,20 @@ async function driftFromDoor(root, { transport, timeoutMs } = {}) {
|
|
|
264
264
|
// no shared kernel-lib import), exactly as findInstallRoot/flag/fail are duplicated across these files.
|
|
265
265
|
// CASE-SENSITIVE: the token shapes are case-specific.
|
|
266
266
|
const SECRET_PATTERNS = [
|
|
267
|
-
/AKIA[0-9A-Z]{16}/,
|
|
268
|
-
/gh[pousr]_[A-Za-z0-9]{
|
|
269
|
-
/
|
|
270
|
-
/
|
|
271
|
-
|
|
267
|
+
/AKIA[0-9A-Z]{16}/, // AWS access key id
|
|
268
|
+
/gh[pousr]_[A-Za-z0-9]{20,}/, // GitHub token (ghp_/gho_/ghu_/ghs_/ghr_); {20,} covers the 36-char + CI forms
|
|
269
|
+
/github_pat_[A-Za-z0-9_]{22,}/, // GitHub fine-grained PAT
|
|
270
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/, // Slack token
|
|
271
|
+
/sk-[A-Za-z0-9]{20,}/, // OpenAI-style secret key
|
|
272
|
+
/sk-proj-[A-Za-z0-9_-]{20,}/, // OpenAI project-scoped key (underscore form sk-… misses)
|
|
273
|
+
/AIza[0-9A-Za-z._-]{10,}/, // Google / Gemini API key
|
|
274
|
+
/sk_(?:live|test)_[A-Za-z0-9]{20,}/, // Stripe live/test secret key
|
|
275
|
+
/npm_[A-Za-z0-9]{20,}/, // npm publish / automation token
|
|
276
|
+
/\bey[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{3,}\.[A-Za-z0-9_-]{3,}\b/, // JWT (incl. Bearer payloads); the eyJ… header gates it
|
|
277
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/, // PEM block (FULL — must precede the header fallback so redaction eats the body)
|
|
278
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/, // PEM header (fallback: a lone/truncated header with no END)
|
|
279
|
+
/Bearer\s+[A-Za-z0-9._~+/=-]{20,}/, // opaque Bearer token (non-JWT)
|
|
280
|
+
/\b[A-Za-z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD)\b\s*[:=]\s*\S+/i, // KEY/TOKEN/SECRET/PASSWORD = value
|
|
272
281
|
];
|
|
273
282
|
|
|
274
283
|
function secretScan(text) {
|