monofence-ai 1.0.0

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.
Files changed (46) hide show
  1. package/README.md +276 -0
  2. package/dist/domain/entities/index.d.ts +2 -0
  3. package/dist/domain/entities/index.d.ts.map +1 -0
  4. package/dist/domain/entities/index.js +2 -0
  5. package/dist/domain/entities/index.js.map +1 -0
  6. package/dist/domain/entities/threat.d.ts +98 -0
  7. package/dist/domain/entities/threat.d.ts.map +1 -0
  8. package/dist/domain/entities/threat.js +21 -0
  9. package/dist/domain/entities/threat.js.map +1 -0
  10. package/dist/domain/services/allowlist.d.ts +11 -0
  11. package/dist/domain/services/allowlist.d.ts.map +1 -0
  12. package/dist/domain/services/allowlist.js +72 -0
  13. package/dist/domain/services/allowlist.js.map +1 -0
  14. package/dist/domain/services/context-tracker.d.ts +15 -0
  15. package/dist/domain/services/context-tracker.d.ts.map +1 -0
  16. package/dist/domain/services/context-tracker.js +75 -0
  17. package/dist/domain/services/context-tracker.js.map +1 -0
  18. package/dist/domain/services/evasion-detector.d.ts +12 -0
  19. package/dist/domain/services/evasion-detector.d.ts.map +1 -0
  20. package/dist/domain/services/evasion-detector.js +128 -0
  21. package/dist/domain/services/evasion-detector.js.map +1 -0
  22. package/dist/domain/services/index.d.ts +7 -0
  23. package/dist/domain/services/index.d.ts.map +1 -0
  24. package/dist/domain/services/index.js +7 -0
  25. package/dist/domain/services/index.js.map +1 -0
  26. package/dist/domain/services/output-scanner.d.ts +25 -0
  27. package/dist/domain/services/output-scanner.d.ts.map +1 -0
  28. package/dist/domain/services/output-scanner.js +113 -0
  29. package/dist/domain/services/output-scanner.js.map +1 -0
  30. package/dist/domain/services/threat-detection-service.d.ts +82 -0
  31. package/dist/domain/services/threat-detection-service.d.ts.map +1 -0
  32. package/dist/domain/services/threat-detection-service.js +426 -0
  33. package/dist/domain/services/threat-detection-service.js.map +1 -0
  34. package/dist/domain/services/threat-learning-service.d.ts +175 -0
  35. package/dist/domain/services/threat-learning-service.d.ts.map +1 -0
  36. package/dist/domain/services/threat-learning-service.js +295 -0
  37. package/dist/domain/services/threat-learning-service.js.map +1 -0
  38. package/dist/hooks/security-hook.d.ts +62 -0
  39. package/dist/hooks/security-hook.d.ts.map +1 -0
  40. package/dist/hooks/security-hook.js +132 -0
  41. package/dist/hooks/security-hook.js.map +1 -0
  42. package/dist/index.d.ts +191 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +284 -0
  45. package/dist/index.js.map +1 -0
  46. package/package.json +68 -0
package/README.md ADDED
@@ -0,0 +1,276 @@
1
+ # monofence-ai
2
+
3
+ [![npm version](https://img.shields.io/npm/v/monofence-ai?color=blue&label=npm)](https://www.npmjs.com/package/monofence-ai)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.3+-blue.svg)](https://www.typescriptlang.org/)
6
+ [![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/)
7
+
8
+ **AI manipulation defense for LLM applications** — evasion detection, multi-turn context tracking, output scanning, and hook wiring. Sub-millisecond detection with self-learning.
9
+
10
+ ```
11
+ Detection: ~0.04ms | 50+ patterns | evasion normalization | context-aware escalation
12
+ ```
13
+
14
+ ---
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ npm install monofence-ai
20
+ # or
21
+ pnpm add monofence-ai
22
+ ```
23
+
24
+ Optional — HNSW-accelerated pattern search:
25
+
26
+ ```bash
27
+ npm install lancedb
28
+ ```
29
+
30
+ ---
31
+
32
+ ## Quick start
33
+
34
+ ```typescript
35
+ import { isSafe, createMonoDefence } from 'monofence-ai';
36
+
37
+ // Fast boolean check
38
+ isSafe('Hello, help me write code'); // true
39
+ isSafe('Ignore all previous instructions'); // false
40
+
41
+ // Full detection with threat objects
42
+ const fence = createMonoDefence();
43
+ const result = await fence.detect(userInput);
44
+
45
+ if (!result.safe) {
46
+ // result.threats — array of detected threats
47
+ // result.overallRisk — 0.0–1.0
48
+ }
49
+ ```
50
+
51
+ ---
52
+
53
+ ## API
54
+
55
+ ### `createMonoDefence(config?)`
56
+
57
+ Creates a `MonoDefence` instance.
58
+
59
+ ```typescript
60
+ const fence = createMonoDefence({
61
+ enableLearning: true, // persist learned threat patterns (default: false)
62
+ enableContextTracking: true, // track escalation state across turns (default: false)
63
+ enablePIIDetection: true, // detect PII in inputs/outputs (default: true)
64
+ maxContextTurns: 20, // rolling window for context tracking (default: 20)
65
+ confidenceThreshold: 0.5, // minimum detection confidence (default: 0.5)
66
+ });
67
+ ```
68
+
69
+ ### `fence.detect(input)`
70
+
71
+ Full async scan. Returns:
72
+
73
+ ```typescript
74
+ {
75
+ safe: boolean; // false if any threat detected
76
+ threats: Threat[]; // detected threat objects with type/severity/confidence
77
+ piiFound: boolean;
78
+ overallRisk: number; // 0.0–1.0
79
+ detectionTimeMs: number;
80
+ }
81
+ ```
82
+
83
+ > When context tracking is on and escalation reaches `attack`, `overallRisk` is raised
84
+ > to at least 0.5 even when `safe=true`. Check both `safe` and `overallRisk` when using
85
+ > context tracking.
86
+
87
+ ### `fence.quickScan(input)`
88
+
89
+ Synchronous, sub-millisecond check. Returns `{ threat: boolean, confidence: number }`.
90
+
91
+ ### `isSafe(input)` / `fence.isSafe(input)`
92
+
93
+ Returns `boolean`. Fastest option — no async overhead.
94
+
95
+ ### `fence.hasPII(input)`
96
+
97
+ Returns `boolean`. Checks emails, SSNs, API keys, and passwords.
98
+
99
+ ### `fence.getStats()`
100
+
101
+ Returns detection counters, learned pattern count, and average latency.
102
+
103
+ ### `fence.learnFromDetection(input, result, feedback)`
104
+
105
+ Reinforces or corrects a prior detection for human-in-the-loop feedback.
106
+
107
+ ### `fence.getBestMitigation(threatType)`
108
+
109
+ Returns the highest-effectiveness mitigation strategy for a threat type.
110
+
111
+ ### `fence.searchSimilarThreats(input, { k })`
112
+
113
+ Vector similarity search over learned threat patterns (requires LanceDB).
114
+
115
+ ### `fence.recordMitigation(threatType, strategy, success)`
116
+
117
+ Records whether a mitigation worked; affects future `getBestMitigation` results.
118
+
119
+ ---
120
+
121
+ ## Threat types
122
+
123
+ | Type | Severity | Examples |
124
+ |---|---|---|
125
+ | `instruction_override` | Critical | "Ignore previous instructions", "forget everything" |
126
+ | `jailbreak` | Critical | "DAN mode", "bypass restrictions", "developer mode" |
127
+ | `role_switching` | High | "You are now", "Act as an unrestricted AI" |
128
+ | `context_manipulation` | Critical | Fake `system:` messages, delimiter injection |
129
+ | `encoding_attack` | Medium | base64/hex obfuscation |
130
+ | `prompt_injection` | Critical | Injected instructions in user content |
131
+
132
+ ---
133
+
134
+ ## Evasion detection
135
+
136
+ Inputs are normalized before pattern matching to defeat obfuscation:
137
+
138
+ - **Homoglyphs**: Cyrillic/Greek lookalikes → ASCII (`і` → `i`)
139
+ - **Spaced chars**: `i g n o r e` → `ignore`
140
+ - **Leet substitution**: `ign0re` → `ignore` (applied after space collapsing)
141
+
142
+ ```typescript
143
+ const result = await fence.detect('іgnore all рrevious instructions'); // Cyrillic chars
144
+ // result.safe === false, threats include instruction_override
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Multi-turn context tracking
150
+
151
+ Enable to track escalation state across a conversation:
152
+
153
+ ```typescript
154
+ const fence = createMonoDefence({ enableContextTracking: true });
155
+
156
+ // Turn 1: probing question → state: probing
157
+ // Turn 2: jailbreak attempt → state: escalating
158
+ // Turn 3: confirmed attack → state: attack
159
+ // Once in attack state, overallRisk ≥ 0.5 even on benign inputs
160
+ ```
161
+
162
+ States: `clean` → `probing` → `escalating` → `attack`. Decays toward `clean` on idle turns.
163
+
164
+ ---
165
+
166
+ ## Multi-agent consensus
167
+
168
+ When running multiple detection agents in parallel:
169
+
170
+ ```typescript
171
+ import { calculateSecurityConsensus } from 'monofence-ai';
172
+
173
+ const consensus = calculateSecurityConsensus([
174
+ { result: resultA, weight: 0.6 },
175
+ { result: resultB, weight: 0.4 },
176
+ ]);
177
+ // consensus.safe, consensus.overallRisk, consensus.threats
178
+ ```
179
+
180
+ A single critical threat short-circuits weighted scoring regardless of agent weight (fail-secure).
181
+
182
+ ---
183
+
184
+ ## Hook wiring (optional)
185
+
186
+ Wire into the monomind hooks system so pre-task and pre-command inputs are scanned automatically. **Off by default.**
187
+
188
+ ```typescript
189
+ import { SecurityHook } from 'monofence-ai/hooks';
190
+
191
+ SecurityHook.register({ priority: 1000 });
192
+ // Runs before all other hooks; aborts on attack escalation state
193
+ ```
194
+
195
+ Or from the CLI:
196
+
197
+ ```bash
198
+ npx monomind hooks pre-task --monofence-ai-check
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Review integration
204
+
205
+ When using `mastermind:review`, two flags activate monofence-ai analysis:
206
+
207
+ | Flag | Effect |
208
+ |---|---|
209
+ | `--monofence-ai-check` | Test suite + adversarial probes against the live detector |
210
+ | `--monofence-ai-security-deep` | Scan LLM input boundaries for unprotected paths |
211
+
212
+ Both are off by default:
213
+
214
+ ```bash
215
+ /mastermind:review --monofence-ai-check --monofence-ai-security-deep
216
+ ```
217
+
218
+ ---
219
+
220
+ ## MCP tools
221
+
222
+ Six MCP tools are available when monomind is installed:
223
+
224
+ | Tool | Description |
225
+ |---|---|
226
+ | `aidefence_scan` | Scan input for threats (`input`, `quick?`) |
227
+ | `aidefence_analyze` | Deep analysis with similar-pattern search |
228
+ | `aidefence_stats` | Detection and learning statistics |
229
+ | `aidefence_learn` | Record feedback for pattern learning |
230
+ | `aidefence_is_safe` | Quick boolean check |
231
+ | `aidefence_has_pii` | PII detection only |
232
+
233
+ ---
234
+
235
+ ## Performance
236
+
237
+ | Operation | Typical latency |
238
+ |---|---|
239
+ | Full `detect()` | ~0.04ms |
240
+ | `quickScan()` | ~0.02ms |
241
+ | PII check | ~0.01ms |
242
+ | HNSW search (LanceDB) | ~0.1ms |
243
+
244
+ Throughput: >12,000 req/s single-threaded. Memory: ~50KB per instance.
245
+
246
+ ---
247
+
248
+ ## Deprecated aliases
249
+
250
+ Still exported for backward compatibility; will be removed in v2:
251
+
252
+ | Deprecated | Replacement |
253
+ |---|---|
254
+ | `createAIDefence` | `createMonoDefence` |
255
+ | `getAIDefence` | `getMonoDefence` |
256
+ | `AIDefenceConfig` | `MonoDefenceConfig` |
257
+ | `AIDefence` | `MonoDefence` |
258
+
259
+ ---
260
+
261
+ ## Development
262
+
263
+ ```bash
264
+ git clone https://github.com/monoes/monomind.git
265
+ cd monomind/packages/monofence-ai
266
+
267
+ npm install
268
+ npm test # vitest run
269
+ npm run build # tsc
270
+ ```
271
+
272
+ ---
273
+
274
+ ## License
275
+
276
+ MIT — part of the [Monomind](https://github.com/monoes/monomind) ecosystem.
@@ -0,0 +1,2 @@
1
+ export * from './threat.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/domain/entities/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './threat.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/domain/entities/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Threat Domain Entity
3
+ *
4
+ * Represents a detected security threat from AI manipulation attempts.
5
+ */
6
+ export type ThreatSeverity = 'low' | 'medium' | 'high' | 'critical';
7
+ export type ThreatType = 'prompt_injection' | 'jailbreak' | 'pii_exposure' | 'instruction_override' | 'role_switching' | 'context_manipulation' | 'encoding_attack' | 'unknown';
8
+ export interface Threat {
9
+ readonly id: string;
10
+ readonly type: ThreatType;
11
+ readonly severity: ThreatSeverity;
12
+ readonly confidence: number;
13
+ readonly pattern: string;
14
+ readonly description: string;
15
+ readonly location?: {
16
+ start: number;
17
+ end: number;
18
+ };
19
+ readonly detectedAt: Date;
20
+ }
21
+ export interface ThreatDetectionResult {
22
+ readonly safe: boolean;
23
+ readonly threats: Threat[];
24
+ readonly detectionTimeMs: number;
25
+ readonly piiFound: boolean;
26
+ readonly inputHash: string;
27
+ readonly wasObfuscated?: boolean;
28
+ /** Aggregate risk score [0, 1] derived from highest-confidence threat; boosted when obfuscation detected */
29
+ readonly overallRisk: number;
30
+ }
31
+ export interface BehavioralAnalysisResult {
32
+ readonly agentId: string;
33
+ readonly anomalyScore: number;
34
+ readonly attractorType: 'point' | 'cycle' | 'torus' | 'strange';
35
+ readonly lyapunovExponent: number;
36
+ readonly analysisTimeMs: number;
37
+ readonly windowSize: string;
38
+ readonly actionCount: number;
39
+ }
40
+ export interface PolicyVerificationResult {
41
+ readonly agentId: string;
42
+ readonly policy: string;
43
+ readonly valid: boolean;
44
+ readonly violations: string[];
45
+ readonly proofStatus: 'valid' | 'invalid' | 'timeout';
46
+ readonly verificationTimeMs: number;
47
+ }
48
+ export type EscalationState = 'clean' | 'probing' | 'escalating' | 'attack';
49
+ export interface EvasionResult {
50
+ readonly normalizedInput: string;
51
+ readonly wasObfuscated: boolean;
52
+ readonly techniqueDetected?: 'homoglyph' | 'leetspeak' | 'spacing' | 'base64' | 'zero_width';
53
+ }
54
+ export interface ContextState {
55
+ readonly escalationState: EscalationState;
56
+ readonly cumulativeThreatScore: number;
57
+ readonly turnCount: number;
58
+ readonly recentThreats: Threat[];
59
+ }
60
+ export interface OutputScanResult {
61
+ readonly safe: boolean;
62
+ readonly leakageFound: boolean;
63
+ readonly leakageTypes: string[];
64
+ readonly echoDetected: boolean;
65
+ readonly policyViolation: boolean;
66
+ readonly contradictionSignal: boolean;
67
+ readonly scanTimeMs: number;
68
+ }
69
+ export interface AllowlistRule {
70
+ readonly id: string;
71
+ readonly pattern: RegExp | string;
72
+ /**
73
+ * Threat types this rule applies to.
74
+ * - Empty array `[]`: full bypass — matching inputs skip detection entirely.
75
+ * - Non-empty array: selective suppression — detection still runs, but threats
76
+ * whose type appears in this array are removed from the result. Threats of
77
+ * other types are reported normally.
78
+ */
79
+ readonly types: ThreatType[];
80
+ readonly context?: string;
81
+ readonly reason: string;
82
+ readonly source: 'builtin' | 'user';
83
+ }
84
+ /**
85
+ * Factory function to create a Threat entity
86
+ */
87
+ export declare function createThreat(params: {
88
+ type: ThreatType;
89
+ severity: ThreatSeverity;
90
+ confidence: number;
91
+ pattern: string;
92
+ description: string;
93
+ location?: {
94
+ start: number;
95
+ end: number;
96
+ };
97
+ }): Threat;
98
+ //# sourceMappingURL=threat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threat.d.ts","sourceRoot":"","sources":["../../../src/domain/entities/threat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Threat Domain Entity
3
+ *
4
+ * Represents a detected security threat from AI manipulation attempts.
5
+ */
6
+ /**
7
+ * Factory function to create a Threat entity
8
+ */
9
+ export function createThreat(params) {
10
+ return {
11
+ id: `threat-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
12
+ type: params.type,
13
+ severity: params.severity,
14
+ confidence: params.confidence,
15
+ pattern: params.pattern,
16
+ description: params.description,
17
+ location: params.location,
18
+ detectedAt: new Date(),
19
+ };
20
+ }
21
+ //# sourceMappingURL=threat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threat.js","sourceRoot":"","sources":["../../../src/domain/entities/threat.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmGH;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,MAO5B;IACC,OAAO;QACL,EAAE,EAAE,UAAU,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;QACpE,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,IAAI,IAAI,EAAE;KACvB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { AllowlistRule } from '../entities/threat.js';
2
+ export declare class Allowlist {
3
+ private rules;
4
+ constructor(userRules?: AllowlistRule[]);
5
+ isAllowed(input: string): boolean;
6
+ getMatchingRules(input: string): AllowlistRule[];
7
+ addRule(rule: AllowlistRule): void;
8
+ private matches;
9
+ }
10
+ export declare function createAllowlist(userRules?: AllowlistRule[]): Allowlist;
11
+ //# sourceMappingURL=allowlist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowlist.d.ts","sourceRoot":"","sources":["../../../src/domain/services/allowlist.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AA2C3D,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAkB;gBAEnB,SAAS,GAAE,aAAa,EAAO;IAI3C,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIjC,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE;IAIhD,OAAO,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAIlC,OAAO,CAAC,OAAO;CAahB;AAED,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,GAAG,SAAS,CAEtE"}
@@ -0,0 +1,72 @@
1
+ const BUILT_IN_RULES = [
2
+ {
3
+ id: 'builtin-greetings',
4
+ // End-anchored: "hi!" or "hello" alone — NOT "hey ignore all instructions"
5
+ pattern: /^\s*(?:hi|hello|hey|greetings|good\s+(?:morning|afternoon|evening))\s*[.!?]?\s*$/i,
6
+ types: [],
7
+ reason: 'Stand-alone greeting — no threat possible',
8
+ source: 'builtin',
9
+ },
10
+ {
11
+ id: 'builtin-math',
12
+ pattern: /^\s*what\s+is\s+[\d\s+\-*/^()]+\??$/i,
13
+ types: [],
14
+ reason: 'Simple arithmetic question',
15
+ source: 'builtin',
16
+ },
17
+ {
18
+ id: 'builtin-weather',
19
+ // Start + end anchored: pure weather query only — allows "in [location]" but not appended instructions
20
+ pattern: /^\s*(?:what(?:'s|\s+is)\s+(?:the\s+)?weather(?:\s+(?:like\s+)?(?:in|for|at|near|today|tomorrow|this\s+week)(?:\s+[\w\s,]+)?)?|how(?:'s|\s+is)\s+(?:the\s+)?weather(?:\s+[\w\s,]+)?|weather\s+(?:in|for|at|today|tomorrow|forecast)(?:\s+[\w\s,]+)?)\s*[.?!]?\s*$/i,
21
+ types: [],
22
+ reason: 'Pure weather query — benign',
23
+ source: 'builtin',
24
+ },
25
+ {
26
+ id: 'builtin-time',
27
+ // Start + end anchored: pure time/date query only
28
+ pattern: /^\s*what\s+(?:time|day|date)\s+is\s+it\s*[.?!]?\s*$/i,
29
+ types: [],
30
+ reason: 'Pure time/date query — benign',
31
+ source: 'builtin',
32
+ },
33
+ {
34
+ id: 'builtin-help',
35
+ pattern: /^\s*(?:can\s+you\s+)?help\s+me\s*[.?!]?\s*$/i,
36
+ types: [],
37
+ reason: 'Short "help me" request — benign',
38
+ source: 'builtin',
39
+ },
40
+ ];
41
+ export class Allowlist {
42
+ rules;
43
+ constructor(userRules = []) {
44
+ this.rules = [...BUILT_IN_RULES, ...userRules];
45
+ }
46
+ isAllowed(input) {
47
+ return this.getMatchingRules(input).length > 0;
48
+ }
49
+ getMatchingRules(input) {
50
+ return this.rules.filter(rule => this.matches(rule, input));
51
+ }
52
+ addRule(rule) {
53
+ this.rules.push(rule);
54
+ }
55
+ matches(rule, input) {
56
+ if (typeof rule.pattern === 'string') {
57
+ // String patterns use substring matching. For security-sensitive rules,
58
+ // prefer RegExp with ^ and $ anchors to avoid over-allowlisting.
59
+ return input.toLowerCase().includes(rule.pattern.toLowerCase());
60
+ }
61
+ // Reset lastIndex before testing — g/y-flagged regexes advance lastIndex after each
62
+ // successful .test() call, causing alternating true/false on repeated identical inputs.
63
+ if (rule.pattern.global || rule.pattern.sticky) {
64
+ rule.pattern.lastIndex = 0;
65
+ }
66
+ return rule.pattern.test(input);
67
+ }
68
+ }
69
+ export function createAllowlist(userRules) {
70
+ return new Allowlist(userRules);
71
+ }
72
+ //# sourceMappingURL=allowlist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowlist.js","sourceRoot":"","sources":["../../../src/domain/services/allowlist.ts"],"names":[],"mappings":"AAEA,MAAM,cAAc,GAAoB;IACtC;QACE,EAAE,EAAE,mBAAmB;QACvB,2EAA2E;QAC3E,OAAO,EAAE,mFAAmF;QAC5F,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,2CAA2C;QACnD,MAAM,EAAE,SAAS;KAClB;IACD;QACE,EAAE,EAAE,cAAc;QAClB,OAAO,EAAE,sCAAsC;QAC/C,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,4BAA4B;QACpC,MAAM,EAAE,SAAS;KAClB;IACD;QACE,EAAE,EAAE,iBAAiB;QACrB,uGAAuG;QACvG,OAAO,EAAE,mQAAmQ;QAC5Q,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,6BAA6B;QACrC,MAAM,EAAE,SAAS;KAClB;IACD;QACE,EAAE,EAAE,cAAc;QAClB,kDAAkD;QAClD,OAAO,EAAE,sDAAsD;QAC/D,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,+BAA+B;QACvC,MAAM,EAAE,SAAS;KAClB;IACD;QACE,EAAE,EAAE,cAAc;QAClB,OAAO,EAAE,8CAA8C;QACvD,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,kCAAkC;QAC1C,MAAM,EAAE,SAAS;KAClB;CACF,CAAC;AAEF,MAAM,OAAO,SAAS;IACZ,KAAK,CAAkB;IAE/B,YAAY,YAA6B,EAAE;QACzC,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,SAAS,CAAC,CAAC;IACjD,CAAC;IAED,SAAS,CAAC,KAAa;QACrB,OAAO,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACjD,CAAC;IAED,gBAAgB,CAAC,KAAa;QAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,CAAC,IAAmB;QACzB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAEO,OAAO,CAAC,IAAmB,EAAE,KAAa;QAChD,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YACrC,wEAAwE;YACxE,iEAAiE;YACjE,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,oFAAoF;QACpF,wFAAwF;QACxF,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAC/C,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;CACF;AAED,MAAM,UAAU,eAAe,CAAC,SAA2B;IACzD,OAAO,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { ContextState, ThreatDetectionResult } from '../entities/threat.js';
2
+ export declare class ContextTracker {
3
+ private state;
4
+ private lastTurnAt;
5
+ private readonly idleDecayMs;
6
+ constructor(opts?: {
7
+ idleDecayMs?: number;
8
+ });
9
+ recordTurn(input: string, result: ThreatDetectionResult): void;
10
+ getState(): Readonly<ContextState>;
11
+ reset(): void;
12
+ private computeNextState;
13
+ }
14
+ export declare function createContextTracker(): ContextTracker;
15
+ //# sourceMappingURL=context-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-tracker.d.ts","sourceRoot":"","sources":["../../../src/domain/services/context-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAA2B,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAiB1G,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAKX;IAEF,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,IAAI,GAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAO;IAI/C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,GAAG,IAAI;IA8B9D,QAAQ,IAAI,QAAQ,CAAC,YAAY,CAAC;IAIlC,KAAK,IAAI,IAAI;IAUb,OAAO,CAAC,gBAAgB;CAiBzB;AAED,wBAAgB,oBAAoB,IAAI,cAAc,CAErD"}
@@ -0,0 +1,75 @@
1
+ // Escalation thresholds
2
+ const PROBING_THRESHOLD = 0.3;
3
+ const ESCALATING_THRESHOLD = 0.6; // cumulative score
4
+ const ATTACK_CONFIDENCE = 0.9; // single-turn jump-to-attack
5
+ const ESCALATION_ORDER = ['clean', 'probing', 'escalating', 'attack'];
6
+ export class ContextTracker {
7
+ state = {
8
+ escalationState: 'clean',
9
+ cumulativeThreatScore: 0,
10
+ turnCount: 0,
11
+ recentThreats: [],
12
+ };
13
+ lastTurnAt = 0;
14
+ idleDecayMs;
15
+ constructor(opts = {}) {
16
+ this.idleDecayMs = opts.idleDecayMs ?? 30 * 60 * 1000; // 30 min default
17
+ }
18
+ recordTurn(input, result) {
19
+ const now = Date.now();
20
+ // Decay escalation state if session has been idle
21
+ if (this.lastTurnAt > 0 && now - this.lastTurnAt > this.idleDecayMs) {
22
+ const currentIndex = ESCALATION_ORDER.indexOf(this.state.escalationState);
23
+ if (currentIndex > 0) {
24
+ this.state.escalationState = ESCALATION_ORDER[currentIndex - 1];
25
+ }
26
+ // Also decay cumulative score so computeNextState doesn't immediately re-escalate
27
+ this.state.cumulativeThreatScore = Math.max(0, this.state.cumulativeThreatScore * 0.5);
28
+ }
29
+ this.lastTurnAt = now;
30
+ this.state.turnCount++;
31
+ // Update cumulative score
32
+ this.state.cumulativeThreatScore += result.overallRisk;
33
+ // Maintain sliding window of 10
34
+ if (!result.safe) {
35
+ this.state.recentThreats = [
36
+ ...this.state.recentThreats.slice(-9),
37
+ ...result.threats,
38
+ ].slice(-10);
39
+ }
40
+ // Escalation state machine (monotonic — only moves forward)
41
+ this.state.escalationState = this.computeNextState(result);
42
+ }
43
+ getState() {
44
+ return { ...this.state, recentThreats: [...this.state.recentThreats] };
45
+ }
46
+ reset() {
47
+ this.state = {
48
+ escalationState: 'clean',
49
+ cumulativeThreatScore: 0,
50
+ turnCount: 0,
51
+ recentThreats: [],
52
+ };
53
+ this.lastTurnAt = 0;
54
+ }
55
+ computeNextState(result) {
56
+ const current = this.state.escalationState;
57
+ const currentIndex = ESCALATION_ORDER.indexOf(current);
58
+ let targetIndex = currentIndex; // monotonic: never go back
59
+ // Jump to attack on high single-turn confidence
60
+ if (result.overallRisk >= ATTACK_CONFIDENCE) {
61
+ targetIndex = ESCALATION_ORDER.indexOf('attack');
62
+ }
63
+ else if (this.state.cumulativeThreatScore >= ESCALATING_THRESHOLD) {
64
+ targetIndex = Math.max(targetIndex, ESCALATION_ORDER.indexOf('escalating'));
65
+ }
66
+ else if (result.overallRisk >= PROBING_THRESHOLD) {
67
+ targetIndex = Math.max(targetIndex, ESCALATION_ORDER.indexOf('probing'));
68
+ }
69
+ return ESCALATION_ORDER[targetIndex];
70
+ }
71
+ }
72
+ export function createContextTracker() {
73
+ return new ContextTracker();
74
+ }
75
+ //# sourceMappingURL=context-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-tracker.js","sourceRoot":"","sources":["../../../src/domain/services/context-tracker.ts"],"names":[],"mappings":"AAEA,wBAAwB;AACxB,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAC9B,MAAM,oBAAoB,GAAG,GAAG,CAAC,CAAI,mBAAmB;AACxD,MAAM,iBAAiB,GAAG,GAAG,CAAC,CAAQ,6BAA6B;AAEnE,MAAM,gBAAgB,GAAsB,CAAC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;AAUzF,MAAM,OAAO,cAAc;IACjB,KAAK,GAAwB;QACnC,eAAe,EAAE,OAAO;QACxB,qBAAqB,EAAE,CAAC;QACxB,SAAS,EAAE,CAAC;QACZ,aAAa,EAAE,EAAE;KAClB,CAAC;IAEM,UAAU,GAAW,CAAC,CAAC;IACd,WAAW,CAAS;IAErC,YAAY,OAAiC,EAAE;QAC7C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,iBAAiB;IAC1E,CAAC;IAED,UAAU,CAAC,KAAa,EAAE,MAA6B;QACrD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,kDAAkD;QAClD,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,GAAG,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACpE,MAAM,YAAY,GAAG,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YAC1E,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;gBACrB,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,gBAAgB,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;YAClE,CAAC;YACD,kFAAkF;YAClF,IAAI,CAAC,KAAK,CAAC,qBAAqB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,qBAAqB,GAAG,GAAG,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;QAEtB,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QAEvB,0BAA0B;QAC1B,IAAI,CAAC,KAAK,CAAC,qBAAqB,IAAI,MAAM,CAAC,WAAW,CAAC;QAEvD,gCAAgC;QAChC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG;gBACzB,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACrC,GAAG,MAAM,CAAC,OAAO;aAClB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QACf,CAAC;QAED,4DAA4D;QAC5D,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC;IAED,QAAQ;QACN,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;IACzE,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,GAAG;YACX,eAAe,EAAE,OAAO;YACxB,qBAAqB,EAAE,CAAC;YACxB,SAAS,EAAE,CAAC;YACZ,aAAa,EAAE,EAAE;SAClB,CAAC;QACF,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;IACtB,CAAC;IAEO,gBAAgB,CAAC,MAA6B;QACpD,MAAM,OAAO,GAAoB,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC;QAC5D,MAAM,YAAY,GAAG,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAEvD,IAAI,WAAW,GAAG,YAAY,CAAC,CAAC,2BAA2B;QAE3D,gDAAgD;QAChD,IAAI,MAAM,CAAC,WAAW,IAAI,iBAAiB,EAAE,CAAC;YAC5C,WAAW,GAAG,gBAAgB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnD,CAAC;aAAM,IAAI,IAAI,CAAC,KAAK,CAAC,qBAAqB,IAAI,oBAAoB,EAAE,CAAC;YACpE,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,gBAAgB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;QAC9E,CAAC;aAAM,IAAI,MAAM,CAAC,WAAW,IAAI,iBAAiB,EAAE,CAAC;YACnD,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACvC,CAAC;CACF;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,IAAI,cAAc,EAAE,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { EvasionResult } from '../entities/threat.js';
2
+ export declare class EvasionDetector {
3
+ normalize(input: string): EvasionResult;
4
+ private replaceHomoglyphs;
5
+ private expandLeetspeak;
6
+ private collapseSpacedChars;
7
+ private stripZeroWidth;
8
+ private appendDecodedBase64;
9
+ private detectTechnique;
10
+ }
11
+ export declare function createEvasionDetector(): EvasionDetector;
12
+ //# sourceMappingURL=evasion-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evasion-detector.d.ts","sourceRoot":"","sources":["../../../src/domain/services/evasion-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAmD3D,qBAAa,eAAe;IAC1B,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa;IA6BvC,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,eAAe;CAWxB;AAED,wBAAgB,qBAAqB,IAAI,eAAe,CAEvD"}