agentshield-sdk 8.0.0 → 11.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 (60) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/LICENSE +21 -21
  3. package/README.md +257 -50
  4. package/bin/agentshield-audit +51 -0
  5. package/package.json +7 -10
  6. package/src/adaptive.js +330 -330
  7. package/src/alert-tuning.js +480 -480
  8. package/src/attack-surface.js +408 -0
  9. package/src/audit-streaming.js +1 -1
  10. package/src/badges.js +196 -196
  11. package/src/behavioral-dna.js +12 -0
  12. package/src/canary.js +2 -3
  13. package/src/certification.js +563 -563
  14. package/src/circuit-breaker.js +2 -2
  15. package/src/confused-deputy.js +4 -0
  16. package/src/continuous-security.js +237 -0
  17. package/src/conversation.js +494 -494
  18. package/src/cross-turn.js +3 -17
  19. package/src/ctf.js +462 -462
  20. package/src/detector-core.js +845 -105
  21. package/src/document-scanner.js +795 -795
  22. package/src/drift-monitor.js +356 -0
  23. package/src/encoding.js +429 -429
  24. package/src/enterprise.js +405 -405
  25. package/src/flight-recorder.js +2 -0
  26. package/src/i18n-patterns.js +523 -523
  27. package/src/index.js +19 -0
  28. package/src/intent-binding.js +314 -0
  29. package/src/intent-graph.js +381 -0
  30. package/src/main.js +134 -41
  31. package/src/mcp-guard.js +1532 -0
  32. package/src/message-integrity.js +226 -0
  33. package/src/micro-model.js +939 -0
  34. package/src/ml-detector.js +316 -0
  35. package/src/model-finetuning.js +884 -884
  36. package/src/multimodal.js +296 -296
  37. package/src/nist-mapping.js +2 -2
  38. package/src/observability.js +330 -330
  39. package/src/openclaw.js +450 -450
  40. package/src/otel.js +544 -544
  41. package/src/owasp-2025.js +1 -1
  42. package/src/owasp-agentic.js +420 -0
  43. package/src/plugin-marketplace.js +628 -628
  44. package/src/plugin-system.js +349 -349
  45. package/src/policy-extended.js +635 -635
  46. package/src/policy.js +443 -443
  47. package/src/prompt-hardening.js +195 -0
  48. package/src/prompt-leakage.js +2 -2
  49. package/src/real-attack-datasets.js +2 -2
  50. package/src/redteam-cli.js +440 -0
  51. package/src/self-training.js +586 -631
  52. package/src/semantic-isolation.js +303 -0
  53. package/src/sota-benchmark.js +491 -0
  54. package/src/supply-chain-scanner.js +889 -0
  55. package/src/testing.js +5 -1
  56. package/src/threat-encyclopedia.js +629 -629
  57. package/src/threat-intel-network.js +1017 -1017
  58. package/src/token-analysis.js +467 -467
  59. package/src/tool-output-validator.js +354 -354
  60. package/src/watermark.js +1 -2
@@ -0,0 +1,226 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Agent Shield — Message Integrity Verification (SOTA)
5
+ *
6
+ * HMAC-signs every message in a conversation to detect tampering.
7
+ * Based on IEEE S&P 2026 finding: plugins transmit message history
8
+ * without integrity checks, enabling adversaries to inject forged
9
+ * messages impersonating high-privilege roles.
10
+ *
11
+ * All processing runs locally — no data ever leaves your environment.
12
+ *
13
+ * @module message-integrity
14
+ */
15
+
16
+ const crypto = require('crypto');
17
+
18
+ // =========================================================================
19
+ // MessageIntegrityChain
20
+ // =========================================================================
21
+
22
+ /**
23
+ * Maintains an HMAC-signed chain of messages. Each message's signature
24
+ * includes the previous signature, creating a tamper-evident chain
25
+ * (like a blockchain of conversation messages).
26
+ */
27
+ class MessageIntegrityChain {
28
+ /**
29
+ * @param {object} [options]
30
+ * @param {string} [options.signingKey] - HMAC key. Auto-generated if not provided.
31
+ * @param {string} [options.algorithm='sha256'] - Hash algorithm.
32
+ */
33
+ constructor(options = {}) {
34
+ this.signingKey = options.signingKey || crypto.randomBytes(32).toString('hex');
35
+ this.algorithm = options.algorithm || 'sha256';
36
+
37
+ /** @type {Array<{ role: string, content: string, signature: string, index: number, timestamp: number }>} */
38
+ this.chain = [];
39
+ this.stats = { messagesAdded: 0, verificationsRun: 0, tamperingsDetected: 0 };
40
+ }
41
+
42
+ /**
43
+ * Add a message to the chain and sign it.
44
+ *
45
+ * @param {string} role - Message role: 'system', 'user', 'assistant', 'tool'.
46
+ * @param {string} content - Message content.
47
+ * @returns {{ index: number, signature: string }}
48
+ */
49
+ addMessage(role, content) {
50
+ const index = this.chain.length;
51
+ const previousSig = index > 0 ? this.chain[index - 1].signature : '0'.repeat(64);
52
+ const timestamp = Date.now();
53
+
54
+ // Sign: role + content + index + previousSig + timestamp
55
+ const payload = `${role}:${content}:${index}:${previousSig}:${timestamp}`;
56
+ const signature = this._sign(payload);
57
+
58
+ this.chain.push({ role, content, signature, index, timestamp });
59
+ this.stats.messagesAdded++;
60
+
61
+ return { index, signature };
62
+ }
63
+
64
+ /**
65
+ * Verify the integrity of the entire chain.
66
+ * Detects any message that was modified, inserted, deleted, or reordered.
67
+ *
68
+ * @returns {{ valid: boolean, tampered: Array<object> }}
69
+ */
70
+ verifyChain() {
71
+ this.stats.verificationsRun++;
72
+ const tampered = [];
73
+
74
+ for (let i = 0; i < this.chain.length; i++) {
75
+ const msg = this.chain[i];
76
+ const previousSig = i > 0 ? this.chain[i - 1].signature : '0'.repeat(64);
77
+
78
+ const payload = `${msg.role}:${msg.content}:${msg.index}:${previousSig}:${msg.timestamp}`;
79
+ const expectedSig = this._sign(payload);
80
+
81
+ if (msg.signature !== expectedSig) {
82
+ tampered.push({
83
+ index: i,
84
+ role: msg.role,
85
+ reason: 'Signature mismatch — message content or order was tampered.',
86
+ expected: expectedSig.substring(0, 16) + '...',
87
+ actual: msg.signature.substring(0, 16) + '...'
88
+ });
89
+ }
90
+
91
+ if (msg.index !== i) {
92
+ tampered.push({
93
+ index: i,
94
+ role: msg.role,
95
+ reason: `Index mismatch — expected ${i} but found ${msg.index}. Message may have been reordered.`
96
+ });
97
+ }
98
+ }
99
+
100
+ if (tampered.length > 0) {
101
+ this.stats.tamperingsDetected += tampered.length;
102
+ }
103
+
104
+ return { valid: tampered.length === 0, tampered };
105
+ }
106
+
107
+ /**
108
+ * Verify a single message at a given index.
109
+ *
110
+ * @param {number} index
111
+ * @returns {{ valid: boolean, reason: string|null }}
112
+ */
113
+ verifyMessage(index) {
114
+ if (index < 0 || index >= this.chain.length) {
115
+ return { valid: false, reason: 'Index out of range.' };
116
+ }
117
+
118
+ const msg = this.chain[index];
119
+ const previousSig = index > 0 ? this.chain[index - 1].signature : '0'.repeat(64);
120
+ const payload = `${msg.role}:${msg.content}:${msg.index}:${previousSig}:${msg.timestamp}`;
121
+ const expectedSig = this._sign(payload);
122
+
123
+ if (msg.signature !== expectedSig) {
124
+ return { valid: false, reason: 'Signature mismatch.' };
125
+ }
126
+ return { valid: true, reason: null };
127
+ }
128
+
129
+ /**
130
+ * Detect role boundary violations — messages claiming a role they shouldn't have.
131
+ * Ref: IEEE S&P 2026 — plugins inject forged messages impersonating high-privilege roles.
132
+ *
133
+ * @param {object} [rolePolicy]
134
+ * @param {Set<string>} [rolePolicy.systemSources] - Sources allowed to send 'system' messages.
135
+ * @returns {Array<object>} Violations.
136
+ */
137
+ detectRoleViolations(rolePolicy = {}) {
138
+ const violations = [];
139
+ const systemSources = rolePolicy.systemSources || new Set(['system_init']);
140
+
141
+ for (let i = 0; i < this.chain.length; i++) {
142
+ const msg = this.chain[i];
143
+
144
+ // System messages should only appear at the start
145
+ if (msg.role === 'system' && i > 0) {
146
+ violations.push({
147
+ index: i,
148
+ type: 'late_system_message',
149
+ severity: 'critical',
150
+ description: `System message at index ${i} — system messages should only appear at conversation start. Possible role injection.`
151
+ });
152
+ }
153
+
154
+ // Detect role impersonation patterns in content
155
+ if (msg.role === 'user') {
156
+ const roleImpersonation = /^(?:system|assistant|admin|developer)\s*[:\-]\s/i.test(msg.content);
157
+ if (roleImpersonation) {
158
+ violations.push({
159
+ index: i,
160
+ type: 'role_impersonation_in_content',
161
+ severity: 'high',
162
+ description: `User message at index ${i} starts with a role prefix — possible role impersonation attempt.`
163
+ });
164
+ }
165
+ }
166
+ }
167
+
168
+ return violations;
169
+ }
170
+
171
+ /**
172
+ * Export the chain for storage or transmission.
173
+ * @returns {object}
174
+ */
175
+ export() {
176
+ return {
177
+ chain: this.chain.map(m => ({ ...m })),
178
+ chainLength: this.chain.length,
179
+ lastSignature: this.chain.length > 0 ? this.chain[this.chain.length - 1].signature : null,
180
+ exportedAt: Date.now()
181
+ };
182
+ }
183
+
184
+ /**
185
+ * Import and verify a chain.
186
+ * @param {object} data - Data from export().
187
+ * @returns {{ valid: boolean, imported: number, tampered: Array<object> }}
188
+ */
189
+ import(data) {
190
+ if (!data || !Array.isArray(data.chain)) {
191
+ return { valid: false, imported: 0, tampered: [{ reason: 'Invalid import data.' }] };
192
+ }
193
+
194
+ const oldChain = this.chain;
195
+ this.chain = data.chain;
196
+ const verification = this.verifyChain();
197
+
198
+ if (!verification.valid) {
199
+ this.chain = oldChain; // Rollback
200
+ return { valid: false, imported: 0, tampered: verification.tampered };
201
+ }
202
+
203
+ return { valid: true, imported: this.chain.length, tampered: [] };
204
+ }
205
+
206
+ /**
207
+ * Get stats.
208
+ * @returns {object}
209
+ */
210
+ getStats() {
211
+ return { ...this.stats, chainLength: this.chain.length };
212
+ }
213
+
214
+ /** @private */
215
+ _sign(payload) {
216
+ return crypto.createHmac(this.algorithm, this.signingKey).update(payload).digest('hex');
217
+ }
218
+ }
219
+
220
+ // =========================================================================
221
+ // EXPORTS
222
+ // =========================================================================
223
+
224
+ module.exports = {
225
+ MessageIntegrityChain
226
+ };