@node9/proxy 1.67.2 → 1.67.4

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/dist/cli.js CHANGED
@@ -2633,7 +2633,7 @@ function* stringValues(obj, depth = 0) {
2633
2633
  }
2634
2634
  for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
2635
2635
  }
2636
- var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto3, MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, INTERP_LEADING_TARGET, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_HEREDOC_OPS, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, VERDICT_RANK, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE, ENGINE_VERSION;
2636
+ var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto3, MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, DLP_SCAN_LIMITS, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, INTERP_LEADING_TARGET, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_HEREDOC_OPS, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, VERDICT_RANK, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE, ENGINE_VERSION;
2637
2637
  var init_dist = __esm({
2638
2638
  "packages/policy-engine/dist/index.mjs"() {
2639
2639
  "use strict";
@@ -3165,6 +3165,13 @@ var init_dist = __esm({
3165
3165
  MAX_DEPTH = 5;
3166
3166
  MAX_STRING_BYTES = 1e5;
3167
3167
  MAX_JSON_PARSE_BYTES = 1e4;
3168
+ DLP_SCAN_LIMITS = {
3169
+ /** Max characters examined per individual string field; the remainder of an
3170
+ * oversized string is NOT scanned. */
3171
+ maxStringBytes: MAX_STRING_BYTES,
3172
+ /** Max nesting depth walked; anything deeper is NOT scanned. */
3173
+ maxDepth: MAX_DEPTH
3174
+ };
3168
3175
  MAX_REGEX_LENGTH = 256;
3169
3176
  REGEX_CACHE_MAX = 500;
3170
3177
  regexCache = /* @__PURE__ */ new Map();
@@ -3202,9 +3209,34 @@ var init_dist = __esm({
3202
3209
  "vi",
3203
3210
  "emacs",
3204
3211
  "code",
3205
- "type"
3212
+ "type",
3213
+ // — the 22 that were missing —
3214
+ "grep",
3215
+ "egrep",
3216
+ "fgrep",
3217
+ "rg",
3218
+ "ag",
3219
+ "ack",
3220
+ "awk",
3221
+ "gawk",
3222
+ "sed",
3223
+ "cut",
3224
+ "tr",
3225
+ "jq",
3226
+ "yq",
3227
+ "od",
3228
+ "xxd",
3229
+ "hexdump",
3230
+ "strings",
3231
+ "sort",
3232
+ "uniq",
3233
+ "tac",
3234
+ "nl",
3235
+ "dd"
3206
3236
  ]);
3207
- FS_OP_PRESCREEN_RE = /(?:^|[\s|;&(`\n])(?:rm|cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\b/;
3237
+ FS_OP_PRESCREEN_RE = new RegExp(
3238
+ `(?:^|[\\s|;&(\`\\n])(?:rm|${[...FS_READ_TOOLS].map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`
3239
+ );
3208
3240
  HOME_CACHE_ALLOWLIST = [
3209
3241
  ".cache",
3210
3242
  ".npm/_npx",
@@ -3243,9 +3275,37 @@ var init_dist = __esm({
3243
3275
  // for the canonical test-asserted contract.
3244
3276
  rule: "shield:project-jail:block-read-env",
3245
3277
  reason: "Reading .env files is blocked by project-jail shield",
3246
- match: (p) => /(?:^|[\\/])\.env(?:\.(?:local|production|staging|development|production\.local|staging\.local|development\.local))?$/i.test(
3247
- p
3248
- )
3278
+ // Structural, not a list. The previous form enumerated seven suffixes and
3279
+ // anchored on `$`, so `.env.prod`, `.env.ci` and `.env.local.bak` — all
3280
+ // gitignored, all routinely holding real secrets — were never covered. A
3281
+ // hand-written list of what to protect is only ever as complete as the day
3282
+ // it was typed; this says "`.env` plus any suffix chain" and then names the
3283
+ // exceptions, which is the direction that fails safe.
3284
+ //
3285
+ // \.env the segment itself
3286
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
3287
+ // files. Without it a flat suffix class swallows both.
3288
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
3289
+ // [\w.-]*$ any suffix chain. Flat class, no nested quantifier —
3290
+ // `(\.[\w-]+)*` reads the same but is rejected by
3291
+ // safe-regex2, and this pattern runs on the hook hot path.
3292
+ //
3293
+ // The two exclusions are NOT the same shape, because the words do not mean
3294
+ // the same thing:
3295
+ //
3296
+ // (?!\.(?:example|sample|template)\b) — "this file is a fixture", and it
3297
+ // stays a fixture whatever follows, so `.env.example.md` is allowed too.
3298
+ // These are checked into git by convention: already public, so blocking
3299
+ // them buys nothing and costs the most common legitimate agent read.
3300
+ //
3301
+ // (?!\.test$) — anchored, because `test` names an ENVIRONMENT, not a
3302
+ // fixture. `.env.test` is the committed template and stays allowed, but
3303
+ // `.env.test.local` is gitignored by the `.env*.local` convention and
3304
+ // holds real values, so it must block. Using `\b` here — the obvious
3305
+ // symmetry — silently exempts every `.env.test.*` file.
3306
+ //
3307
+ // shields.test.ts:983-995 is the canonical contract; keep both in step.
3308
+ match: (p) => /(?:^|[\\/])\.env(?![\w-])(?!\.(?:example|sample|template)\b)(?!\.test$)[\w.-]*$/i.test(p)
3249
3309
  },
3250
3310
  {
3251
3311
  // verdict: 'review' (not 'block') is a deliberate design choice
@@ -4403,7 +4463,7 @@ var init_dist = __esm({
4403
4463
  REALTIME_PII_PATTERNS = ["SSN", "Credit Card"];
4404
4464
  MAX_PII_SCAN_BYTES = 1e5;
4405
4465
  LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
4406
- CANONICAL_EXTRACTOR_VERSION = "canonical-v8";
4466
+ CANONICAL_EXTRACTOR_VERSION = "canonical-v9";
4407
4467
  DEDUPE_PREVIEW_LEN = 120;
4408
4468
  TERMINAL_ESCAPE_RE = // eslint-disable-next-line no-control-regex
4409
4469
  /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
@@ -49460,6 +49520,14 @@ function atLeastConfidence(c, min) {
49460
49520
  function sanitize3(value) {
49461
49521
  return value.replace(/[\x00-\x1F\x7F]/g, "");
49462
49522
  }
49523
+ function scanCoveredEverything(value, depth = 0) {
49524
+ if (value === null || value === void 0) return true;
49525
+ if (typeof value === "string") return value.length <= DLP_SCAN_LIMITS.maxStringBytes;
49526
+ if (typeof value !== "object") return true;
49527
+ if (depth >= DLP_SCAN_LIMITS.maxDepth) return false;
49528
+ const children = Array.isArray(value) ? value : Object.values(value);
49529
+ return children.every((child) => scanCoveredEverything(child, depth + 1));
49530
+ }
49463
49531
  function buildArgsField(rawInput) {
49464
49532
  let hashed = {};
49465
49533
  try {
@@ -49469,6 +49537,7 @@ function buildArgsField(rawInput) {
49469
49537
  try {
49470
49538
  const hit = scanArgs(rawInput);
49471
49539
  if (hit) return { ...hashed, dlpPattern: hit.patternName, dlpSample: hit.redactedSample };
49540
+ if (!scanCoveredEverything(rawInput)) return { ...hashed, argsUnscanned: true };
49472
49541
  return { args: JSON.parse(redactSecrets(JSON.stringify(rawInput))) };
49473
49542
  } catch {
49474
49543
  return hashed;
package/dist/cli.mjs CHANGED
@@ -2643,7 +2643,7 @@ function* stringValues(obj, depth = 0) {
2643
2643
  }
2644
2644
  for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
2645
2645
  }
2646
- var MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, INTERP_LEADING_TARGET, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_HEREDOC_OPS, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, VERDICT_RANK, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE, ENGINE_VERSION;
2646
+ var MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, DLP_SCAN_LIMITS, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, INTERP_LEADING_TARGET, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_HEREDOC_OPS, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, VERDICT_RANK, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE, ENGINE_VERSION;
2647
2647
  var init_dist = __esm({
2648
2648
  "packages/policy-engine/dist/index.mjs"() {
2649
2649
  "use strict";
@@ -3169,6 +3169,13 @@ var init_dist = __esm({
3169
3169
  MAX_DEPTH = 5;
3170
3170
  MAX_STRING_BYTES = 1e5;
3171
3171
  MAX_JSON_PARSE_BYTES = 1e4;
3172
+ DLP_SCAN_LIMITS = {
3173
+ /** Max characters examined per individual string field; the remainder of an
3174
+ * oversized string is NOT scanned. */
3175
+ maxStringBytes: MAX_STRING_BYTES,
3176
+ /** Max nesting depth walked; anything deeper is NOT scanned. */
3177
+ maxDepth: MAX_DEPTH
3178
+ };
3172
3179
  MAX_REGEX_LENGTH = 256;
3173
3180
  REGEX_CACHE_MAX = 500;
3174
3181
  regexCache = /* @__PURE__ */ new Map();
@@ -3206,9 +3213,34 @@ var init_dist = __esm({
3206
3213
  "vi",
3207
3214
  "emacs",
3208
3215
  "code",
3209
- "type"
3216
+ "type",
3217
+ // — the 22 that were missing —
3218
+ "grep",
3219
+ "egrep",
3220
+ "fgrep",
3221
+ "rg",
3222
+ "ag",
3223
+ "ack",
3224
+ "awk",
3225
+ "gawk",
3226
+ "sed",
3227
+ "cut",
3228
+ "tr",
3229
+ "jq",
3230
+ "yq",
3231
+ "od",
3232
+ "xxd",
3233
+ "hexdump",
3234
+ "strings",
3235
+ "sort",
3236
+ "uniq",
3237
+ "tac",
3238
+ "nl",
3239
+ "dd"
3210
3240
  ]);
3211
- FS_OP_PRESCREEN_RE = /(?:^|[\s|;&(`\n])(?:rm|cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\b/;
3241
+ FS_OP_PRESCREEN_RE = new RegExp(
3242
+ `(?:^|[\\s|;&(\`\\n])(?:rm|${[...FS_READ_TOOLS].map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`
3243
+ );
3212
3244
  HOME_CACHE_ALLOWLIST = [
3213
3245
  ".cache",
3214
3246
  ".npm/_npx",
@@ -3247,9 +3279,37 @@ var init_dist = __esm({
3247
3279
  // for the canonical test-asserted contract.
3248
3280
  rule: "shield:project-jail:block-read-env",
3249
3281
  reason: "Reading .env files is blocked by project-jail shield",
3250
- match: (p) => /(?:^|[\\/])\.env(?:\.(?:local|production|staging|development|production\.local|staging\.local|development\.local))?$/i.test(
3251
- p
3252
- )
3282
+ // Structural, not a list. The previous form enumerated seven suffixes and
3283
+ // anchored on `$`, so `.env.prod`, `.env.ci` and `.env.local.bak` — all
3284
+ // gitignored, all routinely holding real secrets — were never covered. A
3285
+ // hand-written list of what to protect is only ever as complete as the day
3286
+ // it was typed; this says "`.env` plus any suffix chain" and then names the
3287
+ // exceptions, which is the direction that fails safe.
3288
+ //
3289
+ // \.env the segment itself
3290
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
3291
+ // files. Without it a flat suffix class swallows both.
3292
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
3293
+ // [\w.-]*$ any suffix chain. Flat class, no nested quantifier —
3294
+ // `(\.[\w-]+)*` reads the same but is rejected by
3295
+ // safe-regex2, and this pattern runs on the hook hot path.
3296
+ //
3297
+ // The two exclusions are NOT the same shape, because the words do not mean
3298
+ // the same thing:
3299
+ //
3300
+ // (?!\.(?:example|sample|template)\b) — "this file is a fixture", and it
3301
+ // stays a fixture whatever follows, so `.env.example.md` is allowed too.
3302
+ // These are checked into git by convention: already public, so blocking
3303
+ // them buys nothing and costs the most common legitimate agent read.
3304
+ //
3305
+ // (?!\.test$) — anchored, because `test` names an ENVIRONMENT, not a
3306
+ // fixture. `.env.test` is the committed template and stays allowed, but
3307
+ // `.env.test.local` is gitignored by the `.env*.local` convention and
3308
+ // holds real values, so it must block. Using `\b` here — the obvious
3309
+ // symmetry — silently exempts every `.env.test.*` file.
3310
+ //
3311
+ // shields.test.ts:983-995 is the canonical contract; keep both in step.
3312
+ match: (p) => /(?:^|[\\/])\.env(?![\w-])(?!\.(?:example|sample|template)\b)(?!\.test$)[\w.-]*$/i.test(p)
3253
3313
  },
3254
3314
  {
3255
3315
  // verdict: 'review' (not 'block') is a deliberate design choice
@@ -4407,7 +4467,7 @@ var init_dist = __esm({
4407
4467
  REALTIME_PII_PATTERNS = ["SSN", "Credit Card"];
4408
4468
  MAX_PII_SCAN_BYTES = 1e5;
4409
4469
  LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
4410
- CANONICAL_EXTRACTOR_VERSION = "canonical-v8";
4470
+ CANONICAL_EXTRACTOR_VERSION = "canonical-v9";
4411
4471
  DEDUPE_PREVIEW_LEN = 120;
4412
4472
  TERMINAL_ESCAPE_RE = // eslint-disable-next-line no-control-regex
4413
4473
  /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
@@ -49453,6 +49513,14 @@ function atLeastConfidence(c, min) {
49453
49513
  function sanitize3(value) {
49454
49514
  return value.replace(/[\x00-\x1F\x7F]/g, "");
49455
49515
  }
49516
+ function scanCoveredEverything(value, depth = 0) {
49517
+ if (value === null || value === void 0) return true;
49518
+ if (typeof value === "string") return value.length <= DLP_SCAN_LIMITS.maxStringBytes;
49519
+ if (typeof value !== "object") return true;
49520
+ if (depth >= DLP_SCAN_LIMITS.maxDepth) return false;
49521
+ const children = Array.isArray(value) ? value : Object.values(value);
49522
+ return children.every((child) => scanCoveredEverything(child, depth + 1));
49523
+ }
49456
49524
  function buildArgsField(rawInput) {
49457
49525
  let hashed = {};
49458
49526
  try {
@@ -49462,6 +49530,7 @@ function buildArgsField(rawInput) {
49462
49530
  try {
49463
49531
  const hit = scanArgs(rawInput);
49464
49532
  if (hit) return { ...hashed, dlpPattern: hit.patternName, dlpSample: hit.redactedSample };
49533
+ if (!scanCoveredEverything(rawInput)) return { ...hashed, argsUnscanned: true };
49465
49534
  return { args: JSON.parse(redactSecrets(JSON.stringify(rawInput))) };
49466
49535
  } catch {
49467
49536
  return hashed;
@@ -1239,9 +1239,34 @@ var init_dist = __esm({
1239
1239
  "vi",
1240
1240
  "emacs",
1241
1241
  "code",
1242
- "type"
1242
+ "type",
1243
+ // — the 22 that were missing —
1244
+ "grep",
1245
+ "egrep",
1246
+ "fgrep",
1247
+ "rg",
1248
+ "ag",
1249
+ "ack",
1250
+ "awk",
1251
+ "gawk",
1252
+ "sed",
1253
+ "cut",
1254
+ "tr",
1255
+ "jq",
1256
+ "yq",
1257
+ "od",
1258
+ "xxd",
1259
+ "hexdump",
1260
+ "strings",
1261
+ "sort",
1262
+ "uniq",
1263
+ "tac",
1264
+ "nl",
1265
+ "dd"
1243
1266
  ]);
1244
- FS_OP_PRESCREEN_RE = /(?:^|[\s|;&(`\n])(?:rm|cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\b/;
1267
+ FS_OP_PRESCREEN_RE = new RegExp(
1268
+ `(?:^|[\\s|;&(\`\\n])(?:rm|${[...FS_READ_TOOLS].map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`
1269
+ );
1245
1270
  HOME_CACHE_ALLOWLIST = [
1246
1271
  ".cache",
1247
1272
  ".npm/_npx",
@@ -1280,9 +1305,37 @@ var init_dist = __esm({
1280
1305
  // for the canonical test-asserted contract.
1281
1306
  rule: "shield:project-jail:block-read-env",
1282
1307
  reason: "Reading .env files is blocked by project-jail shield",
1283
- match: (p) => /(?:^|[\\/])\.env(?:\.(?:local|production|staging|development|production\.local|staging\.local|development\.local))?$/i.test(
1284
- p
1285
- )
1308
+ // Structural, not a list. The previous form enumerated seven suffixes and
1309
+ // anchored on `$`, so `.env.prod`, `.env.ci` and `.env.local.bak` — all
1310
+ // gitignored, all routinely holding real secrets — were never covered. A
1311
+ // hand-written list of what to protect is only ever as complete as the day
1312
+ // it was typed; this says "`.env` plus any suffix chain" and then names the
1313
+ // exceptions, which is the direction that fails safe.
1314
+ //
1315
+ // \.env the segment itself
1316
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
1317
+ // files. Without it a flat suffix class swallows both.
1318
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
1319
+ // [\w.-]*$ any suffix chain. Flat class, no nested quantifier —
1320
+ // `(\.[\w-]+)*` reads the same but is rejected by
1321
+ // safe-regex2, and this pattern runs on the hook hot path.
1322
+ //
1323
+ // The two exclusions are NOT the same shape, because the words do not mean
1324
+ // the same thing:
1325
+ //
1326
+ // (?!\.(?:example|sample|template)\b) — "this file is a fixture", and it
1327
+ // stays a fixture whatever follows, so `.env.example.md` is allowed too.
1328
+ // These are checked into git by convention: already public, so blocking
1329
+ // them buys nothing and costs the most common legitimate agent read.
1330
+ //
1331
+ // (?!\.test$) — anchored, because `test` names an ENVIRONMENT, not a
1332
+ // fixture. `.env.test` is the committed template and stays allowed, but
1333
+ // `.env.test.local` is gitignored by the `.env*.local` convention and
1334
+ // holds real values, so it must block. Using `\b` here — the obvious
1335
+ // symmetry — silently exempts every `.env.test.*` file.
1336
+ //
1337
+ // shields.test.ts:983-995 is the canonical contract; keep both in step.
1338
+ match: (p) => /(?:^|[\\/])\.env(?![\w-])(?!\.(?:example|sample|template)\b)(?!\.test$)[\w.-]*$/i.test(p)
1286
1339
  },
1287
1340
  {
1288
1341
  // verdict: 'review' (not 'block') is a deliberate design choice
package/dist/index.js CHANGED
@@ -1371,9 +1371,34 @@ var FS_READ_TOOLS = /* @__PURE__ */ new Set([
1371
1371
  "vi",
1372
1372
  "emacs",
1373
1373
  "code",
1374
- "type"
1374
+ "type",
1375
+ // — the 22 that were missing —
1376
+ "grep",
1377
+ "egrep",
1378
+ "fgrep",
1379
+ "rg",
1380
+ "ag",
1381
+ "ack",
1382
+ "awk",
1383
+ "gawk",
1384
+ "sed",
1385
+ "cut",
1386
+ "tr",
1387
+ "jq",
1388
+ "yq",
1389
+ "od",
1390
+ "xxd",
1391
+ "hexdump",
1392
+ "strings",
1393
+ "sort",
1394
+ "uniq",
1395
+ "tac",
1396
+ "nl",
1397
+ "dd"
1375
1398
  ]);
1376
- var FS_OP_PRESCREEN_RE = /(?:^|[\s|;&(`\n])(?:rm|cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\b/;
1399
+ var FS_OP_PRESCREEN_RE = new RegExp(
1400
+ `(?:^|[\\s|;&(\`\\n])(?:rm|${[...FS_READ_TOOLS].map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`
1401
+ );
1377
1402
  var HOME_CACHE_ALLOWLIST = [
1378
1403
  ".cache",
1379
1404
  ".npm/_npx",
@@ -1412,9 +1437,37 @@ var SENSITIVE_PATH_RULES = [
1412
1437
  // for the canonical test-asserted contract.
1413
1438
  rule: "shield:project-jail:block-read-env",
1414
1439
  reason: "Reading .env files is blocked by project-jail shield",
1415
- match: (p) => /(?:^|[\\/])\.env(?:\.(?:local|production|staging|development|production\.local|staging\.local|development\.local))?$/i.test(
1416
- p
1417
- )
1440
+ // Structural, not a list. The previous form enumerated seven suffixes and
1441
+ // anchored on `$`, so `.env.prod`, `.env.ci` and `.env.local.bak` — all
1442
+ // gitignored, all routinely holding real secrets — were never covered. A
1443
+ // hand-written list of what to protect is only ever as complete as the day
1444
+ // it was typed; this says "`.env` plus any suffix chain" and then names the
1445
+ // exceptions, which is the direction that fails safe.
1446
+ //
1447
+ // \.env the segment itself
1448
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
1449
+ // files. Without it a flat suffix class swallows both.
1450
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
1451
+ // [\w.-]*$ any suffix chain. Flat class, no nested quantifier —
1452
+ // `(\.[\w-]+)*` reads the same but is rejected by
1453
+ // safe-regex2, and this pattern runs on the hook hot path.
1454
+ //
1455
+ // The two exclusions are NOT the same shape, because the words do not mean
1456
+ // the same thing:
1457
+ //
1458
+ // (?!\.(?:example|sample|template)\b) — "this file is a fixture", and it
1459
+ // stays a fixture whatever follows, so `.env.example.md` is allowed too.
1460
+ // These are checked into git by convention: already public, so blocking
1461
+ // them buys nothing and costs the most common legitimate agent read.
1462
+ //
1463
+ // (?!\.test$) — anchored, because `test` names an ENVIRONMENT, not a
1464
+ // fixture. `.env.test` is the committed template and stays allowed, but
1465
+ // `.env.test.local` is gitignored by the `.env*.local` convention and
1466
+ // holds real values, so it must block. Using `\b` here — the obvious
1467
+ // symmetry — silently exempts every `.env.test.*` file.
1468
+ //
1469
+ // shields.test.ts:983-995 is the canonical contract; keep both in step.
1470
+ match: (p) => /(?:^|[\\/])\.env(?![\w-])(?!\.(?:example|sample|template)\b)(?!\.test$)[\w.-]*$/i.test(p)
1418
1471
  },
1419
1472
  {
1420
1473
  // verdict: 'review' (not 'block') is a deliberate design choice
package/dist/index.mjs CHANGED
@@ -1341,9 +1341,34 @@ var FS_READ_TOOLS = /* @__PURE__ */ new Set([
1341
1341
  "vi",
1342
1342
  "emacs",
1343
1343
  "code",
1344
- "type"
1344
+ "type",
1345
+ // — the 22 that were missing —
1346
+ "grep",
1347
+ "egrep",
1348
+ "fgrep",
1349
+ "rg",
1350
+ "ag",
1351
+ "ack",
1352
+ "awk",
1353
+ "gawk",
1354
+ "sed",
1355
+ "cut",
1356
+ "tr",
1357
+ "jq",
1358
+ "yq",
1359
+ "od",
1360
+ "xxd",
1361
+ "hexdump",
1362
+ "strings",
1363
+ "sort",
1364
+ "uniq",
1365
+ "tac",
1366
+ "nl",
1367
+ "dd"
1345
1368
  ]);
1346
- var FS_OP_PRESCREEN_RE = /(?:^|[\s|;&(`\n])(?:rm|cat|less|head|tail|bat|more|open|print|nano|vim|vi|emacs|code|type)\b/;
1369
+ var FS_OP_PRESCREEN_RE = new RegExp(
1370
+ `(?:^|[\\s|;&(\`\\n])(?:rm|${[...FS_READ_TOOLS].map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`
1371
+ );
1347
1372
  var HOME_CACHE_ALLOWLIST = [
1348
1373
  ".cache",
1349
1374
  ".npm/_npx",
@@ -1382,9 +1407,37 @@ var SENSITIVE_PATH_RULES = [
1382
1407
  // for the canonical test-asserted contract.
1383
1408
  rule: "shield:project-jail:block-read-env",
1384
1409
  reason: "Reading .env files is blocked by project-jail shield",
1385
- match: (p) => /(?:^|[\\/])\.env(?:\.(?:local|production|staging|development|production\.local|staging\.local|development\.local))?$/i.test(
1386
- p
1387
- )
1410
+ // Structural, not a list. The previous form enumerated seven suffixes and
1411
+ // anchored on `$`, so `.env.prod`, `.env.ci` and `.env.local.bak` — all
1412
+ // gitignored, all routinely holding real secrets — were never covered. A
1413
+ // hand-written list of what to protect is only ever as complete as the day
1414
+ // it was typed; this says "`.env` plus any suffix chain" and then names the
1415
+ // exceptions, which is the direction that fails safe.
1416
+ //
1417
+ // \.env the segment itself
1418
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
1419
+ // files. Without it a flat suffix class swallows both.
1420
+ // (?![\w-]) a boundary, so `.environment` and `.envrc` are NOT .env
1421
+ // [\w.-]*$ any suffix chain. Flat class, no nested quantifier —
1422
+ // `(\.[\w-]+)*` reads the same but is rejected by
1423
+ // safe-regex2, and this pattern runs on the hook hot path.
1424
+ //
1425
+ // The two exclusions are NOT the same shape, because the words do not mean
1426
+ // the same thing:
1427
+ //
1428
+ // (?!\.(?:example|sample|template)\b) — "this file is a fixture", and it
1429
+ // stays a fixture whatever follows, so `.env.example.md` is allowed too.
1430
+ // These are checked into git by convention: already public, so blocking
1431
+ // them buys nothing and costs the most common legitimate agent read.
1432
+ //
1433
+ // (?!\.test$) — anchored, because `test` names an ENVIRONMENT, not a
1434
+ // fixture. `.env.test` is the committed template and stays allowed, but
1435
+ // `.env.test.local` is gitignored by the `.env*.local` convention and
1436
+ // holds real values, so it must block. Using `\b` here — the obvious
1437
+ // symmetry — silently exempts every `.env.test.*` file.
1438
+ //
1439
+ // shields.test.ts:983-995 is the canonical contract; keep both in step.
1440
+ match: (p) => /(?:^|[\\/])\.env(?![\w-])(?!\.(?:example|sample|template)\b)(?!\.test$)[\w.-]*$/i.test(p)
1388
1441
  },
1389
1442
  {
1390
1443
  // verdict: 'review' (not 'block') is a deliberate design choice
package/dist/scan-ink.mjs CHANGED
@@ -818,6 +818,48 @@ function assertBuiltinPatternsAreSafe() {
818
818
  assertBuiltinPatternsAreSafe();
819
819
  var { syntax } = mvdanSh;
820
820
  var sharedParser = syntax.NewParser();
821
+ var FS_READ_TOOLS = /* @__PURE__ */ new Set([
822
+ "cat",
823
+ "less",
824
+ "head",
825
+ "tail",
826
+ "bat",
827
+ "more",
828
+ "open",
829
+ "print",
830
+ "nano",
831
+ "vim",
832
+ "vi",
833
+ "emacs",
834
+ "code",
835
+ "type",
836
+ // — the 22 that were missing —
837
+ "grep",
838
+ "egrep",
839
+ "fgrep",
840
+ "rg",
841
+ "ag",
842
+ "ack",
843
+ "awk",
844
+ "gawk",
845
+ "sed",
846
+ "cut",
847
+ "tr",
848
+ "jq",
849
+ "yq",
850
+ "od",
851
+ "xxd",
852
+ "hexdump",
853
+ "strings",
854
+ "sort",
855
+ "uniq",
856
+ "tac",
857
+ "nl",
858
+ "dd"
859
+ ]);
860
+ var FS_OP_PRESCREEN_RE = new RegExp(
861
+ `(?:^|[\\s|;&(\`\\n])(?:rm|${[...FS_READ_TOOLS].map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`
862
+ );
821
863
  function deriveRedirOp(sample) {
822
864
  try {
823
865
  const f = sharedParser.Parse(sample, "cmd");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/proxy",
3
- "version": "1.67.2",
3
+ "version": "1.67.4",
4
4
  "description": "The Sudo Command for AI Agents. Execution Security for Claude Code, Codex, Gemini, Cursor, Opencode, Pi, and any MCP server.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",