agentshield-sdk 7.2.1 → 7.4.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 (57) hide show
  1. package/CHANGELOG.md +125 -1
  2. package/README.md +68 -7
  3. package/bin/agent-shield.js +19 -0
  4. package/package.json +10 -3
  5. package/src/agent-protocol.js +4 -0
  6. package/src/allowlist.js +605 -603
  7. package/src/attack-genome.js +536 -0
  8. package/src/attack-replay.js +246 -0
  9. package/src/audit-streaming.js +486 -469
  10. package/src/audit.js +619 -0
  11. package/src/behavior-profiling.js +299 -289
  12. package/src/behavioral-dna.js +757 -0
  13. package/src/canary.js +273 -271
  14. package/src/compliance-authority.js +803 -0
  15. package/src/compliance.js +619 -617
  16. package/src/confidence-tuning.js +328 -324
  17. package/src/context-scoring.js +362 -360
  18. package/src/cost-optimizer.js +1024 -1024
  19. package/src/detector-core.js +186 -0
  20. package/src/distributed.js +7 -2
  21. package/src/embedding.js +310 -307
  22. package/src/errors.js +9 -0
  23. package/src/evolution-simulator.js +650 -0
  24. package/src/flight-recorder.js +379 -0
  25. package/src/herd-immunity.js +521 -0
  26. package/src/honeypot.js +332 -328
  27. package/src/index.js +6 -5
  28. package/src/integrations.js +1 -2
  29. package/src/intent-firewall.js +775 -0
  30. package/src/llm-redteam.js +678 -670
  31. package/src/main.js +139 -0
  32. package/src/mcp-security-runtime.js +6 -5
  33. package/src/middleware.js +11 -5
  34. package/src/model-fingerprint.js +1059 -1042
  35. package/src/multi-agent-trust.js +459 -453
  36. package/src/multi-agent.js +1 -1
  37. package/src/normalizer.js +734 -0
  38. package/src/pii.js +8 -1
  39. package/src/policy-dsl.js +775 -775
  40. package/src/presets.js +409 -409
  41. package/src/production.js +22 -9
  42. package/src/real-attack-datasets.js +246 -0
  43. package/src/redteam.js +475 -475
  44. package/src/report-generator.js +640 -0
  45. package/src/response-handler.js +436 -429
  46. package/src/scanners.js +358 -357
  47. package/src/self-healing.js +368 -363
  48. package/src/semantic.js +339 -339
  49. package/src/shield-score.js +250 -250
  50. package/src/soc-dashboard.js +394 -0
  51. package/src/sso-saml.js +8 -4
  52. package/src/supply-chain.js +667 -0
  53. package/src/testing.js +24 -2
  54. package/src/threat-intel-federation.js +343 -0
  55. package/src/tool-guard.js +412 -412
  56. package/src/watermark.js +242 -235
  57. package/src/worker-scanner.js +608 -601
@@ -0,0 +1,246 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Agent Shield - Attack Replay Platform
5
+ *
6
+ * Record real attacks, replay them against updated defenses,
7
+ * generate mutations, and track defense improvements over time.
8
+ * Like BurpSuite's Repeater but for AI agent security.
9
+ *
10
+ * @module attack-replay
11
+ */
12
+
13
+ const crypto = require('crypto');
14
+ const { scanText } = require('./detector-core');
15
+
16
+ /**
17
+ * Records and replays attacks against defenses.
18
+ */
19
+ class AttackReplayEngine {
20
+ /**
21
+ * @param {object} [options]
22
+ * @param {number} [options.maxRecordings=10000] - Max stored recordings.
23
+ * @param {string} [options.sensitivity='high'] - Detection sensitivity.
24
+ */
25
+ constructor(options = {}) {
26
+ this.maxRecordings = options.maxRecordings || 10000;
27
+ this.sensitivity = options.sensitivity || 'high';
28
+ this._recordings = [];
29
+ this._replayHistory = [];
30
+ }
31
+
32
+ /**
33
+ * Record an attack for later replay.
34
+ * @param {object} attack
35
+ * @param {string} attack.text - The attack text.
36
+ * @param {string} [attack.category] - Attack category.
37
+ * @param {string} [attack.source] - Where the attack came from.
38
+ * @param {boolean} [attack.wasDetected] - Whether it was caught originally.
39
+ * @param {object} [attack.metadata] - Additional metadata.
40
+ * @returns {object} The recording with ID and timestamp.
41
+ */
42
+ record(attack) {
43
+ const recording = {
44
+ id: crypto.randomBytes(8).toString('hex'),
45
+ text: attack.text,
46
+ category: attack.category || 'unknown',
47
+ source: attack.source || 'manual',
48
+ wasDetected: attack.wasDetected != null ? attack.wasDetected : null,
49
+ metadata: attack.metadata || {},
50
+ timestamp: Date.now(),
51
+ hash: crypto.createHash('sha256').update(attack.text).digest('hex').substring(0, 16),
52
+ };
53
+
54
+ this._recordings.push(recording);
55
+ if (this._recordings.length > this.maxRecordings) {
56
+ this._recordings = this._recordings.slice(-Math.floor(this.maxRecordings * 0.75));
57
+ }
58
+
59
+ return recording;
60
+ }
61
+
62
+ /**
63
+ * Replay a single recording against current defenses.
64
+ * @param {string} recordingId
65
+ * @returns {object} Replay result with detection status.
66
+ */
67
+ replay(recordingId) {
68
+ const recording = this._recordings.find(r => r.id === recordingId);
69
+ if (!recording) return null;
70
+
71
+ const result = scanText(recording.text, { sensitivity: this.sensitivity });
72
+ const detected = result.threats.length > 0;
73
+
74
+ const replayResult = {
75
+ recordingId,
76
+ text: recording.text.substring(0, 100),
77
+ category: recording.category,
78
+ originallyDetected: recording.wasDetected,
79
+ nowDetected: detected,
80
+ improved: !recording.wasDetected && detected,
81
+ regressed: recording.wasDetected && !detected,
82
+ threats: result.threats,
83
+ replayedAt: Date.now(),
84
+ };
85
+
86
+ this._replayHistory.push(replayResult);
87
+ return replayResult;
88
+ }
89
+
90
+ /**
91
+ * Replay ALL recordings against current defenses.
92
+ * Shows what improved, regressed, or stayed the same.
93
+ * @returns {object} Aggregate replay results.
94
+ */
95
+ replayAll() {
96
+ const results = [];
97
+ let improved = 0;
98
+ let regressed = 0;
99
+ let unchanged = 0;
100
+ let nowDetected = 0;
101
+ let nowMissed = 0;
102
+
103
+ for (const recording of this._recordings) {
104
+ const result = scanText(recording.text, { sensitivity: this.sensitivity });
105
+ const detected = result.threats.length > 0;
106
+
107
+ if (recording.wasDetected === false && detected) improved++;
108
+ else if (recording.wasDetected === true && !detected) regressed++;
109
+ else unchanged++;
110
+
111
+ if (detected) nowDetected++;
112
+ else nowMissed++;
113
+
114
+ results.push({
115
+ id: recording.id,
116
+ category: recording.category,
117
+ originally: recording.wasDetected,
118
+ now: detected,
119
+ status: recording.wasDetected === false && detected ? 'improved'
120
+ : recording.wasDetected === true && !detected ? 'regressed'
121
+ : 'unchanged',
122
+ });
123
+ }
124
+
125
+ return {
126
+ total: this._recordings.length,
127
+ nowDetected,
128
+ nowMissed,
129
+ improved,
130
+ regressed,
131
+ unchanged,
132
+ detectionRate: this._recordings.length > 0
133
+ ? (nowDetected / this._recordings.length * 100).toFixed(1) + '%'
134
+ : '0%',
135
+ results,
136
+ replayedAt: Date.now(),
137
+ };
138
+ }
139
+
140
+ /**
141
+ * Find recordings that currently evade detection (for targeted hardening).
142
+ * @returns {Array} Recordings that are not detected by current defenses.
143
+ */
144
+ findEvasions() {
145
+ const evasions = [];
146
+ for (const recording of this._recordings) {
147
+ const result = scanText(recording.text, { sensitivity: this.sensitivity });
148
+ if (result.threats.length === 0) {
149
+ evasions.push({
150
+ id: recording.id,
151
+ text: recording.text,
152
+ category: recording.category,
153
+ source: recording.source,
154
+ hash: recording.hash,
155
+ });
156
+ }
157
+ }
158
+ return evasions;
159
+ }
160
+
161
+ /**
162
+ * Export recordings for sharing or archival.
163
+ * @returns {string} JSON string.
164
+ */
165
+ export() {
166
+ return JSON.stringify({
167
+ version: '1.0',
168
+ exportedAt: Date.now(),
169
+ recordings: this._recordings,
170
+ count: this._recordings.length,
171
+ }, null, 2);
172
+ }
173
+
174
+ /**
175
+ * Import recordings from export.
176
+ * @param {string} json
177
+ * @returns {number} Number of recordings imported.
178
+ */
179
+ import(json) {
180
+ const data = JSON.parse(json);
181
+ const recordings = data.recordings || [];
182
+ this._recordings.push(...recordings);
183
+ if (this._recordings.length > this.maxRecordings) {
184
+ this._recordings = this._recordings.slice(-this.maxRecordings);
185
+ }
186
+ return recordings.length;
187
+ }
188
+
189
+ /**
190
+ * Get all recordings.
191
+ * @param {string} [category] - Filter by category.
192
+ * @returns {Array}
193
+ */
194
+ getRecordings(category) {
195
+ if (category) return this._recordings.filter(r => r.category === category);
196
+ return [...this._recordings];
197
+ }
198
+
199
+ /**
200
+ * Get replay history.
201
+ * @returns {Array}
202
+ */
203
+ getHistory() {
204
+ return [...this._replayHistory];
205
+ }
206
+
207
+ /**
208
+ * Get stats.
209
+ * @returns {object}
210
+ */
211
+ getStats() {
212
+ const categories = {};
213
+ for (const r of this._recordings) {
214
+ categories[r.category] = (categories[r.category] || 0) + 1;
215
+ }
216
+ return {
217
+ totalRecordings: this._recordings.length,
218
+ totalReplays: this._replayHistory.length,
219
+ categories,
220
+ };
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Compare defense effectiveness across two time periods.
226
+ * @param {object} before - replayAll() result from before.
227
+ * @param {object} after - replayAll() result from after.
228
+ * @returns {object} Comparison.
229
+ */
230
+ function compareDefenses(before, after) {
231
+ return {
232
+ detectionRateBefore: before.detectionRate,
233
+ detectionRateAfter: after.detectionRate,
234
+ improvement: parseFloat(after.detectionRate) - parseFloat(before.detectionRate),
235
+ newlyDetected: after.improved,
236
+ regressions: after.regressed,
237
+ verdict: parseFloat(after.detectionRate) > parseFloat(before.detectionRate) ? 'improved'
238
+ : parseFloat(after.detectionRate) < parseFloat(before.detectionRate) ? 'regressed'
239
+ : 'unchanged',
240
+ };
241
+ }
242
+
243
+ module.exports = {
244
+ AttackReplayEngine,
245
+ compareDefenses,
246
+ };