@node9/policy-engine 2.14.1 → 2.14.3
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 +41 -2
- package/dist/index.d.ts +41 -2
- package/dist/index.js +34 -9
- package/dist/index.mjs +30 -9
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -571,6 +571,19 @@ interface PolicyVerdict {
|
|
|
571
571
|
matchedField?: string;
|
|
572
572
|
matchedWord?: string;
|
|
573
573
|
tier?: 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
|
574
|
+
/**
|
|
575
|
+
* False when NO human may override this verdict: the SSRF tier-1 floors,
|
|
576
|
+
* whose own reason string already tells the user "This address cannot be
|
|
577
|
+
* allowlisted". Absent means an override is a legitimate product decision,
|
|
578
|
+
* which is every other verdict.
|
|
579
|
+
*
|
|
580
|
+
* It exists because the host downgrades a hard block into a review whenever a
|
|
581
|
+
* human approver is reachable (orchestrator.ts, `mayDowngrade`). That is right
|
|
582
|
+
* for a smart-rule block and wrong for a floor, and the host could not tell
|
|
583
|
+
* the two apart: `overridable` was computed in egress/ssrf.ts, rendered into
|
|
584
|
+
* the reason sentence, and then dropped here.
|
|
585
|
+
*/
|
|
586
|
+
overridable?: boolean;
|
|
574
587
|
ruleName?: string;
|
|
575
588
|
/** State predicates from the matched smart rule (only when decision is 'block'). */
|
|
576
589
|
dependsOnStatePredicates?: string[];
|
|
@@ -647,6 +660,27 @@ declare function validateRegex(pattern: string): string | null;
|
|
|
647
660
|
*/
|
|
648
661
|
declare function getCompiledRegex(pattern: string, flags?: string): RegExp | null;
|
|
649
662
|
|
|
663
|
+
/** See TERMINAL_ESCAPE_RE. Keeps tab, newline and carriage return. */
|
|
664
|
+
declare function stripTerminalEscapes(s: string): string;
|
|
665
|
+
/** See CONTROL_CHAR_RE. Removes every C0 control and DEL, whitespace included. */
|
|
666
|
+
declare function stripControlChars(s: string): string;
|
|
667
|
+
/**
|
|
668
|
+
* One safe line, for any string that came from outside this process before it
|
|
669
|
+
* reaches a terminal or a log file.
|
|
670
|
+
*
|
|
671
|
+
* node9's terminal output IS the user's trust signal: a "connected and
|
|
672
|
+
* governed" line is what tells someone the machine is protected. A response
|
|
673
|
+
* field carrying CR plus SGR codes can paint a line that looks exactly like
|
|
674
|
+
* one of ours, and a newline in a value written to hook-debug.log forges a
|
|
675
|
+
* second journal entry. So: escape sequences removed, all whitespace collapsed
|
|
676
|
+
* to single spaces (one value can never become two lines), and a length cap so
|
|
677
|
+
* a hostile or broken peer cannot flood the log.
|
|
678
|
+
*
|
|
679
|
+
* Accepts unknown because most call sites hold a caught `error` or an optional
|
|
680
|
+
* response field.
|
|
681
|
+
*/
|
|
682
|
+
declare function safeMessage(value: unknown, max?: number): string;
|
|
683
|
+
|
|
650
684
|
interface ShieldDefinition {
|
|
651
685
|
name: string;
|
|
652
686
|
description: string;
|
|
@@ -1058,6 +1092,11 @@ interface BlastSummary {
|
|
|
1058
1092
|
/** Number of env vars flagged as credentials. No keys included. */
|
|
1059
1093
|
envExposureCount: number;
|
|
1060
1094
|
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Longest path `truncateBlastPath` will look at, tail-anchored. PATH_MAX is
|
|
1097
|
+
* 4096 on Linux, so anything past this is not a path we could have read.
|
|
1098
|
+
*/
|
|
1099
|
+
declare const MAX_BLAST_PATH = 4096;
|
|
1061
1100
|
/**
|
|
1062
1101
|
* Sanitise a sensitive path for transmission. Keeps only the trailing 2
|
|
1063
1102
|
* segments — enough to identify the kind of file ("~/.aws/credentials"
|
|
@@ -1306,7 +1345,7 @@ declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v15";
|
|
|
1306
1345
|
* files changed, this hash must change too, and you must consciously
|
|
1307
1346
|
* decide whether to bump CANONICAL_EXTRACTOR_VERSION."
|
|
1308
1347
|
*/
|
|
1309
|
-
declare const CANONICAL_EXTRACTOR_HASH = "
|
|
1348
|
+
declare const CANONICAL_EXTRACTOR_HASH = "2823cd6a54a1fca7";
|
|
1310
1349
|
declare function extractCanonicalFindings(call: ToolCallEntry, ctx: ExtractContext): CanonicalFinding[];
|
|
1311
1350
|
declare function extractSessionLevelFindings(calls: ReadonlyArray<SessionToolCall>, ctx: SessionExtractContext): CanonicalFinding[];
|
|
1312
1351
|
/**
|
|
@@ -1426,4 +1465,4 @@ declare function ssrfDestinationFloor(toolName: string, args: unknown, opts?: {
|
|
|
1426
1465
|
/** Engine version stamped on audit entries for future drift detection. */
|
|
1427
1466
|
declare const ENGINE_VERSION = "1.4.0";
|
|
1428
1467
|
|
|
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 };
|
|
1468
|
+
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
|
@@ -571,6 +571,19 @@ interface PolicyVerdict {
|
|
|
571
571
|
matchedField?: string;
|
|
572
572
|
matchedWord?: string;
|
|
573
573
|
tier?: 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
|
574
|
+
/**
|
|
575
|
+
* False when NO human may override this verdict: the SSRF tier-1 floors,
|
|
576
|
+
* whose own reason string already tells the user "This address cannot be
|
|
577
|
+
* allowlisted". Absent means an override is a legitimate product decision,
|
|
578
|
+
* which is every other verdict.
|
|
579
|
+
*
|
|
580
|
+
* It exists because the host downgrades a hard block into a review whenever a
|
|
581
|
+
* human approver is reachable (orchestrator.ts, `mayDowngrade`). That is right
|
|
582
|
+
* for a smart-rule block and wrong for a floor, and the host could not tell
|
|
583
|
+
* the two apart: `overridable` was computed in egress/ssrf.ts, rendered into
|
|
584
|
+
* the reason sentence, and then dropped here.
|
|
585
|
+
*/
|
|
586
|
+
overridable?: boolean;
|
|
574
587
|
ruleName?: string;
|
|
575
588
|
/** State predicates from the matched smart rule (only when decision is 'block'). */
|
|
576
589
|
dependsOnStatePredicates?: string[];
|
|
@@ -647,6 +660,27 @@ declare function validateRegex(pattern: string): string | null;
|
|
|
647
660
|
*/
|
|
648
661
|
declare function getCompiledRegex(pattern: string, flags?: string): RegExp | null;
|
|
649
662
|
|
|
663
|
+
/** See TERMINAL_ESCAPE_RE. Keeps tab, newline and carriage return. */
|
|
664
|
+
declare function stripTerminalEscapes(s: string): string;
|
|
665
|
+
/** See CONTROL_CHAR_RE. Removes every C0 control and DEL, whitespace included. */
|
|
666
|
+
declare function stripControlChars(s: string): string;
|
|
667
|
+
/**
|
|
668
|
+
* One safe line, for any string that came from outside this process before it
|
|
669
|
+
* reaches a terminal or a log file.
|
|
670
|
+
*
|
|
671
|
+
* node9's terminal output IS the user's trust signal: a "connected and
|
|
672
|
+
* governed" line is what tells someone the machine is protected. A response
|
|
673
|
+
* field carrying CR plus SGR codes can paint a line that looks exactly like
|
|
674
|
+
* one of ours, and a newline in a value written to hook-debug.log forges a
|
|
675
|
+
* second journal entry. So: escape sequences removed, all whitespace collapsed
|
|
676
|
+
* to single spaces (one value can never become two lines), and a length cap so
|
|
677
|
+
* a hostile or broken peer cannot flood the log.
|
|
678
|
+
*
|
|
679
|
+
* Accepts unknown because most call sites hold a caught `error` or an optional
|
|
680
|
+
* response field.
|
|
681
|
+
*/
|
|
682
|
+
declare function safeMessage(value: unknown, max?: number): string;
|
|
683
|
+
|
|
650
684
|
interface ShieldDefinition {
|
|
651
685
|
name: string;
|
|
652
686
|
description: string;
|
|
@@ -1058,6 +1092,11 @@ interface BlastSummary {
|
|
|
1058
1092
|
/** Number of env vars flagged as credentials. No keys included. */
|
|
1059
1093
|
envExposureCount: number;
|
|
1060
1094
|
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Longest path `truncateBlastPath` will look at, tail-anchored. PATH_MAX is
|
|
1097
|
+
* 4096 on Linux, so anything past this is not a path we could have read.
|
|
1098
|
+
*/
|
|
1099
|
+
declare const MAX_BLAST_PATH = 4096;
|
|
1061
1100
|
/**
|
|
1062
1101
|
* Sanitise a sensitive path for transmission. Keeps only the trailing 2
|
|
1063
1102
|
* segments — enough to identify the kind of file ("~/.aws/credentials"
|
|
@@ -1306,7 +1345,7 @@ declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v15";
|
|
|
1306
1345
|
* files changed, this hash must change too, and you must consciously
|
|
1307
1346
|
* decide whether to bump CANONICAL_EXTRACTOR_VERSION."
|
|
1308
1347
|
*/
|
|
1309
|
-
declare const CANONICAL_EXTRACTOR_HASH = "
|
|
1348
|
+
declare const CANONICAL_EXTRACTOR_HASH = "2823cd6a54a1fca7";
|
|
1310
1349
|
declare function extractCanonicalFindings(call: ToolCallEntry, ctx: ExtractContext): CanonicalFinding[];
|
|
1311
1350
|
declare function extractSessionLevelFindings(calls: ReadonlyArray<SessionToolCall>, ctx: SessionExtractContext): CanonicalFinding[];
|
|
1312
1351
|
/**
|
|
@@ -1426,4 +1465,4 @@ declare function ssrfDestinationFloor(toolName: string, args: unknown, opts?: {
|
|
|
1426
1465
|
/** Engine version stamped on audit entries for future drift detection. */
|
|
1427
1466
|
declare const ENGINE_VERSION = "1.4.0";
|
|
1428
1467
|
|
|
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 };
|
|
1468
|
+
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,
|
|
@@ -4005,7 +4009,8 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
4005
4009
|
reason: dest.reason,
|
|
4006
4010
|
ruleName: `ssrf:${dest.tier}:${toolName}:${dest.host}`,
|
|
4007
4011
|
ruleDescription: dest.reason,
|
|
4008
|
-
tier: 3
|
|
4012
|
+
tier: 3,
|
|
4013
|
+
overridable: dest.overridable
|
|
4009
4014
|
};
|
|
4010
4015
|
}
|
|
4011
4016
|
}
|
|
@@ -4154,7 +4159,8 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
4154
4159
|
reason: ssrf.reason,
|
|
4155
4160
|
ruleName: `ssrf:${ssrf.tier}:${ssrf.binary}:${ssrf.host}`,
|
|
4156
4161
|
ruleDescription: ssrf.reason,
|
|
4157
|
-
tier: 3
|
|
4162
|
+
tier: 3,
|
|
4163
|
+
overridable: ssrf.overridable
|
|
4158
4164
|
};
|
|
4159
4165
|
}
|
|
4160
4166
|
}
|
|
@@ -4279,6 +4285,21 @@ function isIgnoredTool(toolName, config) {
|
|
|
4279
4285
|
return matchesPattern(toolName, config.policy.ignoredTools);
|
|
4280
4286
|
}
|
|
4281
4287
|
|
|
4288
|
+
// src/utils/safe-text.ts
|
|
4289
|
+
var TERMINAL_ESCAPE_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
4290
|
+
var CONTROL_CHAR_RE = /[\x00-\x1F\x7F]/g;
|
|
4291
|
+
function stripTerminalEscapes(s) {
|
|
4292
|
+
return s.replace(TERMINAL_ESCAPE_RE, "");
|
|
4293
|
+
}
|
|
4294
|
+
function stripControlChars(s) {
|
|
4295
|
+
return s.replace(CONTROL_CHAR_RE, "");
|
|
4296
|
+
}
|
|
4297
|
+
function safeMessage(value, max = 300) {
|
|
4298
|
+
const raw = typeof value === "string" ? value : value instanceof Error ? value.message : String(value ?? "");
|
|
4299
|
+
const s = stripTerminalEscapes(raw).replace(/\s+/g, " ").trim();
|
|
4300
|
+
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
4301
|
+
}
|
|
4302
|
+
|
|
4282
4303
|
// src/shields/index.ts
|
|
4283
4304
|
var import_safe_regex23 = __toESM(require("safe-regex2"));
|
|
4284
4305
|
|
|
@@ -5360,9 +5381,13 @@ function computeAgentDeviceScore(opts) {
|
|
|
5360
5381
|
}
|
|
5361
5382
|
|
|
5362
5383
|
// src/blast/index.ts
|
|
5384
|
+
var MAX_BLAST_PATH = 4096;
|
|
5363
5385
|
function truncateBlastPath(full) {
|
|
5364
5386
|
if (!full) return "";
|
|
5365
|
-
|
|
5387
|
+
if (full.length > MAX_BLAST_PATH) full = full.slice(-MAX_BLAST_PATH);
|
|
5388
|
+
let end = full.length;
|
|
5389
|
+
while (end > 0 && (full[end - 1] === "/" || full[end - 1] === "\\")) end--;
|
|
5390
|
+
const cleaned = full.slice(0, end);
|
|
5366
5391
|
const parts = cleaned.split(/[/\\]+/).filter((p) => p.length > 0);
|
|
5367
5392
|
if (parts.length <= 2) {
|
|
5368
5393
|
return cleaned.startsWith("~") && !cleaned.startsWith("~/") ? cleaned : cleaned.startsWith("~/") ? cleaned : parts.join("/");
|
|
@@ -5650,7 +5675,7 @@ function matchCanaryArgs(args, values) {
|
|
|
5650
5675
|
// src/scan/canonical.ts
|
|
5651
5676
|
var LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
|
|
5652
5677
|
var CANONICAL_EXTRACTOR_VERSION = "canonical-v15";
|
|
5653
|
-
var CANONICAL_EXTRACTOR_HASH = "
|
|
5678
|
+
var CANONICAL_EXTRACTOR_HASH = "2823cd6a54a1fca7";
|
|
5654
5679
|
var DEDUPE_PREVIEW_LEN = 120;
|
|
5655
5680
|
function extractCanonicalFindings(call, ctx) {
|
|
5656
5681
|
const out = [];
|
|
@@ -5969,13 +5994,9 @@ function toScanFinding(c) {
|
|
|
5969
5994
|
lineIndex: c.lineIndex
|
|
5970
5995
|
};
|
|
5971
5996
|
}
|
|
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
5997
|
function previewArgs(input, max) {
|
|
5977
5998
|
const cmd = input.command ?? input.query ?? input.file_path ?? JSON.stringify(input);
|
|
5978
|
-
const s = String(cmd)
|
|
5999
|
+
const s = stripTerminalEscapes(String(cmd)).replace(/\s+/g, " ").trim();
|
|
5979
6000
|
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
5980
6001
|
}
|
|
5981
6002
|
function makeFinding(args) {
|
|
@@ -6041,6 +6062,7 @@ var ENGINE_VERSION = "1.4.0";
|
|
|
6041
6062
|
LONG_OUTPUT_THRESHOLD_BYTES,
|
|
6042
6063
|
LOOP_MAX_RECORDS,
|
|
6043
6064
|
LOOP_THRESHOLD_FOR_WASTE,
|
|
6065
|
+
MAX_BLAST_PATH,
|
|
6044
6066
|
NET_BINARIES,
|
|
6045
6067
|
PATTERN_VERB_NAMES,
|
|
6046
6068
|
PRIVILEGE_ESCALATION_RE,
|
|
@@ -6104,6 +6126,7 @@ var ENGINE_VERSION = "1.4.0";
|
|
|
6104
6126
|
previewArgs,
|
|
6105
6127
|
redactText,
|
|
6106
6128
|
resolvePinned,
|
|
6129
|
+
safeMessage,
|
|
6107
6130
|
sampleCopyCommand,
|
|
6108
6131
|
scanArgs,
|
|
6109
6132
|
scanInjection,
|
|
@@ -6112,6 +6135,8 @@ var ENGINE_VERSION = "1.4.0";
|
|
|
6112
6135
|
ssrfDestinationFloor,
|
|
6113
6136
|
ssrfFloor,
|
|
6114
6137
|
ssrfReason,
|
|
6138
|
+
stripControlChars,
|
|
6139
|
+
stripTerminalEscapes,
|
|
6115
6140
|
summarizeBlast,
|
|
6116
6141
|
summarizeScan,
|
|
6117
6142
|
toScanFinding,
|
package/dist/index.mjs
CHANGED
|
@@ -3869,7 +3869,8 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
3869
3869
|
reason: dest.reason,
|
|
3870
3870
|
ruleName: `ssrf:${dest.tier}:${toolName}:${dest.host}`,
|
|
3871
3871
|
ruleDescription: dest.reason,
|
|
3872
|
-
tier: 3
|
|
3872
|
+
tier: 3,
|
|
3873
|
+
overridable: dest.overridable
|
|
3873
3874
|
};
|
|
3874
3875
|
}
|
|
3875
3876
|
}
|
|
@@ -4018,7 +4019,8 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
4018
4019
|
reason: ssrf.reason,
|
|
4019
4020
|
ruleName: `ssrf:${ssrf.tier}:${ssrf.binary}:${ssrf.host}`,
|
|
4020
4021
|
ruleDescription: ssrf.reason,
|
|
4021
|
-
tier: 3
|
|
4022
|
+
tier: 3,
|
|
4023
|
+
overridable: ssrf.overridable
|
|
4022
4024
|
};
|
|
4023
4025
|
}
|
|
4024
4026
|
}
|
|
@@ -4143,6 +4145,21 @@ function isIgnoredTool(toolName, config) {
|
|
|
4143
4145
|
return matchesPattern(toolName, config.policy.ignoredTools);
|
|
4144
4146
|
}
|
|
4145
4147
|
|
|
4148
|
+
// src/utils/safe-text.ts
|
|
4149
|
+
var TERMINAL_ESCAPE_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
4150
|
+
var CONTROL_CHAR_RE = /[\x00-\x1F\x7F]/g;
|
|
4151
|
+
function stripTerminalEscapes(s) {
|
|
4152
|
+
return s.replace(TERMINAL_ESCAPE_RE, "");
|
|
4153
|
+
}
|
|
4154
|
+
function stripControlChars(s) {
|
|
4155
|
+
return s.replace(CONTROL_CHAR_RE, "");
|
|
4156
|
+
}
|
|
4157
|
+
function safeMessage(value, max = 300) {
|
|
4158
|
+
const raw = typeof value === "string" ? value : value instanceof Error ? value.message : String(value ?? "");
|
|
4159
|
+
const s = stripTerminalEscapes(raw).replace(/\s+/g, " ").trim();
|
|
4160
|
+
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
4161
|
+
}
|
|
4162
|
+
|
|
4146
4163
|
// src/shields/index.ts
|
|
4147
4164
|
import safeRegex3 from "safe-regex2";
|
|
4148
4165
|
|
|
@@ -5224,9 +5241,13 @@ function computeAgentDeviceScore(opts) {
|
|
|
5224
5241
|
}
|
|
5225
5242
|
|
|
5226
5243
|
// src/blast/index.ts
|
|
5244
|
+
var MAX_BLAST_PATH = 4096;
|
|
5227
5245
|
function truncateBlastPath(full) {
|
|
5228
5246
|
if (!full) return "";
|
|
5229
|
-
|
|
5247
|
+
if (full.length > MAX_BLAST_PATH) full = full.slice(-MAX_BLAST_PATH);
|
|
5248
|
+
let end = full.length;
|
|
5249
|
+
while (end > 0 && (full[end - 1] === "/" || full[end - 1] === "\\")) end--;
|
|
5250
|
+
const cleaned = full.slice(0, end);
|
|
5230
5251
|
const parts = cleaned.split(/[/\\]+/).filter((p) => p.length > 0);
|
|
5231
5252
|
if (parts.length <= 2) {
|
|
5232
5253
|
return cleaned.startsWith("~") && !cleaned.startsWith("~/") ? cleaned : cleaned.startsWith("~/") ? cleaned : parts.join("/");
|
|
@@ -5514,7 +5535,7 @@ function matchCanaryArgs(args, values) {
|
|
|
5514
5535
|
// src/scan/canonical.ts
|
|
5515
5536
|
var LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
|
|
5516
5537
|
var CANONICAL_EXTRACTOR_VERSION = "canonical-v15";
|
|
5517
|
-
var CANONICAL_EXTRACTOR_HASH = "
|
|
5538
|
+
var CANONICAL_EXTRACTOR_HASH = "2823cd6a54a1fca7";
|
|
5518
5539
|
var DEDUPE_PREVIEW_LEN = 120;
|
|
5519
5540
|
function extractCanonicalFindings(call, ctx) {
|
|
5520
5541
|
const out = [];
|
|
@@ -5833,13 +5854,9 @@ function toScanFinding(c) {
|
|
|
5833
5854
|
lineIndex: c.lineIndex
|
|
5834
5855
|
};
|
|
5835
5856
|
}
|
|
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
5857
|
function previewArgs(input, max) {
|
|
5841
5858
|
const cmd = input.command ?? input.query ?? input.file_path ?? JSON.stringify(input);
|
|
5842
|
-
const s = String(cmd)
|
|
5859
|
+
const s = stripTerminalEscapes(String(cmd)).replace(/\s+/g, " ").trim();
|
|
5843
5860
|
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
5844
5861
|
}
|
|
5845
5862
|
function makeFinding(args) {
|
|
@@ -5904,6 +5921,7 @@ export {
|
|
|
5904
5921
|
LONG_OUTPUT_THRESHOLD_BYTES,
|
|
5905
5922
|
LOOP_MAX_RECORDS,
|
|
5906
5923
|
LOOP_THRESHOLD_FOR_WASTE,
|
|
5924
|
+
MAX_BLAST_PATH,
|
|
5907
5925
|
NET_BINARIES,
|
|
5908
5926
|
PATTERN_VERB_NAMES,
|
|
5909
5927
|
PRIVILEGE_ESCALATION_RE,
|
|
@@ -5967,6 +5985,7 @@ export {
|
|
|
5967
5985
|
previewArgs,
|
|
5968
5986
|
redactText,
|
|
5969
5987
|
resolvePinned,
|
|
5988
|
+
safeMessage,
|
|
5970
5989
|
sampleCopyCommand,
|
|
5971
5990
|
scanArgs,
|
|
5972
5991
|
scanInjection,
|
|
@@ -5975,6 +5994,8 @@ export {
|
|
|
5975
5994
|
ssrfDestinationFloor,
|
|
5976
5995
|
ssrfFloor,
|
|
5977
5996
|
ssrfReason,
|
|
5997
|
+
stripControlChars,
|
|
5998
|
+
stripTerminalEscapes,
|
|
5978
5999
|
summarizeBlast,
|
|
5979
6000
|
summarizeScan,
|
|
5980
6001
|
toScanFinding,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node9/policy-engine",
|
|
3
|
-
"version": "2.14.
|
|
3
|
+
"version": "2.14.3",
|
|
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",
|