@panguard-ai/atr 0.2.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 (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +299 -0
  3. package/dist/cli.d.ts +12 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +720 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/coverage-analyzer.d.ts +43 -0
  8. package/dist/coverage-analyzer.d.ts.map +1 -0
  9. package/dist/coverage-analyzer.js +329 -0
  10. package/dist/coverage-analyzer.js.map +1 -0
  11. package/dist/engine.d.ts +127 -0
  12. package/dist/engine.d.ts.map +1 -0
  13. package/dist/engine.js +636 -0
  14. package/dist/engine.js.map +1 -0
  15. package/dist/index.d.ts +26 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +18 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/loader.d.ts +21 -0
  20. package/dist/loader.d.ts.map +1 -0
  21. package/dist/loader.js +124 -0
  22. package/dist/loader.js.map +1 -0
  23. package/dist/mcp-server.d.ts +13 -0
  24. package/dist/mcp-server.d.ts.map +1 -0
  25. package/dist/mcp-server.js +220 -0
  26. package/dist/mcp-server.js.map +1 -0
  27. package/dist/mcp-tools/coverage-gaps.d.ts +13 -0
  28. package/dist/mcp-tools/coverage-gaps.d.ts.map +1 -0
  29. package/dist/mcp-tools/coverage-gaps.js +55 -0
  30. package/dist/mcp-tools/coverage-gaps.js.map +1 -0
  31. package/dist/mcp-tools/list-rules.d.ts +17 -0
  32. package/dist/mcp-tools/list-rules.d.ts.map +1 -0
  33. package/dist/mcp-tools/list-rules.js +45 -0
  34. package/dist/mcp-tools/list-rules.js.map +1 -0
  35. package/dist/mcp-tools/scan.d.ts +18 -0
  36. package/dist/mcp-tools/scan.d.ts.map +1 -0
  37. package/dist/mcp-tools/scan.js +75 -0
  38. package/dist/mcp-tools/scan.js.map +1 -0
  39. package/dist/mcp-tools/submit-proposal.d.ts +12 -0
  40. package/dist/mcp-tools/submit-proposal.d.ts.map +1 -0
  41. package/dist/mcp-tools/submit-proposal.js +95 -0
  42. package/dist/mcp-tools/submit-proposal.js.map +1 -0
  43. package/dist/mcp-tools/threat-summary.d.ts +12 -0
  44. package/dist/mcp-tools/threat-summary.d.ts.map +1 -0
  45. package/dist/mcp-tools/threat-summary.js +74 -0
  46. package/dist/mcp-tools/threat-summary.js.map +1 -0
  47. package/dist/mcp-tools/validate.d.ts +15 -0
  48. package/dist/mcp-tools/validate.d.ts.map +1 -0
  49. package/dist/mcp-tools/validate.js +45 -0
  50. package/dist/mcp-tools/validate.js.map +1 -0
  51. package/dist/modules/index.d.ts +144 -0
  52. package/dist/modules/index.d.ts.map +1 -0
  53. package/dist/modules/index.js +82 -0
  54. package/dist/modules/index.js.map +1 -0
  55. package/dist/modules/semantic.d.ts +105 -0
  56. package/dist/modules/semantic.d.ts.map +1 -0
  57. package/dist/modules/semantic.js +283 -0
  58. package/dist/modules/semantic.js.map +1 -0
  59. package/dist/modules/session.d.ts +70 -0
  60. package/dist/modules/session.d.ts.map +1 -0
  61. package/dist/modules/session.js +128 -0
  62. package/dist/modules/session.js.map +1 -0
  63. package/dist/rule-scaffolder.d.ts +39 -0
  64. package/dist/rule-scaffolder.d.ts.map +1 -0
  65. package/dist/rule-scaffolder.js +173 -0
  66. package/dist/rule-scaffolder.js.map +1 -0
  67. package/dist/session-tracker.d.ts +56 -0
  68. package/dist/session-tracker.d.ts.map +1 -0
  69. package/dist/session-tracker.js +175 -0
  70. package/dist/session-tracker.js.map +1 -0
  71. package/dist/skill-fingerprint.d.ts +96 -0
  72. package/dist/skill-fingerprint.d.ts.map +1 -0
  73. package/dist/skill-fingerprint.js +337 -0
  74. package/dist/skill-fingerprint.js.map +1 -0
  75. package/dist/types.d.ts +129 -0
  76. package/dist/types.d.ts.map +1 -0
  77. package/dist/types.js +6 -0
  78. package/dist/types.js.map +1 -0
  79. package/package.json +75 -0
  80. package/rules/agent-manipulation/ATR-2026-030-cross-agent-attack.yaml +175 -0
  81. package/rules/agent-manipulation/ATR-2026-032-goal-hijacking.yaml +135 -0
  82. package/rules/agent-manipulation/ATR-2026-074-cross-agent-privilege-escalation.yaml +115 -0
  83. package/rules/agent-manipulation/ATR-2026-076-inter-agent-message-spoofing.yaml +165 -0
  84. package/rules/agent-manipulation/ATR-2026-077-human-trust-exploitation.yaml +144 -0
  85. package/rules/context-exfiltration/ATR-2026-020-system-prompt-leak.yaml +175 -0
  86. package/rules/context-exfiltration/ATR-2026-021-api-key-exposure.yaml +176 -0
  87. package/rules/context-exfiltration/ATR-2026-075-agent-memory-manipulation.yaml +115 -0
  88. package/rules/data-poisoning/ATR-2026-070-data-poisoning.yaml +160 -0
  89. package/rules/excessive-autonomy/ATR-2026-050-runaway-agent-loop.yaml +134 -0
  90. package/rules/excessive-autonomy/ATR-2026-051-resource-exhaustion.yaml +137 -0
  91. package/rules/excessive-autonomy/ATR-2026-052-cascading-failure.yaml +153 -0
  92. package/rules/model-security/ATR-2026-072-model-behavior-extraction.yaml +115 -0
  93. package/rules/model-security/ATR-2026-073-malicious-finetuning-data.yaml +108 -0
  94. package/rules/privilege-escalation/ATR-2026-040-privilege-escalation.yaml +175 -0
  95. package/rules/privilege-escalation/ATR-2026-041-scope-creep.yaml +124 -0
  96. package/rules/prompt-injection/ATR-2026-001-direct-prompt-injection.yaml +265 -0
  97. package/rules/prompt-injection/ATR-2026-002-indirect-prompt-injection.yaml +214 -0
  98. package/rules/prompt-injection/ATR-2026-003-jailbreak-attempt.yaml +250 -0
  99. package/rules/prompt-injection/ATR-2026-004-system-prompt-override.yaml +204 -0
  100. package/rules/prompt-injection/ATR-2026-005-multi-turn-injection.yaml +181 -0
  101. package/rules/prompt-injection/ATR-PRED-2026-001.yaml +61 -0
  102. package/rules/prompt-injection/ATR-PRED-2026-002.yaml +58 -0
  103. package/rules/prompt-injection/ATR-PRED-2026-003.yaml +61 -0
  104. package/rules/prompt-injection/ATR-PRED-2026-005.yaml +55 -0
  105. package/rules/prompt-injection/ATR-PRED-2026-006.yaml +51 -0
  106. package/rules/prompt-injection/ATR-PRED-2026-007.yaml +57 -0
  107. package/rules/prompt-injection/ATR-PRED-2026-008.yaml +57 -0
  108. package/rules/prompt-injection/ATR-PRED-2026-009.yaml +51 -0
  109. package/rules/prompt-injection/ATR-PRED-2026-010.yaml +57 -0
  110. package/rules/prompt-injection/ATR-PRED-2026-011.yaml +53 -0
  111. package/rules/prompt-injection/ATR-PRED-2026-012.yaml +57 -0
  112. package/rules/prompt-injection/ATR-PRED-2026-023.yaml +56 -0
  113. package/rules/prompt-injection/ATR-PRED-2026-025.yaml +68 -0
  114. package/rules/prompt-injection/ATR-PRED-2026-026.yaml +66 -0
  115. package/rules/prompt-injection/ATR-PRED-2026-027.yaml +62 -0
  116. package/rules/skill-compromise/ATR-2026-060-skill-impersonation.yaml +153 -0
  117. package/rules/skill-compromise/ATR-2026-061-description-behavior-mismatch.yaml +98 -0
  118. package/rules/skill-compromise/ATR-2026-062-hidden-capability.yaml +96 -0
  119. package/rules/skill-compromise/ATR-2026-063-skill-chain-attack.yaml +96 -0
  120. package/rules/skill-compromise/ATR-2026-064-over-permissioned-skill.yaml +115 -0
  121. package/rules/skill-compromise/ATR-2026-065-skill-update-attack.yaml +93 -0
  122. package/rules/skill-compromise/ATR-2026-066-parameter-injection.yaml +106 -0
  123. package/rules/tool-poisoning/ATR-2026-010-mcp-malicious-response.yaml +237 -0
  124. package/rules/tool-poisoning/ATR-2026-011-tool-output-injection.yaml +185 -0
  125. package/rules/tool-poisoning/ATR-2026-012-unauthorized-tool-call.yaml +190 -0
  126. package/rules/tool-poisoning/ATR-2026-013-tool-ssrf.yaml +208 -0
  127. package/rules/tool-poisoning/ATR-PRED-2026-004.yaml +54 -0
  128. package/rules/tool-poisoning/ATR-PRED-2026-024.yaml +68 -0
  129. package/spec/atr-schema.yaml +375 -0
@@ -0,0 +1,173 @@
1
+ /**
2
+ * ATR Rule Scaffolder - Generates ATR rule YAML scaffolds from structured input
3
+ * @module agent-threat-rules/rule-scaffolder
4
+ */
5
+ import yaml from 'js-yaml';
6
+ const CATEGORY_TO_SOURCE_TYPE = {
7
+ 'prompt-injection': 'llm_io',
8
+ 'tool-poisoning': 'tool_call',
9
+ 'context-exfiltration': 'context_window',
10
+ 'agent-manipulation': 'multi_agent_comm',
11
+ 'privilege-escalation': 'agent_behavior',
12
+ 'excessive-autonomy': 'agent_behavior',
13
+ 'data-poisoning': 'llm_io',
14
+ 'model-abuse': 'llm_io',
15
+ 'skill-compromise': 'skill_lifecycle',
16
+ };
17
+ const CATEGORY_TO_FIELD = {
18
+ 'prompt-injection': 'user_input',
19
+ 'tool-poisoning': 'tool_response',
20
+ 'context-exfiltration': 'agent_output',
21
+ 'agent-manipulation': 'agent_message',
22
+ 'privilege-escalation': 'agent_action',
23
+ 'excessive-autonomy': 'agent_action',
24
+ 'data-poisoning': 'training_input',
25
+ 'model-abuse': 'user_input',
26
+ 'skill-compromise': 'skill_manifest',
27
+ };
28
+ const SEVERITY_TO_ACTIONS = {
29
+ critical: ['block_input', 'alert', 'escalate'],
30
+ high: ['block_input', 'alert'],
31
+ medium: ['alert', 'snapshot'],
32
+ low: ['alert'],
33
+ informational: ['alert'],
34
+ };
35
+ const REGEX_SPECIAL_CHARS = /[.*+?^${}()|[\]\\]/g;
36
+ function escapeRegex(str) {
37
+ return str.replace(REGEX_SPECIAL_CHARS, '\\$&');
38
+ }
39
+ /**
40
+ * Build a case-insensitive regex pattern from a payload string.
41
+ * Extracts significant keywords (length > 3) and creates lookahead assertions,
42
+ * falling back to a simple escaped match for short payloads.
43
+ */
44
+ function buildRegexPattern(payload) {
45
+ const trimmed = payload.trim();
46
+ const words = trimmed.split(/\s+/).filter((w) => w.length > 3);
47
+ if (words.length === 0) {
48
+ return `(?i).*${escapeRegex(trimmed)}.*`;
49
+ }
50
+ const keywords = words.slice(0, 4);
51
+ return `(?i)${keywords.map((k) => `(?=.*${escapeRegex(k)})`).join('')}`;
52
+ }
53
+ function generateId() {
54
+ const year = new Date().getFullYear();
55
+ const seq = String(Math.floor(Math.random() * 900) + 100);
56
+ return `ATR-${year}-${seq}`;
57
+ }
58
+ function getCurrentDate() {
59
+ return new Date().toISOString().split('T')[0];
60
+ }
61
+ export class RuleScaffolder {
62
+ options;
63
+ constructor(options = {}) {
64
+ this.options = {
65
+ author: options.author ?? 'ATR Community (auto-scaffolded)',
66
+ schemaVersion: options.schemaVersion ?? '0.1',
67
+ };
68
+ }
69
+ /**
70
+ * Generate a complete ATR YAML rule from structured input.
71
+ * Returns a ScaffoldResult with the YAML string, generated ID, and any warnings.
72
+ */
73
+ scaffold(input) {
74
+ const warnings = this.validateInput(input);
75
+ const severity = input.severity ?? 'medium';
76
+ const sourceType = input.agentSourceType ?? CATEGORY_TO_SOURCE_TYPE[input.category];
77
+ const field = CATEGORY_TO_FIELD[input.category];
78
+ const id = generateId();
79
+ const date = getCurrentDate();
80
+ const conditions = input.examplePayloads.map((payload, idx) => ({
81
+ field,
82
+ operator: 'regex',
83
+ value: buildRegexPattern(payload),
84
+ description: `Pattern ${idx + 1}: detects "${payload.trim()}"`,
85
+ }));
86
+ const truePositives = input.examplePayloads.map((payload) => ({
87
+ input: payload.trim(),
88
+ expected: 'trigger',
89
+ }));
90
+ const trueNegatives = [
91
+ {
92
+ input: 'TODO: Add benign input that should not trigger this rule',
93
+ expected: 'no_trigger',
94
+ },
95
+ ];
96
+ const references = {};
97
+ if (input.owaspRefs && input.owaspRefs.length > 0) {
98
+ references.owasp_llm = [...input.owaspRefs];
99
+ }
100
+ if (input.mitreRefs && input.mitreRefs.length > 0) {
101
+ references.mitre_atlas = [...input.mitreRefs];
102
+ }
103
+ const conditionExpr = conditions.length > 1 ? 'any' : 'all';
104
+ const rule = {
105
+ title: input.title,
106
+ id,
107
+ schema_version: this.options.schemaVersion,
108
+ status: 'draft',
109
+ description: input.attackDescription,
110
+ author: this.options.author,
111
+ date,
112
+ severity,
113
+ detection_tier: 'pattern',
114
+ maturity: 'draft',
115
+ ...(Object.keys(references).length > 0 ? { references } : {}),
116
+ tags: {
117
+ category: input.category,
118
+ confidence: severity === 'critical' || severity === 'high' ? 'high' : 'medium',
119
+ },
120
+ agent_source: {
121
+ type: sourceType,
122
+ },
123
+ detection: {
124
+ conditions,
125
+ condition: conditionExpr,
126
+ false_positives: [
127
+ 'TODO: Document known false positive scenarios',
128
+ ],
129
+ },
130
+ response: {
131
+ actions: [...SEVERITY_TO_ACTIONS[severity]],
132
+ message_template: `Potential ${input.category} detected: {{matched_patterns}}`,
133
+ },
134
+ test_cases: {
135
+ true_positives: truePositives,
136
+ true_negatives: trueNegatives,
137
+ },
138
+ };
139
+ const yamlStr = yaml.dump(rule, {
140
+ indent: 2,
141
+ lineWidth: 120,
142
+ noRefs: true,
143
+ sortKeys: false,
144
+ quotingType: '"',
145
+ forceQuotes: false,
146
+ });
147
+ return { yaml: yamlStr, id, warnings };
148
+ }
149
+ /**
150
+ * Validate scaffold input, throwing on invalid required fields
151
+ * and returning warnings for non-critical issues.
152
+ */
153
+ validateInput(input) {
154
+ const warnings = [];
155
+ if (!input.title || input.title.trim().length === 0) {
156
+ throw new Error('ScaffoldInput.title is required and must be non-empty');
157
+ }
158
+ if (!input.category) {
159
+ throw new Error('ScaffoldInput.category is required');
160
+ }
161
+ if (!input.attackDescription || input.attackDescription.trim().length === 0) {
162
+ throw new Error('ScaffoldInput.attackDescription is required and must be non-empty');
163
+ }
164
+ if (!input.examplePayloads || input.examplePayloads.length === 0) {
165
+ throw new Error('ScaffoldInput.examplePayloads must contain at least one payload');
166
+ }
167
+ if (input.examplePayloads.length < 3) {
168
+ warnings.push('Fewer than 3 example payloads - consider adding more for better pattern coverage.');
169
+ }
170
+ return warnings;
171
+ }
172
+ }
173
+ //# sourceMappingURL=rule-scaffolder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-scaffolder.js","sourceRoot":"","sources":["../src/rule-scaffolder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * SessionTracker - Tracks per-session state for behavioral detection operators.
3
+ *
4
+ * Enables multi-turn injection detection, call frequency tracking,
5
+ * and pattern repetition counting. All state is internal; public methods
6
+ * return copies to preserve immutability.
7
+ *
8
+ * @module agent-threat-rules/session-tracker
9
+ */
10
+ import type { AgentEvent } from './types.js';
11
+ /** Snapshot of session state returned to callers (immutable copy) */
12
+ export interface SessionStateSnapshot {
13
+ readonly sessionId: string;
14
+ readonly eventCount: number;
15
+ readonly oldestEventTimestamp: number | undefined;
16
+ readonly newestEventTimestamp: number | undefined;
17
+ }
18
+ export declare class SessionTracker {
19
+ private readonly sessions;
20
+ /**
21
+ * Record an agent event for the given session.
22
+ * Extracts tool name and patterns from event fields/content.
23
+ */
24
+ recordEvent(sessionId: string, event: AgentEvent, patterns?: readonly string[]): void;
25
+ /**
26
+ * Get the number of calls to a specific tool within a time window.
27
+ */
28
+ getCallFrequency(sessionId: string, toolName: string, windowMs: number): number;
29
+ /**
30
+ * Get the number of times a pattern has been observed within a time window.
31
+ */
32
+ getPatternFrequency(sessionId: string, pattern: string, windowMs: number): number;
33
+ /**
34
+ * Get total event count for a session, optionally within a time window.
35
+ */
36
+ getEventCount(sessionId: string, windowMs?: number): number;
37
+ /**
38
+ * Get an immutable snapshot of session state. Returns undefined if session does not exist.
39
+ */
40
+ getSessionSnapshot(sessionId: string): SessionStateSnapshot | undefined;
41
+ /**
42
+ * Evict sessions that have been inactive longer than maxAgeMs.
43
+ * Returns the number of sessions evicted.
44
+ */
45
+ cleanup(maxAgeMs: number): number;
46
+ /** Get the number of tracked sessions */
47
+ getSessionCount(): number;
48
+ /**
49
+ * Ensure we don't exceed the maximum session count.
50
+ * Evicts the oldest session if at capacity.
51
+ */
52
+ private ensureCapacity;
53
+ private getOrCreateSession;
54
+ private extractToolName;
55
+ }
56
+ //# sourceMappingURL=session-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-tracker.d.ts","sourceRoot":"","sources":["../src/session-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAgB7C,qEAAqE;AACrE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;CACnD;AAWD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAE5D;;;OAGG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,GAAE,SAAS,MAAM,EAAO,GAAG,IAAI;IAkCzF;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAc/E;;OAEG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAcjF;;OAEG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM;IAkB3D;;OAEG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS;IAevE;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAcjC,yCAAyC;IACzC,eAAe,IAAI,MAAM;IAIzB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,eAAe;CAMxB"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * SessionTracker - Tracks per-session state for behavioral detection operators.
3
+ *
4
+ * Enables multi-turn injection detection, call frequency tracking,
5
+ * and pattern repetition counting. All state is internal; public methods
6
+ * return copies to preserve immutability.
7
+ *
8
+ * @module agent-threat-rules/session-tracker
9
+ */
10
+ /** Maximum number of events stored per session */
11
+ const MAX_EVENTS_PER_SESSION = 1000;
12
+ /** Maximum number of tracked sessions */
13
+ const MAX_SESSIONS = 10_000;
14
+ export class SessionTracker {
15
+ sessions = new Map();
16
+ /**
17
+ * Record an agent event for the given session.
18
+ * Extracts tool name and patterns from event fields/content.
19
+ */
20
+ recordEvent(sessionId, event, patterns = []) {
21
+ this.ensureCapacity();
22
+ const state = this.getOrCreateSession(sessionId);
23
+ const toolName = this.extractToolName(event);
24
+ const now = Date.now();
25
+ const tracked = {
26
+ event: Object.freeze({ ...event }),
27
+ recordedAt: now,
28
+ toolName,
29
+ patterns,
30
+ };
31
+ // Evict oldest if at capacity
32
+ if (state.events.length >= MAX_EVENTS_PER_SESSION) {
33
+ state.events = state.events.slice(1);
34
+ }
35
+ state.events = [...state.events, tracked];
36
+ state.lastActivityAt = now;
37
+ // Update call counts
38
+ if (toolName) {
39
+ const prev = state.callCounts.get(toolName) ?? 0;
40
+ state.callCounts.set(toolName, prev + 1);
41
+ }
42
+ // Update pattern counts
43
+ for (const p of patterns) {
44
+ const prev = state.patternCounts.get(p) ?? 0;
45
+ state.patternCounts.set(p, prev + 1);
46
+ }
47
+ }
48
+ /**
49
+ * Get the number of calls to a specific tool within a time window.
50
+ */
51
+ getCallFrequency(sessionId, toolName, windowMs) {
52
+ const state = this.sessions.get(sessionId);
53
+ if (!state)
54
+ return 0;
55
+ const cutoff = Date.now() - windowMs;
56
+ let count = 0;
57
+ for (const tracked of state.events) {
58
+ if (tracked.recordedAt >= cutoff && tracked.toolName === toolName) {
59
+ count++;
60
+ }
61
+ }
62
+ return count;
63
+ }
64
+ /**
65
+ * Get the number of times a pattern has been observed within a time window.
66
+ */
67
+ getPatternFrequency(sessionId, pattern, windowMs) {
68
+ const state = this.sessions.get(sessionId);
69
+ if (!state)
70
+ return 0;
71
+ const cutoff = Date.now() - windowMs;
72
+ let count = 0;
73
+ for (const tracked of state.events) {
74
+ if (tracked.recordedAt >= cutoff && tracked.patterns.includes(pattern)) {
75
+ count++;
76
+ }
77
+ }
78
+ return count;
79
+ }
80
+ /**
81
+ * Get total event count for a session, optionally within a time window.
82
+ */
83
+ getEventCount(sessionId, windowMs) {
84
+ const state = this.sessions.get(sessionId);
85
+ if (!state)
86
+ return 0;
87
+ if (windowMs === undefined) {
88
+ return state.events.length;
89
+ }
90
+ const cutoff = Date.now() - windowMs;
91
+ let count = 0;
92
+ for (const tracked of state.events) {
93
+ if (tracked.recordedAt >= cutoff) {
94
+ count++;
95
+ }
96
+ }
97
+ return count;
98
+ }
99
+ /**
100
+ * Get an immutable snapshot of session state. Returns undefined if session does not exist.
101
+ */
102
+ getSessionSnapshot(sessionId) {
103
+ const state = this.sessions.get(sessionId);
104
+ if (!state)
105
+ return undefined;
106
+ const oldest = state.events.length > 0 ? state.events[0].recordedAt : undefined;
107
+ const newest = state.events.length > 0 ? state.events[state.events.length - 1].recordedAt : undefined;
108
+ return Object.freeze({
109
+ sessionId,
110
+ eventCount: state.events.length,
111
+ oldestEventTimestamp: oldest,
112
+ newestEventTimestamp: newest,
113
+ });
114
+ }
115
+ /**
116
+ * Evict sessions that have been inactive longer than maxAgeMs.
117
+ * Returns the number of sessions evicted.
118
+ */
119
+ cleanup(maxAgeMs) {
120
+ const cutoff = Date.now() - maxAgeMs;
121
+ let evicted = 0;
122
+ for (const [id, state] of this.sessions) {
123
+ if (state.lastActivityAt < cutoff) {
124
+ this.sessions.delete(id);
125
+ evicted++;
126
+ }
127
+ }
128
+ return evicted;
129
+ }
130
+ /** Get the number of tracked sessions */
131
+ getSessionCount() {
132
+ return this.sessions.size;
133
+ }
134
+ /**
135
+ * Ensure we don't exceed the maximum session count.
136
+ * Evicts the oldest session if at capacity.
137
+ */
138
+ ensureCapacity() {
139
+ if (this.sessions.size < MAX_SESSIONS)
140
+ return;
141
+ let oldestId;
142
+ let oldestTime = Infinity;
143
+ for (const [id, state] of this.sessions) {
144
+ if (state.lastActivityAt < oldestTime) {
145
+ oldestTime = state.lastActivityAt;
146
+ oldestId = id;
147
+ }
148
+ }
149
+ if (oldestId) {
150
+ this.sessions.delete(oldestId);
151
+ }
152
+ }
153
+ getOrCreateSession(sessionId) {
154
+ const existing = this.sessions.get(sessionId);
155
+ if (existing)
156
+ return existing;
157
+ const now = Date.now();
158
+ const state = {
159
+ events: [],
160
+ callCounts: new Map(),
161
+ patternCounts: new Map(),
162
+ createdAt: now,
163
+ lastActivityAt: now,
164
+ };
165
+ this.sessions.set(sessionId, state);
166
+ return state;
167
+ }
168
+ extractToolName(event) {
169
+ if (event.type === 'tool_call' || event.type === 'tool_response') {
170
+ return event.fields?.['tool_name'] ?? event.content;
171
+ }
172
+ return undefined;
173
+ }
174
+ }
175
+ //# sourceMappingURL=session-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-tracker.js","sourceRoot":"","sources":["../src/session-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Skill Behavioral Fingerprint
3
+ * Skill 行為指紋追蹤器
4
+ *
5
+ * Tracks what each skill "normally does" across invocations, then detects
6
+ * behavioral drift when a previously-trusted skill starts acting differently.
7
+ *
8
+ * Solves the "installed then turns malicious" scenario:
9
+ * - First N invocations: build fingerprint (what APIs, what patterns, what scope)
10
+ * - After fingerprint stabilizes: flag any deviation as anomaly
11
+ *
12
+ * 追蹤每個 skill 的「正常行為」,然後在行為偏移時偵測:
13
+ * - 前 N 次呼叫:建立指紋
14
+ * - 指紋穩定後:任何偏離都標記為異常
15
+ *
16
+ * @module agent-threat-rules/skill-fingerprint
17
+ */
18
+ import type { AgentEvent } from './types.js';
19
+ /** Behavioral capabilities observed for a skill */
20
+ interface SkillCapabilities {
21
+ /** Seen filesystem operations (read/write/delete) */
22
+ readonly filesystemOps: ReadonlySet<string>;
23
+ /** Seen network destinations (hostnames) */
24
+ readonly networkTargets: ReadonlySet<string>;
25
+ /** Seen environment variable accesses */
26
+ readonly envAccesses: ReadonlySet<string>;
27
+ /** Seen child process executions */
28
+ readonly processExecs: ReadonlySet<string>;
29
+ /** Seen output patterns (categories: data, error, redirect, exfiltration) */
30
+ readonly outputPatterns: ReadonlySet<string>;
31
+ }
32
+ /** Immutable fingerprint snapshot */
33
+ export interface SkillFingerprint {
34
+ readonly skillName: string;
35
+ readonly invocationCount: number;
36
+ readonly firstSeen: number;
37
+ readonly lastSeen: number;
38
+ readonly isStable: boolean;
39
+ readonly capabilities: SkillCapabilities;
40
+ /** Hash of capabilities for quick comparison */
41
+ readonly capabilityHash: string;
42
+ }
43
+ /** Anomaly when behavior deviates from fingerprint */
44
+ export interface BehaviorAnomaly {
45
+ readonly skillName: string;
46
+ readonly anomalyType: 'new_filesystem_op' | 'new_network_target' | 'new_env_access' | 'new_process_exec' | 'new_output_pattern' | 'capability_expansion';
47
+ readonly description: string;
48
+ readonly severity: 'low' | 'medium' | 'high' | 'critical';
49
+ readonly newValue: string;
50
+ readonly timestamp: number;
51
+ }
52
+ export interface SkillFingerprintConfig {
53
+ /** Minimum invocations before fingerprint can stabilize (default: 10) */
54
+ stabilityThreshold?: number;
55
+ /** Consecutive clean invocations to mark stable (default: 5) */
56
+ stableStreak?: number;
57
+ }
58
+ export declare class SkillFingerprintStore {
59
+ private readonly fingerprints;
60
+ private readonly stabilityThreshold;
61
+ private readonly stableStreak;
62
+ constructor(config?: SkillFingerprintConfig);
63
+ /**
64
+ * Record a skill invocation and detect behavioral anomalies.
65
+ * Returns anomalies if the fingerprint was stable and new capabilities appeared.
66
+ *
67
+ * 記錄 skill 呼叫並偵測行為異常。
68
+ * 如果指紋已穩定且出現新能力,回傳異常列表。
69
+ */
70
+ recordInvocation(skillName: string, event: AgentEvent): readonly BehaviorAnomaly[];
71
+ /**
72
+ * Get an immutable fingerprint snapshot for a skill.
73
+ * 取得某 skill 的不可變指紋快照。
74
+ */
75
+ getFingerprint(skillName: string): SkillFingerprint | undefined;
76
+ /** Get all tracked skill names */
77
+ getTrackedSkills(): string[];
78
+ /** Get count of stable fingerprints */
79
+ getStableCount(): number;
80
+ /** Get total tracked skills */
81
+ getTrackedCount(): number;
82
+ /**
83
+ * Reset a skill's fingerprint (e.g., after a legitimate update).
84
+ * 重置 skill 指紋(例如合法更新後)。
85
+ */
86
+ resetFingerprint(skillName: string): void;
87
+ /**
88
+ * Evict fingerprints not seen since cutoffMs ago.
89
+ * 清除超過 cutoffMs 未活動的指紋。
90
+ */
91
+ cleanup(cutoffMs: number): number;
92
+ private getOrCreate;
93
+ private computeCapabilityHash;
94
+ }
95
+ export {};
96
+ //# sourceMappingURL=skill-fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-fingerprint.d.ts","sourceRoot":"","sources":["../src/skill-fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAM7C,mDAAmD;AACnD,UAAU,iBAAiB;IACzB,qDAAqD;IACrD,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5C,4CAA4C;IAC5C,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7C,yCAAyC;IACzC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1C,oCAAoC;IACpC,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3C,6EAA6E;IAC7E,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC9C;AAED,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;IACzC,gDAAgD;IAChD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,sDAAsD;AACtD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAChB,mBAAmB,GACnB,oBAAoB,GACpB,gBAAgB,GAChB,kBAAkB,GAClB,oBAAoB,GACpB,sBAAsB,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IAC1D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAqGD,MAAM,WAAW,sBAAsB;IACrC,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyC;IACtE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,MAAM,CAAC,EAAE,sBAAsB;IAK3C;;;;;;OAMG;IACH,gBAAgB,CACd,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,GAChB,SAAS,eAAe,EAAE;IA8H7B;;;OAGG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAqB/D,kCAAkC;IAClC,gBAAgB,IAAI,MAAM,EAAE;IAI5B,uCAAuC;IACvC,cAAc,IAAI,MAAM;IAQxB,+BAA+B;IAC/B,eAAe,IAAI,MAAM;IAIzB;;;OAGG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIzC;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAgBjC,OAAO,CAAC,WAAW;IAkCnB,OAAO,CAAC,qBAAqB;CAU9B"}