@node9/policy-engine 2.14.1 → 2.14.2

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/index.d.mts CHANGED
@@ -647,6 +647,27 @@ declare function validateRegex(pattern: string): string | null;
647
647
  */
648
648
  declare function getCompiledRegex(pattern: string, flags?: string): RegExp | null;
649
649
 
650
+ /** See TERMINAL_ESCAPE_RE. Keeps tab, newline and carriage return. */
651
+ declare function stripTerminalEscapes(s: string): string;
652
+ /** See CONTROL_CHAR_RE. Removes every C0 control and DEL, whitespace included. */
653
+ declare function stripControlChars(s: string): string;
654
+ /**
655
+ * One safe line, for any string that came from outside this process before it
656
+ * reaches a terminal or a log file.
657
+ *
658
+ * node9's terminal output IS the user's trust signal: a "connected and
659
+ * governed" line is what tells someone the machine is protected. A response
660
+ * field carrying CR plus SGR codes can paint a line that looks exactly like
661
+ * one of ours, and a newline in a value written to hook-debug.log forges a
662
+ * second journal entry. So: escape sequences removed, all whitespace collapsed
663
+ * to single spaces (one value can never become two lines), and a length cap so
664
+ * a hostile or broken peer cannot flood the log.
665
+ *
666
+ * Accepts unknown because most call sites hold a caught `error` or an optional
667
+ * response field.
668
+ */
669
+ declare function safeMessage(value: unknown, max?: number): string;
670
+
650
671
  interface ShieldDefinition {
651
672
  name: string;
652
673
  description: string;
@@ -1058,6 +1079,11 @@ interface BlastSummary {
1058
1079
  /** Number of env vars flagged as credentials. No keys included. */
1059
1080
  envExposureCount: number;
1060
1081
  }
1082
+ /**
1083
+ * Longest path `truncateBlastPath` will look at, tail-anchored. PATH_MAX is
1084
+ * 4096 on Linux, so anything past this is not a path we could have read.
1085
+ */
1086
+ declare const MAX_BLAST_PATH = 4096;
1061
1087
  /**
1062
1088
  * Sanitise a sensitive path for transmission. Keeps only the trailing 2
1063
1089
  * segments — enough to identify the kind of file ("~/.aws/credentials"
@@ -1306,7 +1332,7 @@ declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v15";
1306
1332
  * files changed, this hash must change too, and you must consciously
1307
1333
  * decide whether to bump CANONICAL_EXTRACTOR_VERSION."
1308
1334
  */
1309
- declare const CANONICAL_EXTRACTOR_HASH = "5dad4c8f07121f6c";
1335
+ declare const CANONICAL_EXTRACTOR_HASH = "2823cd6a54a1fca7";
1310
1336
  declare function extractCanonicalFindings(call: ToolCallEntry, ctx: ExtractContext): CanonicalFinding[];
1311
1337
  declare function extractSessionLevelFindings(calls: ReadonlyArray<SessionToolCall>, ctx: SessionExtractContext): CanonicalFinding[];
1312
1338
  /**
@@ -1426,4 +1452,4 @@ declare function ssrfDestinationFloor(toolName: string, args: unknown, opts?: {
1426
1452
  /** Engine version stamped on audit entries for future drift detection. */
1427
1453
  declare const ENGINE_VERSION = "1.4.0";
1428
1454
 
1429
- export { AST_FS_REGEX_RULES, type AuditEntryForClassify, BASH_TOOL_NAMES, BUILTIN_SHIELDS, type BlastEnvFinding, type BlastFinding, type BlastResult, type BlastSummary, CANARY_MIN_LENGTH, CANONICAL_EXTRACTOR_HASH, CANONICAL_EXTRACTOR_VERSION, COMMAND_WRAPPERS, COPY_VERBS, COST_PER_LOOP_ITER_USD, type CanaryHit, type CanaryValue, type CanaryView, type CanonicalAgent, type CanonicalFinding, type CanonicalFindingType, type CanonicalSourceType, DEFAULT_EGRESS_ALLOWLIST, DESTINATION_ARGS, DESTRUCTIVE_OP_RE, DLP_PATTERNS, DLP_SCAN_LIMITS, type DlpMatch, ENGINE_VERSION, type EgressPolicy, type EgressVerdict, type ExtractContext, FILE_TOOLS, FLAGS_WITH_VALUES, FS_READ_TOOLS, type FsOpVerdict, type InjectionConfidence, type InjectionContext, type InjectionMatch, LONG_OUTPUT_THRESHOLD_BYTES, LOOP_MAX_RECORDS, LOOP_THRESHOLD_FOR_WASTE, type LoopWindowEvaluation, NET_BINARIES, PATTERN_VERB_NAMES, PRIVILEGE_ESCALATION_RE, type PiiPattern, type PipeChainAnalysis, type PolicyConfig, type PolicyContext, type PolicyHostHooks, type PolicyVerdict, type PositionedArg, type ProvenanceLookup, type ProvenanceTrust, REALTIME_PII_PATTERNS, type RiskMetadata, SCAN_SIGNAL_WEIGHTS, SENSITIVE_PATH_RE, SENSITIVE_PATH_REGEXES, SSRF_MAX_HOST, type ScanFinding, type ScanSignals, type ScanSummary, type ScoreTier, type SessionExtractContext, type SessionToolCall, type Severity, type ShellCommandAnalysis, type ShellDestToken, type ShellDestination, type ShieldDefinition, type ShieldOverrides, type ShieldVerdict, type SmartCondition, type SmartRule, type SsrfFloorOptions, type SsrfMatch, type SsrfTier, type SsrfVerdict, type ToolCallEntry, type ToolCallRecord, analyzeFsOperation, analyzePipeChain, analyzeShellCommand, checkDangerousSql, classifyAuditEntry, classifyRuleSeverity, classifyScanSignal, classifySsrf, computeAgentDeviceScore, computeArgsHash, computeBlendedSecurityScore, computeScanScore, computeSecurityScore, dedupeCanonicalFindings, detectArgsPii, detectDangerousEval, detectDangerousShellExec, detectInlineExec, detectPii, evaluateEgress, evaluateLoopWindow, evaluatePolicy, evaluateSmartConditions, extractAllSshHosts, extractCanonicalFindings, extractNetworkTargets, extractPositionalArgs, extractSessionLevelFindings, extractShellDestTokens, extractShellDestinations, fileOperandFlagsOf, getCompiledRegex, getNestedValue, hostMatches, isBashTool, isIgnoredTool, isPrivateHost, isProtectedHomePath, isShellShapedTool, isShieldVerdict, isStrictGatedTier, matchCanary, matchCanaryArgs, matchSensitivePath, matchesPattern, narrativeRuleLabel, normalizeCommandForPolicy, normalizeIpLiteral, parseAllSshHostsFromCommand, parseDestHost, patternShapeOf, positionedArgs, previewArgs, redactText, resolvePinned, sampleCopyCommand, scanArgs, scanInjection, scanText, sensitivePathMatch, ssrfDestinationFloor, ssrfFloor, ssrfReason, summarizeBlast, summarizeScan, toScanFinding, toolMatchesRule, truncateBlastPath, unwrapCommandHead, validateOverrides, validateRegex, validateShieldDefinition };
1455
+ export { AST_FS_REGEX_RULES, type AuditEntryForClassify, BASH_TOOL_NAMES, BUILTIN_SHIELDS, type BlastEnvFinding, type BlastFinding, type BlastResult, type BlastSummary, CANARY_MIN_LENGTH, CANONICAL_EXTRACTOR_HASH, CANONICAL_EXTRACTOR_VERSION, COMMAND_WRAPPERS, COPY_VERBS, COST_PER_LOOP_ITER_USD, type CanaryHit, type CanaryValue, type CanaryView, type CanonicalAgent, type CanonicalFinding, type CanonicalFindingType, type CanonicalSourceType, DEFAULT_EGRESS_ALLOWLIST, DESTINATION_ARGS, DESTRUCTIVE_OP_RE, DLP_PATTERNS, DLP_SCAN_LIMITS, type DlpMatch, ENGINE_VERSION, type EgressPolicy, type EgressVerdict, type ExtractContext, FILE_TOOLS, FLAGS_WITH_VALUES, FS_READ_TOOLS, type FsOpVerdict, type InjectionConfidence, type InjectionContext, type InjectionMatch, LONG_OUTPUT_THRESHOLD_BYTES, LOOP_MAX_RECORDS, LOOP_THRESHOLD_FOR_WASTE, type LoopWindowEvaluation, MAX_BLAST_PATH, NET_BINARIES, PATTERN_VERB_NAMES, PRIVILEGE_ESCALATION_RE, type PiiPattern, type PipeChainAnalysis, type PolicyConfig, type PolicyContext, type PolicyHostHooks, type PolicyVerdict, type PositionedArg, type ProvenanceLookup, type ProvenanceTrust, REALTIME_PII_PATTERNS, type RiskMetadata, SCAN_SIGNAL_WEIGHTS, SENSITIVE_PATH_RE, SENSITIVE_PATH_REGEXES, SSRF_MAX_HOST, type ScanFinding, type ScanSignals, type ScanSummary, type ScoreTier, type SessionExtractContext, type SessionToolCall, type Severity, type ShellCommandAnalysis, type ShellDestToken, type ShellDestination, type ShieldDefinition, type ShieldOverrides, type ShieldVerdict, type SmartCondition, type SmartRule, type SsrfFloorOptions, type SsrfMatch, type SsrfTier, type SsrfVerdict, type ToolCallEntry, type ToolCallRecord, analyzeFsOperation, analyzePipeChain, analyzeShellCommand, checkDangerousSql, classifyAuditEntry, classifyRuleSeverity, classifyScanSignal, classifySsrf, computeAgentDeviceScore, computeArgsHash, computeBlendedSecurityScore, computeScanScore, computeSecurityScore, dedupeCanonicalFindings, detectArgsPii, detectDangerousEval, detectDangerousShellExec, detectInlineExec, detectPii, evaluateEgress, evaluateLoopWindow, evaluatePolicy, evaluateSmartConditions, extractAllSshHosts, extractCanonicalFindings, extractNetworkTargets, extractPositionalArgs, extractSessionLevelFindings, extractShellDestTokens, extractShellDestinations, fileOperandFlagsOf, getCompiledRegex, getNestedValue, hostMatches, isBashTool, isIgnoredTool, isPrivateHost, isProtectedHomePath, isShellShapedTool, isShieldVerdict, isStrictGatedTier, matchCanary, matchCanaryArgs, matchSensitivePath, matchesPattern, narrativeRuleLabel, normalizeCommandForPolicy, normalizeIpLiteral, parseAllSshHostsFromCommand, parseDestHost, patternShapeOf, positionedArgs, previewArgs, redactText, resolvePinned, safeMessage, sampleCopyCommand, scanArgs, scanInjection, scanText, sensitivePathMatch, ssrfDestinationFloor, ssrfFloor, ssrfReason, stripControlChars, stripTerminalEscapes, summarizeBlast, summarizeScan, toScanFinding, toolMatchesRule, truncateBlastPath, unwrapCommandHead, validateOverrides, validateRegex, validateShieldDefinition };
package/dist/index.d.ts CHANGED
@@ -647,6 +647,27 @@ declare function validateRegex(pattern: string): string | null;
647
647
  */
648
648
  declare function getCompiledRegex(pattern: string, flags?: string): RegExp | null;
649
649
 
650
+ /** See TERMINAL_ESCAPE_RE. Keeps tab, newline and carriage return. */
651
+ declare function stripTerminalEscapes(s: string): string;
652
+ /** See CONTROL_CHAR_RE. Removes every C0 control and DEL, whitespace included. */
653
+ declare function stripControlChars(s: string): string;
654
+ /**
655
+ * One safe line, for any string that came from outside this process before it
656
+ * reaches a terminal or a log file.
657
+ *
658
+ * node9's terminal output IS the user's trust signal: a "connected and
659
+ * governed" line is what tells someone the machine is protected. A response
660
+ * field carrying CR plus SGR codes can paint a line that looks exactly like
661
+ * one of ours, and a newline in a value written to hook-debug.log forges a
662
+ * second journal entry. So: escape sequences removed, all whitespace collapsed
663
+ * to single spaces (one value can never become two lines), and a length cap so
664
+ * a hostile or broken peer cannot flood the log.
665
+ *
666
+ * Accepts unknown because most call sites hold a caught `error` or an optional
667
+ * response field.
668
+ */
669
+ declare function safeMessage(value: unknown, max?: number): string;
670
+
650
671
  interface ShieldDefinition {
651
672
  name: string;
652
673
  description: string;
@@ -1058,6 +1079,11 @@ interface BlastSummary {
1058
1079
  /** Number of env vars flagged as credentials. No keys included. */
1059
1080
  envExposureCount: number;
1060
1081
  }
1082
+ /**
1083
+ * Longest path `truncateBlastPath` will look at, tail-anchored. PATH_MAX is
1084
+ * 4096 on Linux, so anything past this is not a path we could have read.
1085
+ */
1086
+ declare const MAX_BLAST_PATH = 4096;
1061
1087
  /**
1062
1088
  * Sanitise a sensitive path for transmission. Keeps only the trailing 2
1063
1089
  * segments — enough to identify the kind of file ("~/.aws/credentials"
@@ -1306,7 +1332,7 @@ declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v15";
1306
1332
  * files changed, this hash must change too, and you must consciously
1307
1333
  * decide whether to bump CANONICAL_EXTRACTOR_VERSION."
1308
1334
  */
1309
- declare const CANONICAL_EXTRACTOR_HASH = "5dad4c8f07121f6c";
1335
+ declare const CANONICAL_EXTRACTOR_HASH = "2823cd6a54a1fca7";
1310
1336
  declare function extractCanonicalFindings(call: ToolCallEntry, ctx: ExtractContext): CanonicalFinding[];
1311
1337
  declare function extractSessionLevelFindings(calls: ReadonlyArray<SessionToolCall>, ctx: SessionExtractContext): CanonicalFinding[];
1312
1338
  /**
@@ -1426,4 +1452,4 @@ declare function ssrfDestinationFloor(toolName: string, args: unknown, opts?: {
1426
1452
  /** Engine version stamped on audit entries for future drift detection. */
1427
1453
  declare const ENGINE_VERSION = "1.4.0";
1428
1454
 
1429
- export { AST_FS_REGEX_RULES, type AuditEntryForClassify, BASH_TOOL_NAMES, BUILTIN_SHIELDS, type BlastEnvFinding, type BlastFinding, type BlastResult, type BlastSummary, CANARY_MIN_LENGTH, CANONICAL_EXTRACTOR_HASH, CANONICAL_EXTRACTOR_VERSION, COMMAND_WRAPPERS, COPY_VERBS, COST_PER_LOOP_ITER_USD, type CanaryHit, type CanaryValue, type CanaryView, type CanonicalAgent, type CanonicalFinding, type CanonicalFindingType, type CanonicalSourceType, DEFAULT_EGRESS_ALLOWLIST, DESTINATION_ARGS, DESTRUCTIVE_OP_RE, DLP_PATTERNS, DLP_SCAN_LIMITS, type DlpMatch, ENGINE_VERSION, type EgressPolicy, type EgressVerdict, type ExtractContext, FILE_TOOLS, FLAGS_WITH_VALUES, FS_READ_TOOLS, type FsOpVerdict, type InjectionConfidence, type InjectionContext, type InjectionMatch, LONG_OUTPUT_THRESHOLD_BYTES, LOOP_MAX_RECORDS, LOOP_THRESHOLD_FOR_WASTE, type LoopWindowEvaluation, NET_BINARIES, PATTERN_VERB_NAMES, PRIVILEGE_ESCALATION_RE, type PiiPattern, type PipeChainAnalysis, type PolicyConfig, type PolicyContext, type PolicyHostHooks, type PolicyVerdict, type PositionedArg, type ProvenanceLookup, type ProvenanceTrust, REALTIME_PII_PATTERNS, type RiskMetadata, SCAN_SIGNAL_WEIGHTS, SENSITIVE_PATH_RE, SENSITIVE_PATH_REGEXES, SSRF_MAX_HOST, type ScanFinding, type ScanSignals, type ScanSummary, type ScoreTier, type SessionExtractContext, type SessionToolCall, type Severity, type ShellCommandAnalysis, type ShellDestToken, type ShellDestination, type ShieldDefinition, type ShieldOverrides, type ShieldVerdict, type SmartCondition, type SmartRule, type SsrfFloorOptions, type SsrfMatch, type SsrfTier, type SsrfVerdict, type ToolCallEntry, type ToolCallRecord, analyzeFsOperation, analyzePipeChain, analyzeShellCommand, checkDangerousSql, classifyAuditEntry, classifyRuleSeverity, classifyScanSignal, classifySsrf, computeAgentDeviceScore, computeArgsHash, computeBlendedSecurityScore, computeScanScore, computeSecurityScore, dedupeCanonicalFindings, detectArgsPii, detectDangerousEval, detectDangerousShellExec, detectInlineExec, detectPii, evaluateEgress, evaluateLoopWindow, evaluatePolicy, evaluateSmartConditions, extractAllSshHosts, extractCanonicalFindings, extractNetworkTargets, extractPositionalArgs, extractSessionLevelFindings, extractShellDestTokens, extractShellDestinations, fileOperandFlagsOf, getCompiledRegex, getNestedValue, hostMatches, isBashTool, isIgnoredTool, isPrivateHost, isProtectedHomePath, isShellShapedTool, isShieldVerdict, isStrictGatedTier, matchCanary, matchCanaryArgs, matchSensitivePath, matchesPattern, narrativeRuleLabel, normalizeCommandForPolicy, normalizeIpLiteral, parseAllSshHostsFromCommand, parseDestHost, patternShapeOf, positionedArgs, previewArgs, redactText, resolvePinned, sampleCopyCommand, scanArgs, scanInjection, scanText, sensitivePathMatch, ssrfDestinationFloor, ssrfFloor, ssrfReason, summarizeBlast, summarizeScan, toScanFinding, toolMatchesRule, truncateBlastPath, unwrapCommandHead, validateOverrides, validateRegex, validateShieldDefinition };
1455
+ export { AST_FS_REGEX_RULES, type AuditEntryForClassify, BASH_TOOL_NAMES, BUILTIN_SHIELDS, type BlastEnvFinding, type BlastFinding, type BlastResult, type BlastSummary, CANARY_MIN_LENGTH, CANONICAL_EXTRACTOR_HASH, CANONICAL_EXTRACTOR_VERSION, COMMAND_WRAPPERS, COPY_VERBS, COST_PER_LOOP_ITER_USD, type CanaryHit, type CanaryValue, type CanaryView, type CanonicalAgent, type CanonicalFinding, type CanonicalFindingType, type CanonicalSourceType, DEFAULT_EGRESS_ALLOWLIST, DESTINATION_ARGS, DESTRUCTIVE_OP_RE, DLP_PATTERNS, DLP_SCAN_LIMITS, type DlpMatch, ENGINE_VERSION, type EgressPolicy, type EgressVerdict, type ExtractContext, FILE_TOOLS, FLAGS_WITH_VALUES, FS_READ_TOOLS, type FsOpVerdict, type InjectionConfidence, type InjectionContext, type InjectionMatch, LONG_OUTPUT_THRESHOLD_BYTES, LOOP_MAX_RECORDS, LOOP_THRESHOLD_FOR_WASTE, type LoopWindowEvaluation, MAX_BLAST_PATH, NET_BINARIES, PATTERN_VERB_NAMES, PRIVILEGE_ESCALATION_RE, type PiiPattern, type PipeChainAnalysis, type PolicyConfig, type PolicyContext, type PolicyHostHooks, type PolicyVerdict, type PositionedArg, type ProvenanceLookup, type ProvenanceTrust, REALTIME_PII_PATTERNS, type RiskMetadata, SCAN_SIGNAL_WEIGHTS, SENSITIVE_PATH_RE, SENSITIVE_PATH_REGEXES, SSRF_MAX_HOST, type ScanFinding, type ScanSignals, type ScanSummary, type ScoreTier, type SessionExtractContext, type SessionToolCall, type Severity, type ShellCommandAnalysis, type ShellDestToken, type ShellDestination, type ShieldDefinition, type ShieldOverrides, type ShieldVerdict, type SmartCondition, type SmartRule, type SsrfFloorOptions, type SsrfMatch, type SsrfTier, type SsrfVerdict, type ToolCallEntry, type ToolCallRecord, analyzeFsOperation, analyzePipeChain, analyzeShellCommand, checkDangerousSql, classifyAuditEntry, classifyRuleSeverity, classifyScanSignal, classifySsrf, computeAgentDeviceScore, computeArgsHash, computeBlendedSecurityScore, computeScanScore, computeSecurityScore, dedupeCanonicalFindings, detectArgsPii, detectDangerousEval, detectDangerousShellExec, detectInlineExec, detectPii, evaluateEgress, evaluateLoopWindow, evaluatePolicy, evaluateSmartConditions, extractAllSshHosts, extractCanonicalFindings, extractNetworkTargets, extractPositionalArgs, extractSessionLevelFindings, extractShellDestTokens, extractShellDestinations, fileOperandFlagsOf, getCompiledRegex, getNestedValue, hostMatches, isBashTool, isIgnoredTool, isPrivateHost, isProtectedHomePath, isShellShapedTool, isShieldVerdict, isStrictGatedTier, matchCanary, matchCanaryArgs, matchSensitivePath, matchesPattern, narrativeRuleLabel, normalizeCommandForPolicy, normalizeIpLiteral, parseAllSshHostsFromCommand, parseDestHost, patternShapeOf, positionedArgs, previewArgs, redactText, resolvePinned, safeMessage, sampleCopyCommand, scanArgs, scanInjection, scanText, sensitivePathMatch, ssrfDestinationFloor, ssrfFloor, ssrfReason, stripControlChars, stripTerminalEscapes, summarizeBlast, summarizeScan, toScanFinding, toolMatchesRule, truncateBlastPath, unwrapCommandHead, validateOverrides, validateRegex, validateShieldDefinition };
package/dist/index.js CHANGED
@@ -51,6 +51,7 @@ __export(src_exports, {
51
51
  LONG_OUTPUT_THRESHOLD_BYTES: () => LONG_OUTPUT_THRESHOLD_BYTES,
52
52
  LOOP_MAX_RECORDS: () => LOOP_MAX_RECORDS,
53
53
  LOOP_THRESHOLD_FOR_WASTE: () => LOOP_THRESHOLD_FOR_WASTE,
54
+ MAX_BLAST_PATH: () => MAX_BLAST_PATH,
54
55
  NET_BINARIES: () => NET_BINARIES,
55
56
  PATTERN_VERB_NAMES: () => PATTERN_VERB_NAMES,
56
57
  PRIVILEGE_ESCALATION_RE: () => PRIVILEGE_ESCALATION_RE,
@@ -114,6 +115,7 @@ __export(src_exports, {
114
115
  previewArgs: () => previewArgs,
115
116
  redactText: () => redactText,
116
117
  resolvePinned: () => resolvePinned,
118
+ safeMessage: () => safeMessage,
117
119
  sampleCopyCommand: () => sampleCopyCommand,
118
120
  scanArgs: () => scanArgs,
119
121
  scanInjection: () => scanInjection,
@@ -122,6 +124,8 @@ __export(src_exports, {
122
124
  ssrfDestinationFloor: () => ssrfDestinationFloor,
123
125
  ssrfFloor: () => ssrfFloor,
124
126
  ssrfReason: () => ssrfReason,
127
+ stripControlChars: () => stripControlChars,
128
+ stripTerminalEscapes: () => stripTerminalEscapes,
125
129
  summarizeBlast: () => summarizeBlast,
126
130
  summarizeScan: () => summarizeScan,
127
131
  toScanFinding: () => toScanFinding,
@@ -4279,6 +4283,21 @@ function isIgnoredTool(toolName, config) {
4279
4283
  return matchesPattern(toolName, config.policy.ignoredTools);
4280
4284
  }
4281
4285
 
4286
+ // src/utils/safe-text.ts
4287
+ var TERMINAL_ESCAPE_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
4288
+ var CONTROL_CHAR_RE = /[\x00-\x1F\x7F]/g;
4289
+ function stripTerminalEscapes(s) {
4290
+ return s.replace(TERMINAL_ESCAPE_RE, "");
4291
+ }
4292
+ function stripControlChars(s) {
4293
+ return s.replace(CONTROL_CHAR_RE, "");
4294
+ }
4295
+ function safeMessage(value, max = 300) {
4296
+ const raw = typeof value === "string" ? value : value instanceof Error ? value.message : String(value ?? "");
4297
+ const s = stripTerminalEscapes(raw).replace(/\s+/g, " ").trim();
4298
+ return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
4299
+ }
4300
+
4282
4301
  // src/shields/index.ts
4283
4302
  var import_safe_regex23 = __toESM(require("safe-regex2"));
4284
4303
 
@@ -5360,9 +5379,13 @@ function computeAgentDeviceScore(opts) {
5360
5379
  }
5361
5380
 
5362
5381
  // src/blast/index.ts
5382
+ var MAX_BLAST_PATH = 4096;
5363
5383
  function truncateBlastPath(full) {
5364
5384
  if (!full) return "";
5365
- const cleaned = full.replace(/[/\\]+$/, "");
5385
+ if (full.length > MAX_BLAST_PATH) full = full.slice(-MAX_BLAST_PATH);
5386
+ let end = full.length;
5387
+ while (end > 0 && (full[end - 1] === "/" || full[end - 1] === "\\")) end--;
5388
+ const cleaned = full.slice(0, end);
5366
5389
  const parts = cleaned.split(/[/\\]+/).filter((p) => p.length > 0);
5367
5390
  if (parts.length <= 2) {
5368
5391
  return cleaned.startsWith("~") && !cleaned.startsWith("~/") ? cleaned : cleaned.startsWith("~/") ? cleaned : parts.join("/");
@@ -5650,7 +5673,7 @@ function matchCanaryArgs(args, values) {
5650
5673
  // src/scan/canonical.ts
5651
5674
  var LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
5652
5675
  var CANONICAL_EXTRACTOR_VERSION = "canonical-v15";
5653
- var CANONICAL_EXTRACTOR_HASH = "5dad4c8f07121f6c";
5676
+ var CANONICAL_EXTRACTOR_HASH = "2823cd6a54a1fca7";
5654
5677
  var DEDUPE_PREVIEW_LEN = 120;
5655
5678
  function extractCanonicalFindings(call, ctx) {
5656
5679
  const out = [];
@@ -5969,13 +5992,9 @@ function toScanFinding(c) {
5969
5992
  lineIndex: c.lineIndex
5970
5993
  };
5971
5994
  }
5972
- var TERMINAL_ESCAPE_RE = (
5973
- // eslint-disable-next-line no-control-regex
5974
- /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g
5975
- );
5976
5995
  function previewArgs(input, max) {
5977
5996
  const cmd = input.command ?? input.query ?? input.file_path ?? JSON.stringify(input);
5978
- const s = String(cmd).replace(TERMINAL_ESCAPE_RE, "").replace(/\s+/g, " ").trim();
5997
+ const s = stripTerminalEscapes(String(cmd)).replace(/\s+/g, " ").trim();
5979
5998
  return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
5980
5999
  }
5981
6000
  function makeFinding(args) {
@@ -6041,6 +6060,7 @@ var ENGINE_VERSION = "1.4.0";
6041
6060
  LONG_OUTPUT_THRESHOLD_BYTES,
6042
6061
  LOOP_MAX_RECORDS,
6043
6062
  LOOP_THRESHOLD_FOR_WASTE,
6063
+ MAX_BLAST_PATH,
6044
6064
  NET_BINARIES,
6045
6065
  PATTERN_VERB_NAMES,
6046
6066
  PRIVILEGE_ESCALATION_RE,
@@ -6104,6 +6124,7 @@ var ENGINE_VERSION = "1.4.0";
6104
6124
  previewArgs,
6105
6125
  redactText,
6106
6126
  resolvePinned,
6127
+ safeMessage,
6107
6128
  sampleCopyCommand,
6108
6129
  scanArgs,
6109
6130
  scanInjection,
@@ -6112,6 +6133,8 @@ var ENGINE_VERSION = "1.4.0";
6112
6133
  ssrfDestinationFloor,
6113
6134
  ssrfFloor,
6114
6135
  ssrfReason,
6136
+ stripControlChars,
6137
+ stripTerminalEscapes,
6115
6138
  summarizeBlast,
6116
6139
  summarizeScan,
6117
6140
  toScanFinding,
package/dist/index.mjs CHANGED
@@ -4143,6 +4143,21 @@ function isIgnoredTool(toolName, config) {
4143
4143
  return matchesPattern(toolName, config.policy.ignoredTools);
4144
4144
  }
4145
4145
 
4146
+ // src/utils/safe-text.ts
4147
+ var TERMINAL_ESCAPE_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
4148
+ var CONTROL_CHAR_RE = /[\x00-\x1F\x7F]/g;
4149
+ function stripTerminalEscapes(s) {
4150
+ return s.replace(TERMINAL_ESCAPE_RE, "");
4151
+ }
4152
+ function stripControlChars(s) {
4153
+ return s.replace(CONTROL_CHAR_RE, "");
4154
+ }
4155
+ function safeMessage(value, max = 300) {
4156
+ const raw = typeof value === "string" ? value : value instanceof Error ? value.message : String(value ?? "");
4157
+ const s = stripTerminalEscapes(raw).replace(/\s+/g, " ").trim();
4158
+ return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
4159
+ }
4160
+
4146
4161
  // src/shields/index.ts
4147
4162
  import safeRegex3 from "safe-regex2";
4148
4163
 
@@ -5224,9 +5239,13 @@ function computeAgentDeviceScore(opts) {
5224
5239
  }
5225
5240
 
5226
5241
  // src/blast/index.ts
5242
+ var MAX_BLAST_PATH = 4096;
5227
5243
  function truncateBlastPath(full) {
5228
5244
  if (!full) return "";
5229
- const cleaned = full.replace(/[/\\]+$/, "");
5245
+ if (full.length > MAX_BLAST_PATH) full = full.slice(-MAX_BLAST_PATH);
5246
+ let end = full.length;
5247
+ while (end > 0 && (full[end - 1] === "/" || full[end - 1] === "\\")) end--;
5248
+ const cleaned = full.slice(0, end);
5230
5249
  const parts = cleaned.split(/[/\\]+/).filter((p) => p.length > 0);
5231
5250
  if (parts.length <= 2) {
5232
5251
  return cleaned.startsWith("~") && !cleaned.startsWith("~/") ? cleaned : cleaned.startsWith("~/") ? cleaned : parts.join("/");
@@ -5514,7 +5533,7 @@ function matchCanaryArgs(args, values) {
5514
5533
  // src/scan/canonical.ts
5515
5534
  var LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
5516
5535
  var CANONICAL_EXTRACTOR_VERSION = "canonical-v15";
5517
- var CANONICAL_EXTRACTOR_HASH = "5dad4c8f07121f6c";
5536
+ var CANONICAL_EXTRACTOR_HASH = "2823cd6a54a1fca7";
5518
5537
  var DEDUPE_PREVIEW_LEN = 120;
5519
5538
  function extractCanonicalFindings(call, ctx) {
5520
5539
  const out = [];
@@ -5833,13 +5852,9 @@ function toScanFinding(c) {
5833
5852
  lineIndex: c.lineIndex
5834
5853
  };
5835
5854
  }
5836
- var TERMINAL_ESCAPE_RE = (
5837
- // eslint-disable-next-line no-control-regex
5838
- /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g
5839
- );
5840
5855
  function previewArgs(input, max) {
5841
5856
  const cmd = input.command ?? input.query ?? input.file_path ?? JSON.stringify(input);
5842
- const s = String(cmd).replace(TERMINAL_ESCAPE_RE, "").replace(/\s+/g, " ").trim();
5857
+ const s = stripTerminalEscapes(String(cmd)).replace(/\s+/g, " ").trim();
5843
5858
  return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
5844
5859
  }
5845
5860
  function makeFinding(args) {
@@ -5904,6 +5919,7 @@ export {
5904
5919
  LONG_OUTPUT_THRESHOLD_BYTES,
5905
5920
  LOOP_MAX_RECORDS,
5906
5921
  LOOP_THRESHOLD_FOR_WASTE,
5922
+ MAX_BLAST_PATH,
5907
5923
  NET_BINARIES,
5908
5924
  PATTERN_VERB_NAMES,
5909
5925
  PRIVILEGE_ESCALATION_RE,
@@ -5967,6 +5983,7 @@ export {
5967
5983
  previewArgs,
5968
5984
  redactText,
5969
5985
  resolvePinned,
5986
+ safeMessage,
5970
5987
  sampleCopyCommand,
5971
5988
  scanArgs,
5972
5989
  scanInjection,
@@ -5975,6 +5992,8 @@ export {
5975
5992
  ssrfDestinationFloor,
5976
5993
  ssrfFloor,
5977
5994
  ssrfReason,
5995
+ stripControlChars,
5996
+ stripTerminalEscapes,
5978
5997
  summarizeBlast,
5979
5998
  summarizeScan,
5980
5999
  toScanFinding,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/policy-engine",
3
- "version": "2.14.1",
3
+ "version": "2.14.2",
4
4
  "description": "Shared policy evaluation engine for node9 — DLP, smart rules, AST shell parsing, shields, loop detection. Pure functions, no I/O. Used by both node9-proxy and the node9 SaaS firewall.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://node9.ai",