@node9/policy-engine 2.8.5 → 2.9.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/dist/index.d.mts +135 -13
- package/dist/index.d.ts +135 -13
- package/dist/index.js +778 -52
- package/dist/index.mjs +768 -50
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -136,6 +136,15 @@ interface DlpPattern {
|
|
|
136
136
|
* Only set on broad patterns where the regex alone can't distinguish real secrets.
|
|
137
137
|
*/
|
|
138
138
|
minEntropy?: number;
|
|
139
|
+
/**
|
|
140
|
+
* Structural validator run on the matched token (checksum, version byte).
|
|
141
|
+
* When present it DECIDES: a passing validator accepts the match outright,
|
|
142
|
+
* skipping the stopword and entropy heuristics (a checksum-valid token that
|
|
143
|
+
* happens to contain a stopword substring is a real secret, roughly 1 in
|
|
144
|
+
* 3,000 real WIF keys); a failing one rejects it. Must never throw; a throw
|
|
145
|
+
* is treated as "not suppressed" so a validator bug cannot hide a match.
|
|
146
|
+
*/
|
|
147
|
+
validate?: (raw: string) => boolean;
|
|
139
148
|
}
|
|
140
149
|
declare const DLP_PATTERNS: DlpPattern[];
|
|
141
150
|
/**
|
|
@@ -168,11 +177,6 @@ declare const DLP_SCAN_LIMITS: {
|
|
|
168
177
|
/** Max nesting depth walked; anything deeper is NOT scanned. */
|
|
169
178
|
readonly maxDepth: 5;
|
|
170
179
|
};
|
|
171
|
-
/**
|
|
172
|
-
* Recursively scans an args value for known secret patterns.
|
|
173
|
-
* Handles nested objects, arrays, and JSON-encoded strings.
|
|
174
|
-
* Returns the first match found, or null if clean.
|
|
175
|
-
*/
|
|
176
180
|
declare function scanArgs(args: unknown, depth?: number, fieldPath?: string): DlpMatch | null;
|
|
177
181
|
/** Scan a plain text string (e.g. Claude response prose) for DLP patterns. */
|
|
178
182
|
declare function scanText(text: string): DlpMatch | null;
|
|
@@ -264,6 +268,25 @@ declare function parseDestHost(token: string): string | null;
|
|
|
264
268
|
* and parses the host. Deduplicated by host. Pure — no I/O, no DNS.
|
|
265
269
|
*/
|
|
266
270
|
declare function extractShellDestinations(command: string): ShellDestination[];
|
|
271
|
+
/** A raw destination-position token from a network binary, BEFORE parseDestHost.
|
|
272
|
+
* The SSRF floor needs these because parseDestHost requires a dot and therefore
|
|
273
|
+
* drops `2852039166`, which denotes a cloud metadata address (measured: that
|
|
274
|
+
* command is allowed today at the strictest egress setting). */
|
|
275
|
+
interface ShellDestToken {
|
|
276
|
+
token: string;
|
|
277
|
+
binary: string;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Destination-position tokens for every network binary in a command, unparsed.
|
|
281
|
+
*
|
|
282
|
+
* Same walk and same flag-skipping as extractShellDestinations, so the two agree
|
|
283
|
+
* on which arguments are destinations. It exists as a sibling rather than a
|
|
284
|
+
* widening of parseDestHost because the dot requirement there is a load-bearing
|
|
285
|
+
* false-positive guard: turning every numeric token into a HOST would change
|
|
286
|
+
* egress verdicts for every user. Asking whether a token DENOTES A PROTECTED
|
|
287
|
+
* ADDRESS has no false-positive surface, because that comparison is exact.
|
|
288
|
+
*/
|
|
289
|
+
declare function extractShellDestTokens(command: string): ShellDestToken[];
|
|
267
290
|
declare function analyzeFsOperation(command: string): FsOpVerdict | null;
|
|
268
291
|
interface ShellCommandAnalysis {
|
|
269
292
|
/** First word of every CallExpr — the command names invoked. */
|
|
@@ -291,6 +314,14 @@ interface EgressPolicy {
|
|
|
291
314
|
deny: string[];
|
|
292
315
|
/** Auto-allow localhost / RFC1918 / *.local. Default true. */
|
|
293
316
|
allowPrivate: boolean;
|
|
317
|
+
/** SSRF floor: exempts OVERRIDABLE tiers only (carrier-grade NAT, and
|
|
318
|
+
* loopback/RFC1918 when ssrfStrict is on). A tier-1 entry is ignored here
|
|
319
|
+
* and rejected at config load with a reason. */
|
|
320
|
+
ssrfAllow?: readonly string[];
|
|
321
|
+
/** SSRF floor tier 3: also block loopback and RFC1918. Off by default,
|
|
322
|
+
* because a developer talks to those constantly (72 of 308 destinations on
|
|
323
|
+
* measured real history). */
|
|
324
|
+
ssrfStrict?: boolean;
|
|
294
325
|
}
|
|
295
326
|
interface EgressVerdict {
|
|
296
327
|
verdict: 'block' | 'review';
|
|
@@ -990,7 +1021,7 @@ declare const SENSITIVE_PATH_RE: RegExp;
|
|
|
990
1021
|
*/
|
|
991
1022
|
declare const FILE_TOOLS: Set<string>;
|
|
992
1023
|
|
|
993
|
-
type PiiPattern = 'Email' | 'SSN' | 'Phone' | 'Credit Card';
|
|
1024
|
+
type PiiPattern = 'Email' | 'SSN' | 'Phone' | 'Credit Card' | 'IBAN';
|
|
994
1025
|
/**
|
|
995
1026
|
* Detect PII patterns in a string. Returns a deduplicated list — one entry
|
|
996
1027
|
* per distinct pattern type, never multiple "Email" findings from one input.
|
|
@@ -998,13 +1029,40 @@ type PiiPattern = 'Email' | 'SSN' | 'Phone' | 'Credit Card';
|
|
|
998
1029
|
declare function detectPii(text: string): PiiPattern[];
|
|
999
1030
|
declare const REALTIME_PII_PATTERNS: readonly PiiPattern[];
|
|
1000
1031
|
/**
|
|
1001
|
-
* Realtime adapter for detectPii: walks a tool-args value
|
|
1002
|
-
*
|
|
1003
|
-
*
|
|
1032
|
+
* Realtime adapter for detectPii: walks a tool-args value leaf by leaf and
|
|
1033
|
+
* returns only the high-signal PII patterns found. Used by the authorize path
|
|
1034
|
+
* to gate SSN / Credit Card in tool arguments. Pure.
|
|
1035
|
+
*
|
|
1036
|
+
* Walks leaves rather than scanning JSON.stringify(args). Stringifying turns
|
|
1037
|
+
* a real newline into the two characters backslash + `n`, and `n` is a word
|
|
1038
|
+
* character, so a card or SSN that BEGINS A LINE inside a multi-line value
|
|
1039
|
+
* (a CSV being written, for instance) had no \b in front of it and was
|
|
1040
|
+
* invisible to the realtime gate. Raw leaves keep the real newline.
|
|
1004
1041
|
*/
|
|
1005
1042
|
declare function detectArgsPii(args: unknown): PiiPattern[];
|
|
1006
1043
|
|
|
1007
|
-
|
|
1044
|
+
interface CanaryValue {
|
|
1045
|
+
id: string;
|
|
1046
|
+
value: string;
|
|
1047
|
+
retired?: boolean;
|
|
1048
|
+
}
|
|
1049
|
+
type CanaryView = 'raw' | 'url-decoded' | 'base64-decoded' | 'hex-decoded' | 'separators-stripped';
|
|
1050
|
+
interface CanaryHit {
|
|
1051
|
+
id: string;
|
|
1052
|
+
view: CanaryView;
|
|
1053
|
+
fieldPath?: string;
|
|
1054
|
+
retired: boolean;
|
|
1055
|
+
}
|
|
1056
|
+
/** Values shorter than this are skipped by the matcher AND rejected by the registry (H12):
|
|
1057
|
+
* below 16 the separators-stripped view starts to collide with ordinary text. */
|
|
1058
|
+
declare const CANARY_MIN_LENGTH = 16;
|
|
1059
|
+
/** Exact containment of any registered value in any bounded view of the text. */
|
|
1060
|
+
declare function matchCanary(text: string, values: readonly CanaryValue[]): CanaryHit | null;
|
|
1061
|
+
/** Walks string leaves (depth <= 6, per-field budget), parsing JSON-in-string leaves
|
|
1062
|
+
* so escaped values are seen (B23), like scanArgs. */
|
|
1063
|
+
declare function matchCanaryArgs(args: unknown, values: readonly CanaryValue[]): CanaryHit | null;
|
|
1064
|
+
|
|
1065
|
+
type CanonicalFindingType = 'smart-rule' | 'ast-fs-op' | 'dlp' | 'pii' | 'canary' | 'sensitive-file-read' | 'privilege-escalation' | 'destructive-op' | 'pipe-to-shell' | 'eval-of-remote' | 'loop' | 'long-output-redacted';
|
|
1008
1066
|
type CanonicalAgent = 'claude' | 'gemini' | 'codex' | 'shell';
|
|
1009
1067
|
type CanonicalSourceType = 'default' | 'shield' | 'user' | 'engine';
|
|
1010
1068
|
interface CanonicalFinding {
|
|
@@ -1083,6 +1141,13 @@ interface ExtractContext {
|
|
|
1083
1141
|
toolInspection: Record<string, string>;
|
|
1084
1142
|
/** DLP enabled flag from PolicyConfig. */
|
|
1085
1143
|
dlpEnabled: boolean;
|
|
1144
|
+
/** Decoy credentials registered on this machine (value plus kind and plant
|
|
1145
|
+
* path for the finding text). Optional: absent or empty means no canary
|
|
1146
|
+
* pass, which keeps extractor output machine-independent in CI (H3). */
|
|
1147
|
+
canaryValues?: ReadonlyArray<CanaryValue & {
|
|
1148
|
+
kind?: string;
|
|
1149
|
+
path?: string;
|
|
1150
|
+
}>;
|
|
1086
1151
|
}
|
|
1087
1152
|
interface SessionExtractContext {
|
|
1088
1153
|
sessionId: string;
|
|
@@ -1131,7 +1196,7 @@ declare const LONG_OUTPUT_THRESHOLD_BYTES: number;
|
|
|
1131
1196
|
* and fails CI when the hash drifts without a version bump — forgetting
|
|
1132
1197
|
* is loud, not silent.
|
|
1133
1198
|
*/
|
|
1134
|
-
declare const CANONICAL_EXTRACTOR_VERSION = "canonical-
|
|
1199
|
+
declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v10";
|
|
1135
1200
|
/**
|
|
1136
1201
|
* SHA-256 prefix of the detector-source files
|
|
1137
1202
|
* (canonical.ts + pii.ts + destructive-regex.ts).
|
|
@@ -1142,7 +1207,7 @@ declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v9";
|
|
|
1142
1207
|
* files changed, this hash must change too, and you must consciously
|
|
1143
1208
|
* decide whether to bump CANONICAL_EXTRACTOR_VERSION."
|
|
1144
1209
|
*/
|
|
1145
|
-
declare const CANONICAL_EXTRACTOR_HASH = "
|
|
1210
|
+
declare const CANONICAL_EXTRACTOR_HASH = "5c786cc174281e51";
|
|
1146
1211
|
declare function extractCanonicalFindings(call: ToolCallEntry, ctx: ExtractContext): CanonicalFinding[];
|
|
1147
1212
|
declare function extractSessionLevelFindings(calls: ReadonlyArray<SessionToolCall>, ctx: SessionExtractContext): CanonicalFinding[];
|
|
1148
1213
|
/**
|
|
@@ -1166,7 +1231,64 @@ declare function dedupeCanonicalFindings(findings: ReadonlyArray<CanonicalFindin
|
|
|
1166
1231
|
declare function toScanFinding(c: CanonicalFinding): ScanFinding | null;
|
|
1167
1232
|
declare function previewArgs(input: Record<string, unknown>, max: number): string;
|
|
1168
1233
|
|
|
1234
|
+
type SsrfTier = 'metadata' | 'link-local' | 'multicast' | 'unspecified' | 'cgnat' | 'private';
|
|
1235
|
+
interface SsrfMatch {
|
|
1236
|
+
tier: SsrfTier;
|
|
1237
|
+
/** false for tier 1: no allowlist entry exempts it. */
|
|
1238
|
+
overridable: boolean;
|
|
1239
|
+
/** 'address' when an IP literal matched, 'hostname' for the metadata name list. */
|
|
1240
|
+
kind: 'address' | 'hostname';
|
|
1241
|
+
/** The canonical address; absent for a hostname match. Never an empty string:
|
|
1242
|
+
* an empty value is dropped in flight by cloud.ts and the audit shipper. */
|
|
1243
|
+
normalized?: string;
|
|
1244
|
+
}
|
|
1245
|
+
/** Longest legal DNS name. The caller does NOT reliably bound this: a URL with a
|
|
1246
|
+
* 261-character host reaches us intact (measured), so we bound our own input. */
|
|
1247
|
+
declare const SSRF_MAX_HOST = 253;
|
|
1248
|
+
/**
|
|
1249
|
+
* Fold any spelling of an IP literal to one canonical address, or null when the
|
|
1250
|
+
* input is not an IP literal (a hostname, or malformed). Never throws.
|
|
1251
|
+
*
|
|
1252
|
+
* IPv4-mapped IPv6 folds to the IPv4 address it denotes (RFC 4291 2.5.5.2), so
|
|
1253
|
+
* `[::ffff:a9fe:a9fe]` and `169.254.169.254` compare equal. Brackets and a zone
|
|
1254
|
+
* id are stripped here: the caller does NOT strip them (measured).
|
|
1255
|
+
*/
|
|
1256
|
+
declare function normalizeIpLiteral(host: string): string | null;
|
|
1257
|
+
/**
|
|
1258
|
+
* Classify a destination host. Returns null when it is not a protected address,
|
|
1259
|
+
* which means the ordinary egress policy decides. Never throws.
|
|
1260
|
+
*
|
|
1261
|
+
* Ordering is significant: the exact metadata addresses are checked before the
|
|
1262
|
+
* link-local range that contains them, so the reason names metadata.
|
|
1263
|
+
*/
|
|
1264
|
+
declare function classifySsrf(host: string): SsrfMatch | null;
|
|
1265
|
+
interface SsrfVerdict extends SsrfMatch {
|
|
1266
|
+
/** The token as written in the command. */
|
|
1267
|
+
host: string;
|
|
1268
|
+
binary: string;
|
|
1269
|
+
reason: string;
|
|
1270
|
+
}
|
|
1271
|
+
interface SsrfFloorOptions {
|
|
1272
|
+
/** Exempts OVERRIDABLE tiers only. A tier-1 entry here is ignored (and is
|
|
1273
|
+
* rejected at config load with a reason, never silently). */
|
|
1274
|
+
ssrfAllow?: readonly string[];
|
|
1275
|
+
/** Opt-in tier 3: loopback and RFC1918. Off by default: a developer talks to
|
|
1276
|
+
* those constantly (72 of 308 destinations on measured real history). */
|
|
1277
|
+
ssrfStrict?: boolean;
|
|
1278
|
+
}
|
|
1279
|
+
/**
|
|
1280
|
+
* The floor. Returns the first protected destination, or null.
|
|
1281
|
+
*
|
|
1282
|
+
* Runs unconditionally: not gated on egress.enabled, mode, allow or allowPrivate.
|
|
1283
|
+
* The one thing that does switch it off is `node9 pause`, which returns before
|
|
1284
|
+
* every gate; that is stated as a limit rather than special-cased here.
|
|
1285
|
+
*/
|
|
1286
|
+
declare function ssrfFloor(tokens: ReadonlyArray<{
|
|
1287
|
+
token: string;
|
|
1288
|
+
binary: string;
|
|
1289
|
+
}>, opts?: SsrfFloorOptions): SsrfVerdict | null;
|
|
1290
|
+
|
|
1169
1291
|
/** Engine version stamped on audit entries for future drift detection. */
|
|
1170
1292
|
declare const ENGINE_VERSION = "1.4.0";
|
|
1171
1293
|
|
|
1172
|
-
export { AST_FS_REGEX_RULES, type AuditEntryForClassify, BASH_TOOL_NAMES, BUILTIN_SHIELDS, type BlastEnvFinding, type BlastFinding, type BlastResult, type BlastSummary, CANONICAL_EXTRACTOR_HASH, CANONICAL_EXTRACTOR_VERSION, COST_PER_LOOP_ITER_USD, type CanonicalAgent, type CanonicalFinding, type CanonicalFindingType, type CanonicalSourceType, DEFAULT_EGRESS_ALLOWLIST, 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, PRIVILEGE_ESCALATION_RE, type PiiPattern, type PipeChainAnalysis, type PolicyConfig, type PolicyContext, type PolicyHostHooks, type PolicyVerdict, type ProvenanceLookup, type ProvenanceTrust, REALTIME_PII_PATTERNS, type RiskMetadata, SCAN_SIGNAL_WEIGHTS, SENSITIVE_PATH_RE, SENSITIVE_PATH_REGEXES, type ScanFinding, type ScanSignals, type ScanSummary, type ScoreTier, type SessionExtractContext, type SessionToolCall, type Severity, type ShellCommandAnalysis, type ShellDestination, type ShieldDefinition, type ShieldOverrides, type ShieldVerdict, type SmartCondition, type SmartRule, type ToolCallEntry, type ToolCallRecord, analyzeFsOperation, analyzePipeChain, analyzeShellCommand, checkDangerousSql, classifyAuditEntry, classifyRuleSeverity, classifyScanSignal, computeAgentDeviceScore, computeArgsHash, computeBlendedSecurityScore, computeScanScore, computeSecurityScore, dedupeCanonicalFindings, detectArgsPii, detectDangerousEval, detectDangerousShellExec, detectInlineExec, detectPii, evaluateEgress, evaluateLoopWindow, evaluatePolicy, evaluateSmartConditions, extractAllSshHosts, extractCanonicalFindings, extractNetworkTargets, extractPositionalArgs, extractSessionLevelFindings, extractShellDestinations, getCompiledRegex, getNestedValue, hostMatches, isBashTool, isIgnoredTool, isPrivateHost, isProtectedHomePath, isShellShapedTool, isShieldVerdict, matchSensitivePath, matchesPattern, narrativeRuleLabel, normalizeCommandForPolicy, parseAllSshHostsFromCommand, parseDestHost, previewArgs, redactText, resolvePinned, scanArgs, scanInjection, scanText, sensitivePathMatch, summarizeBlast, summarizeScan, toScanFinding, toolMatchesRule, truncateBlastPath, validateOverrides, validateRegex, validateShieldDefinition };
|
|
1294
|
+
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, COST_PER_LOOP_ITER_USD, type CanaryHit, type CanaryValue, type CanaryView, type CanonicalAgent, type CanonicalFinding, type CanonicalFindingType, type CanonicalSourceType, DEFAULT_EGRESS_ALLOWLIST, 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, PRIVILEGE_ESCALATION_RE, type PiiPattern, type PipeChainAnalysis, type PolicyConfig, type PolicyContext, type PolicyHostHooks, type PolicyVerdict, 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, getCompiledRegex, getNestedValue, hostMatches, isBashTool, isIgnoredTool, isPrivateHost, isProtectedHomePath, isShellShapedTool, isShieldVerdict, matchCanary, matchCanaryArgs, matchSensitivePath, matchesPattern, narrativeRuleLabel, normalizeCommandForPolicy, normalizeIpLiteral, parseAllSshHostsFromCommand, parseDestHost, previewArgs, redactText, resolvePinned, scanArgs, scanInjection, scanText, sensitivePathMatch, ssrfFloor, summarizeBlast, summarizeScan, toScanFinding, toolMatchesRule, truncateBlastPath, validateOverrides, validateRegex, validateShieldDefinition };
|
package/dist/index.d.ts
CHANGED
|
@@ -136,6 +136,15 @@ interface DlpPattern {
|
|
|
136
136
|
* Only set on broad patterns where the regex alone can't distinguish real secrets.
|
|
137
137
|
*/
|
|
138
138
|
minEntropy?: number;
|
|
139
|
+
/**
|
|
140
|
+
* Structural validator run on the matched token (checksum, version byte).
|
|
141
|
+
* When present it DECIDES: a passing validator accepts the match outright,
|
|
142
|
+
* skipping the stopword and entropy heuristics (a checksum-valid token that
|
|
143
|
+
* happens to contain a stopword substring is a real secret, roughly 1 in
|
|
144
|
+
* 3,000 real WIF keys); a failing one rejects it. Must never throw; a throw
|
|
145
|
+
* is treated as "not suppressed" so a validator bug cannot hide a match.
|
|
146
|
+
*/
|
|
147
|
+
validate?: (raw: string) => boolean;
|
|
139
148
|
}
|
|
140
149
|
declare const DLP_PATTERNS: DlpPattern[];
|
|
141
150
|
/**
|
|
@@ -168,11 +177,6 @@ declare const DLP_SCAN_LIMITS: {
|
|
|
168
177
|
/** Max nesting depth walked; anything deeper is NOT scanned. */
|
|
169
178
|
readonly maxDepth: 5;
|
|
170
179
|
};
|
|
171
|
-
/**
|
|
172
|
-
* Recursively scans an args value for known secret patterns.
|
|
173
|
-
* Handles nested objects, arrays, and JSON-encoded strings.
|
|
174
|
-
* Returns the first match found, or null if clean.
|
|
175
|
-
*/
|
|
176
180
|
declare function scanArgs(args: unknown, depth?: number, fieldPath?: string): DlpMatch | null;
|
|
177
181
|
/** Scan a plain text string (e.g. Claude response prose) for DLP patterns. */
|
|
178
182
|
declare function scanText(text: string): DlpMatch | null;
|
|
@@ -264,6 +268,25 @@ declare function parseDestHost(token: string): string | null;
|
|
|
264
268
|
* and parses the host. Deduplicated by host. Pure — no I/O, no DNS.
|
|
265
269
|
*/
|
|
266
270
|
declare function extractShellDestinations(command: string): ShellDestination[];
|
|
271
|
+
/** A raw destination-position token from a network binary, BEFORE parseDestHost.
|
|
272
|
+
* The SSRF floor needs these because parseDestHost requires a dot and therefore
|
|
273
|
+
* drops `2852039166`, which denotes a cloud metadata address (measured: that
|
|
274
|
+
* command is allowed today at the strictest egress setting). */
|
|
275
|
+
interface ShellDestToken {
|
|
276
|
+
token: string;
|
|
277
|
+
binary: string;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Destination-position tokens for every network binary in a command, unparsed.
|
|
281
|
+
*
|
|
282
|
+
* Same walk and same flag-skipping as extractShellDestinations, so the two agree
|
|
283
|
+
* on which arguments are destinations. It exists as a sibling rather than a
|
|
284
|
+
* widening of parseDestHost because the dot requirement there is a load-bearing
|
|
285
|
+
* false-positive guard: turning every numeric token into a HOST would change
|
|
286
|
+
* egress verdicts for every user. Asking whether a token DENOTES A PROTECTED
|
|
287
|
+
* ADDRESS has no false-positive surface, because that comparison is exact.
|
|
288
|
+
*/
|
|
289
|
+
declare function extractShellDestTokens(command: string): ShellDestToken[];
|
|
267
290
|
declare function analyzeFsOperation(command: string): FsOpVerdict | null;
|
|
268
291
|
interface ShellCommandAnalysis {
|
|
269
292
|
/** First word of every CallExpr — the command names invoked. */
|
|
@@ -291,6 +314,14 @@ interface EgressPolicy {
|
|
|
291
314
|
deny: string[];
|
|
292
315
|
/** Auto-allow localhost / RFC1918 / *.local. Default true. */
|
|
293
316
|
allowPrivate: boolean;
|
|
317
|
+
/** SSRF floor: exempts OVERRIDABLE tiers only (carrier-grade NAT, and
|
|
318
|
+
* loopback/RFC1918 when ssrfStrict is on). A tier-1 entry is ignored here
|
|
319
|
+
* and rejected at config load with a reason. */
|
|
320
|
+
ssrfAllow?: readonly string[];
|
|
321
|
+
/** SSRF floor tier 3: also block loopback and RFC1918. Off by default,
|
|
322
|
+
* because a developer talks to those constantly (72 of 308 destinations on
|
|
323
|
+
* measured real history). */
|
|
324
|
+
ssrfStrict?: boolean;
|
|
294
325
|
}
|
|
295
326
|
interface EgressVerdict {
|
|
296
327
|
verdict: 'block' | 'review';
|
|
@@ -990,7 +1021,7 @@ declare const SENSITIVE_PATH_RE: RegExp;
|
|
|
990
1021
|
*/
|
|
991
1022
|
declare const FILE_TOOLS: Set<string>;
|
|
992
1023
|
|
|
993
|
-
type PiiPattern = 'Email' | 'SSN' | 'Phone' | 'Credit Card';
|
|
1024
|
+
type PiiPattern = 'Email' | 'SSN' | 'Phone' | 'Credit Card' | 'IBAN';
|
|
994
1025
|
/**
|
|
995
1026
|
* Detect PII patterns in a string. Returns a deduplicated list — one entry
|
|
996
1027
|
* per distinct pattern type, never multiple "Email" findings from one input.
|
|
@@ -998,13 +1029,40 @@ type PiiPattern = 'Email' | 'SSN' | 'Phone' | 'Credit Card';
|
|
|
998
1029
|
declare function detectPii(text: string): PiiPattern[];
|
|
999
1030
|
declare const REALTIME_PII_PATTERNS: readonly PiiPattern[];
|
|
1000
1031
|
/**
|
|
1001
|
-
* Realtime adapter for detectPii: walks a tool-args value
|
|
1002
|
-
*
|
|
1003
|
-
*
|
|
1032
|
+
* Realtime adapter for detectPii: walks a tool-args value leaf by leaf and
|
|
1033
|
+
* returns only the high-signal PII patterns found. Used by the authorize path
|
|
1034
|
+
* to gate SSN / Credit Card in tool arguments. Pure.
|
|
1035
|
+
*
|
|
1036
|
+
* Walks leaves rather than scanning JSON.stringify(args). Stringifying turns
|
|
1037
|
+
* a real newline into the two characters backslash + `n`, and `n` is a word
|
|
1038
|
+
* character, so a card or SSN that BEGINS A LINE inside a multi-line value
|
|
1039
|
+
* (a CSV being written, for instance) had no \b in front of it and was
|
|
1040
|
+
* invisible to the realtime gate. Raw leaves keep the real newline.
|
|
1004
1041
|
*/
|
|
1005
1042
|
declare function detectArgsPii(args: unknown): PiiPattern[];
|
|
1006
1043
|
|
|
1007
|
-
|
|
1044
|
+
interface CanaryValue {
|
|
1045
|
+
id: string;
|
|
1046
|
+
value: string;
|
|
1047
|
+
retired?: boolean;
|
|
1048
|
+
}
|
|
1049
|
+
type CanaryView = 'raw' | 'url-decoded' | 'base64-decoded' | 'hex-decoded' | 'separators-stripped';
|
|
1050
|
+
interface CanaryHit {
|
|
1051
|
+
id: string;
|
|
1052
|
+
view: CanaryView;
|
|
1053
|
+
fieldPath?: string;
|
|
1054
|
+
retired: boolean;
|
|
1055
|
+
}
|
|
1056
|
+
/** Values shorter than this are skipped by the matcher AND rejected by the registry (H12):
|
|
1057
|
+
* below 16 the separators-stripped view starts to collide with ordinary text. */
|
|
1058
|
+
declare const CANARY_MIN_LENGTH = 16;
|
|
1059
|
+
/** Exact containment of any registered value in any bounded view of the text. */
|
|
1060
|
+
declare function matchCanary(text: string, values: readonly CanaryValue[]): CanaryHit | null;
|
|
1061
|
+
/** Walks string leaves (depth <= 6, per-field budget), parsing JSON-in-string leaves
|
|
1062
|
+
* so escaped values are seen (B23), like scanArgs. */
|
|
1063
|
+
declare function matchCanaryArgs(args: unknown, values: readonly CanaryValue[]): CanaryHit | null;
|
|
1064
|
+
|
|
1065
|
+
type CanonicalFindingType = 'smart-rule' | 'ast-fs-op' | 'dlp' | 'pii' | 'canary' | 'sensitive-file-read' | 'privilege-escalation' | 'destructive-op' | 'pipe-to-shell' | 'eval-of-remote' | 'loop' | 'long-output-redacted';
|
|
1008
1066
|
type CanonicalAgent = 'claude' | 'gemini' | 'codex' | 'shell';
|
|
1009
1067
|
type CanonicalSourceType = 'default' | 'shield' | 'user' | 'engine';
|
|
1010
1068
|
interface CanonicalFinding {
|
|
@@ -1083,6 +1141,13 @@ interface ExtractContext {
|
|
|
1083
1141
|
toolInspection: Record<string, string>;
|
|
1084
1142
|
/** DLP enabled flag from PolicyConfig. */
|
|
1085
1143
|
dlpEnabled: boolean;
|
|
1144
|
+
/** Decoy credentials registered on this machine (value plus kind and plant
|
|
1145
|
+
* path for the finding text). Optional: absent or empty means no canary
|
|
1146
|
+
* pass, which keeps extractor output machine-independent in CI (H3). */
|
|
1147
|
+
canaryValues?: ReadonlyArray<CanaryValue & {
|
|
1148
|
+
kind?: string;
|
|
1149
|
+
path?: string;
|
|
1150
|
+
}>;
|
|
1086
1151
|
}
|
|
1087
1152
|
interface SessionExtractContext {
|
|
1088
1153
|
sessionId: string;
|
|
@@ -1131,7 +1196,7 @@ declare const LONG_OUTPUT_THRESHOLD_BYTES: number;
|
|
|
1131
1196
|
* and fails CI when the hash drifts without a version bump — forgetting
|
|
1132
1197
|
* is loud, not silent.
|
|
1133
1198
|
*/
|
|
1134
|
-
declare const CANONICAL_EXTRACTOR_VERSION = "canonical-
|
|
1199
|
+
declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v10";
|
|
1135
1200
|
/**
|
|
1136
1201
|
* SHA-256 prefix of the detector-source files
|
|
1137
1202
|
* (canonical.ts + pii.ts + destructive-regex.ts).
|
|
@@ -1142,7 +1207,7 @@ declare const CANONICAL_EXTRACTOR_VERSION = "canonical-v9";
|
|
|
1142
1207
|
* files changed, this hash must change too, and you must consciously
|
|
1143
1208
|
* decide whether to bump CANONICAL_EXTRACTOR_VERSION."
|
|
1144
1209
|
*/
|
|
1145
|
-
declare const CANONICAL_EXTRACTOR_HASH = "
|
|
1210
|
+
declare const CANONICAL_EXTRACTOR_HASH = "5c786cc174281e51";
|
|
1146
1211
|
declare function extractCanonicalFindings(call: ToolCallEntry, ctx: ExtractContext): CanonicalFinding[];
|
|
1147
1212
|
declare function extractSessionLevelFindings(calls: ReadonlyArray<SessionToolCall>, ctx: SessionExtractContext): CanonicalFinding[];
|
|
1148
1213
|
/**
|
|
@@ -1166,7 +1231,64 @@ declare function dedupeCanonicalFindings(findings: ReadonlyArray<CanonicalFindin
|
|
|
1166
1231
|
declare function toScanFinding(c: CanonicalFinding): ScanFinding | null;
|
|
1167
1232
|
declare function previewArgs(input: Record<string, unknown>, max: number): string;
|
|
1168
1233
|
|
|
1234
|
+
type SsrfTier = 'metadata' | 'link-local' | 'multicast' | 'unspecified' | 'cgnat' | 'private';
|
|
1235
|
+
interface SsrfMatch {
|
|
1236
|
+
tier: SsrfTier;
|
|
1237
|
+
/** false for tier 1: no allowlist entry exempts it. */
|
|
1238
|
+
overridable: boolean;
|
|
1239
|
+
/** 'address' when an IP literal matched, 'hostname' for the metadata name list. */
|
|
1240
|
+
kind: 'address' | 'hostname';
|
|
1241
|
+
/** The canonical address; absent for a hostname match. Never an empty string:
|
|
1242
|
+
* an empty value is dropped in flight by cloud.ts and the audit shipper. */
|
|
1243
|
+
normalized?: string;
|
|
1244
|
+
}
|
|
1245
|
+
/** Longest legal DNS name. The caller does NOT reliably bound this: a URL with a
|
|
1246
|
+
* 261-character host reaches us intact (measured), so we bound our own input. */
|
|
1247
|
+
declare const SSRF_MAX_HOST = 253;
|
|
1248
|
+
/**
|
|
1249
|
+
* Fold any spelling of an IP literal to one canonical address, or null when the
|
|
1250
|
+
* input is not an IP literal (a hostname, or malformed). Never throws.
|
|
1251
|
+
*
|
|
1252
|
+
* IPv4-mapped IPv6 folds to the IPv4 address it denotes (RFC 4291 2.5.5.2), so
|
|
1253
|
+
* `[::ffff:a9fe:a9fe]` and `169.254.169.254` compare equal. Brackets and a zone
|
|
1254
|
+
* id are stripped here: the caller does NOT strip them (measured).
|
|
1255
|
+
*/
|
|
1256
|
+
declare function normalizeIpLiteral(host: string): string | null;
|
|
1257
|
+
/**
|
|
1258
|
+
* Classify a destination host. Returns null when it is not a protected address,
|
|
1259
|
+
* which means the ordinary egress policy decides. Never throws.
|
|
1260
|
+
*
|
|
1261
|
+
* Ordering is significant: the exact metadata addresses are checked before the
|
|
1262
|
+
* link-local range that contains them, so the reason names metadata.
|
|
1263
|
+
*/
|
|
1264
|
+
declare function classifySsrf(host: string): SsrfMatch | null;
|
|
1265
|
+
interface SsrfVerdict extends SsrfMatch {
|
|
1266
|
+
/** The token as written in the command. */
|
|
1267
|
+
host: string;
|
|
1268
|
+
binary: string;
|
|
1269
|
+
reason: string;
|
|
1270
|
+
}
|
|
1271
|
+
interface SsrfFloorOptions {
|
|
1272
|
+
/** Exempts OVERRIDABLE tiers only. A tier-1 entry here is ignored (and is
|
|
1273
|
+
* rejected at config load with a reason, never silently). */
|
|
1274
|
+
ssrfAllow?: readonly string[];
|
|
1275
|
+
/** Opt-in tier 3: loopback and RFC1918. Off by default: a developer talks to
|
|
1276
|
+
* those constantly (72 of 308 destinations on measured real history). */
|
|
1277
|
+
ssrfStrict?: boolean;
|
|
1278
|
+
}
|
|
1279
|
+
/**
|
|
1280
|
+
* The floor. Returns the first protected destination, or null.
|
|
1281
|
+
*
|
|
1282
|
+
* Runs unconditionally: not gated on egress.enabled, mode, allow or allowPrivate.
|
|
1283
|
+
* The one thing that does switch it off is `node9 pause`, which returns before
|
|
1284
|
+
* every gate; that is stated as a limit rather than special-cased here.
|
|
1285
|
+
*/
|
|
1286
|
+
declare function ssrfFloor(tokens: ReadonlyArray<{
|
|
1287
|
+
token: string;
|
|
1288
|
+
binary: string;
|
|
1289
|
+
}>, opts?: SsrfFloorOptions): SsrfVerdict | null;
|
|
1290
|
+
|
|
1169
1291
|
/** Engine version stamped on audit entries for future drift detection. */
|
|
1170
1292
|
declare const ENGINE_VERSION = "1.4.0";
|
|
1171
1293
|
|
|
1172
|
-
export { AST_FS_REGEX_RULES, type AuditEntryForClassify, BASH_TOOL_NAMES, BUILTIN_SHIELDS, type BlastEnvFinding, type BlastFinding, type BlastResult, type BlastSummary, CANONICAL_EXTRACTOR_HASH, CANONICAL_EXTRACTOR_VERSION, COST_PER_LOOP_ITER_USD, type CanonicalAgent, type CanonicalFinding, type CanonicalFindingType, type CanonicalSourceType, DEFAULT_EGRESS_ALLOWLIST, 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, PRIVILEGE_ESCALATION_RE, type PiiPattern, type PipeChainAnalysis, type PolicyConfig, type PolicyContext, type PolicyHostHooks, type PolicyVerdict, type ProvenanceLookup, type ProvenanceTrust, REALTIME_PII_PATTERNS, type RiskMetadata, SCAN_SIGNAL_WEIGHTS, SENSITIVE_PATH_RE, SENSITIVE_PATH_REGEXES, type ScanFinding, type ScanSignals, type ScanSummary, type ScoreTier, type SessionExtractContext, type SessionToolCall, type Severity, type ShellCommandAnalysis, type ShellDestination, type ShieldDefinition, type ShieldOverrides, type ShieldVerdict, type SmartCondition, type SmartRule, type ToolCallEntry, type ToolCallRecord, analyzeFsOperation, analyzePipeChain, analyzeShellCommand, checkDangerousSql, classifyAuditEntry, classifyRuleSeverity, classifyScanSignal, computeAgentDeviceScore, computeArgsHash, computeBlendedSecurityScore, computeScanScore, computeSecurityScore, dedupeCanonicalFindings, detectArgsPii, detectDangerousEval, detectDangerousShellExec, detectInlineExec, detectPii, evaluateEgress, evaluateLoopWindow, evaluatePolicy, evaluateSmartConditions, extractAllSshHosts, extractCanonicalFindings, extractNetworkTargets, extractPositionalArgs, extractSessionLevelFindings, extractShellDestinations, getCompiledRegex, getNestedValue, hostMatches, isBashTool, isIgnoredTool, isPrivateHost, isProtectedHomePath, isShellShapedTool, isShieldVerdict, matchSensitivePath, matchesPattern, narrativeRuleLabel, normalizeCommandForPolicy, parseAllSshHostsFromCommand, parseDestHost, previewArgs, redactText, resolvePinned, scanArgs, scanInjection, scanText, sensitivePathMatch, summarizeBlast, summarizeScan, toScanFinding, toolMatchesRule, truncateBlastPath, validateOverrides, validateRegex, validateShieldDefinition };
|
|
1294
|
+
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, COST_PER_LOOP_ITER_USD, type CanaryHit, type CanaryValue, type CanaryView, type CanonicalAgent, type CanonicalFinding, type CanonicalFindingType, type CanonicalSourceType, DEFAULT_EGRESS_ALLOWLIST, 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, PRIVILEGE_ESCALATION_RE, type PiiPattern, type PipeChainAnalysis, type PolicyConfig, type PolicyContext, type PolicyHostHooks, type PolicyVerdict, 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, getCompiledRegex, getNestedValue, hostMatches, isBashTool, isIgnoredTool, isPrivateHost, isProtectedHomePath, isShellShapedTool, isShieldVerdict, matchCanary, matchCanaryArgs, matchSensitivePath, matchesPattern, narrativeRuleLabel, normalizeCommandForPolicy, normalizeIpLiteral, parseAllSshHostsFromCommand, parseDestHost, previewArgs, redactText, resolvePinned, scanArgs, scanInjection, scanText, sensitivePathMatch, ssrfFloor, summarizeBlast, summarizeScan, toScanFinding, toolMatchesRule, truncateBlastPath, validateOverrides, validateRegex, validateShieldDefinition };
|