hackmyagent 0.11.13 → 0.11.15

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 (127) hide show
  1. package/README.md +26 -3
  2. package/dist/attack-engine/feedback-loop.d.ts +36 -0
  3. package/dist/attack-engine/feedback-loop.d.ts.map +1 -0
  4. package/dist/attack-engine/feedback-loop.js +261 -0
  5. package/dist/attack-engine/feedback-loop.js.map +1 -0
  6. package/dist/attack-engine/index.d.ts +13 -0
  7. package/dist/attack-engine/index.d.ts.map +1 -0
  8. package/dist/attack-engine/index.js +21 -0
  9. package/dist/attack-engine/index.js.map +1 -0
  10. package/dist/attack-engine/payload-generator.d.ts +21 -0
  11. package/dist/attack-engine/payload-generator.d.ts.map +1 -0
  12. package/dist/attack-engine/payload-generator.js +210 -0
  13. package/dist/attack-engine/payload-generator.js.map +1 -0
  14. package/dist/attack-engine/target-reader.d.ts +15 -0
  15. package/dist/attack-engine/target-reader.d.ts.map +1 -0
  16. package/dist/attack-engine/target-reader.js +152 -0
  17. package/dist/attack-engine/target-reader.js.map +1 -0
  18. package/dist/attack-engine/training-pipeline.d.ts +57 -0
  19. package/dist/attack-engine/training-pipeline.d.ts.map +1 -0
  20. package/dist/attack-engine/training-pipeline.js +146 -0
  21. package/dist/attack-engine/training-pipeline.js.map +1 -0
  22. package/dist/attack-engine/types.d.ts +133 -0
  23. package/dist/attack-engine/types.d.ts.map +1 -0
  24. package/dist/attack-engine/types.js +22 -0
  25. package/dist/attack-engine/types.js.map +1 -0
  26. package/dist/cli.js +248 -15
  27. package/dist/cli.js.map +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +9 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/nanomind-core/analyzers/capability-analyzer.d.ts +40 -0
  33. package/dist/nanomind-core/analyzers/capability-analyzer.d.ts.map +1 -0
  34. package/dist/nanomind-core/analyzers/capability-analyzer.js +310 -0
  35. package/dist/nanomind-core/analyzers/capability-analyzer.js.map +1 -0
  36. package/dist/nanomind-core/analyzers/code-analyzer.d.ts +21 -0
  37. package/dist/nanomind-core/analyzers/code-analyzer.d.ts.map +1 -0
  38. package/dist/nanomind-core/analyzers/code-analyzer.js +350 -0
  39. package/dist/nanomind-core/analyzers/code-analyzer.js.map +1 -0
  40. package/dist/nanomind-core/analyzers/credential-analyzer.d.ts +20 -0
  41. package/dist/nanomind-core/analyzers/credential-analyzer.d.ts.map +1 -0
  42. package/dist/nanomind-core/analyzers/credential-analyzer.js +317 -0
  43. package/dist/nanomind-core/analyzers/credential-analyzer.js.map +1 -0
  44. package/dist/nanomind-core/analyzers/governance-analyzer.d.ts +22 -0
  45. package/dist/nanomind-core/analyzers/governance-analyzer.d.ts.map +1 -0
  46. package/dist/nanomind-core/analyzers/governance-analyzer.js +393 -0
  47. package/dist/nanomind-core/analyzers/governance-analyzer.js.map +1 -0
  48. package/dist/nanomind-core/analyzers/prompt-analyzer.d.ts +22 -0
  49. package/dist/nanomind-core/analyzers/prompt-analyzer.d.ts.map +1 -0
  50. package/dist/nanomind-core/analyzers/prompt-analyzer.js +486 -0
  51. package/dist/nanomind-core/analyzers/prompt-analyzer.js.map +1 -0
  52. package/dist/nanomind-core/analyzers/scope-analyzer.d.ts +20 -0
  53. package/dist/nanomind-core/analyzers/scope-analyzer.d.ts.map +1 -0
  54. package/dist/nanomind-core/analyzers/scope-analyzer.js +326 -0
  55. package/dist/nanomind-core/analyzers/scope-analyzer.js.map +1 -0
  56. package/dist/nanomind-core/compiler/semantic-compiler.d.ts +41 -0
  57. package/dist/nanomind-core/compiler/semantic-compiler.d.ts.map +1 -0
  58. package/dist/nanomind-core/compiler/semantic-compiler.js +490 -0
  59. package/dist/nanomind-core/compiler/semantic-compiler.js.map +1 -0
  60. package/dist/nanomind-core/index.d.ts +30 -0
  61. package/dist/nanomind-core/index.d.ts.map +1 -0
  62. package/dist/nanomind-core/index.js +45 -0
  63. package/dist/nanomind-core/index.js.map +1 -0
  64. package/dist/nanomind-core/ingestion/artifact-parser.d.ts +48 -0
  65. package/dist/nanomind-core/ingestion/artifact-parser.d.ts.map +1 -0
  66. package/dist/nanomind-core/ingestion/artifact-parser.js +203 -0
  67. package/dist/nanomind-core/ingestion/artifact-parser.js.map +1 -0
  68. package/dist/nanomind-core/ingestion/input-sanitizer.d.ts +49 -0
  69. package/dist/nanomind-core/ingestion/input-sanitizer.d.ts.map +1 -0
  70. package/dist/nanomind-core/ingestion/input-sanitizer.js +80 -0
  71. package/dist/nanomind-core/ingestion/input-sanitizer.js.map +1 -0
  72. package/dist/nanomind-core/scanner-bridge.d.ts +49 -0
  73. package/dist/nanomind-core/scanner-bridge.d.ts.map +1 -0
  74. package/dist/nanomind-core/scanner-bridge.js +317 -0
  75. package/dist/nanomind-core/scanner-bridge.js.map +1 -0
  76. package/dist/nanomind-core/security/defense-in-depth.d.ts +99 -0
  77. package/dist/nanomind-core/security/defense-in-depth.d.ts.map +1 -0
  78. package/dist/nanomind-core/security/defense-in-depth.js +206 -0
  79. package/dist/nanomind-core/security/defense-in-depth.js.map +1 -0
  80. package/dist/nanomind-core/security/integrity-verifier.d.ts +132 -0
  81. package/dist/nanomind-core/security/integrity-verifier.d.ts.map +1 -0
  82. package/dist/nanomind-core/security/integrity-verifier.js +437 -0
  83. package/dist/nanomind-core/security/integrity-verifier.js.map +1 -0
  84. package/dist/nanomind-core/types.d.ts +125 -0
  85. package/dist/nanomind-core/types.d.ts.map +1 -0
  86. package/dist/nanomind-core/types.js +22 -0
  87. package/dist/nanomind-core/types.js.map +1 -0
  88. package/dist/output/asff.d.ts.map +1 -1
  89. package/dist/output/asff.js +2 -1
  90. package/dist/output/asff.js.map +1 -1
  91. package/dist/semantic/index.d.ts +4 -0
  92. package/dist/semantic/index.d.ts.map +1 -1
  93. package/dist/semantic/index.js +13 -1
  94. package/dist/semantic/index.js.map +1 -1
  95. package/dist/semantic/nanomind-analyzer.d.ts +77 -0
  96. package/dist/semantic/nanomind-analyzer.d.ts.map +1 -0
  97. package/dist/semantic/nanomind-analyzer.js +165 -0
  98. package/dist/semantic/nanomind-analyzer.js.map +1 -0
  99. package/dist/semantic/nanomind-enhancer.d.ts +50 -0
  100. package/dist/semantic/nanomind-enhancer.d.ts.map +1 -0
  101. package/dist/semantic/nanomind-enhancer.js +203 -0
  102. package/dist/semantic/nanomind-enhancer.js.map +1 -0
  103. package/dist/simulation/engine.d.ts +69 -0
  104. package/dist/simulation/engine.d.ts.map +1 -0
  105. package/dist/simulation/engine.js +297 -0
  106. package/dist/simulation/engine.js.map +1 -0
  107. package/dist/simulation/index.d.ts +15 -0
  108. package/dist/simulation/index.d.ts.map +1 -0
  109. package/dist/simulation/index.js +31 -0
  110. package/dist/simulation/index.js.map +1 -0
  111. package/dist/simulation/llm-executor.d.ts +58 -0
  112. package/dist/simulation/llm-executor.d.ts.map +1 -0
  113. package/dist/simulation/llm-executor.js +297 -0
  114. package/dist/simulation/llm-executor.js.map +1 -0
  115. package/dist/simulation/mock-tools.d.ts +35 -0
  116. package/dist/simulation/mock-tools.d.ts.map +1 -0
  117. package/dist/simulation/mock-tools.js +181 -0
  118. package/dist/simulation/mock-tools.js.map +1 -0
  119. package/dist/simulation/probes.d.ts +17 -0
  120. package/dist/simulation/probes.d.ts.map +1 -0
  121. package/dist/simulation/probes.js +295 -0
  122. package/dist/simulation/probes.js.map +1 -0
  123. package/dist/simulation/types.d.ts +79 -0
  124. package/dist/simulation/types.d.ts.map +1 -0
  125. package/dist/simulation/types.js +25 -0
  126. package/dist/simulation/types.js.map +1 -0
  127. package/package.json +1 -1
@@ -0,0 +1,317 @@
1
+ "use strict";
2
+ /**
3
+ * NanoMind Scanner Bridge
4
+ *
5
+ * Integrates AST-based analyzers into the existing HMA scan flow.
6
+ * Defense-in-depth: both static and AST checks run. NanoMind can
7
+ * UPGRADE findings (add new, increase severity) but NEVER suppress
8
+ * static findings.
9
+ *
10
+ * Flow:
11
+ * 1. verifyAll() integrity check
12
+ * 2. Discover security-relevant files in target directory
13
+ * 3. Compile each file into a SecurityAST via SemanticCompiler
14
+ * 4. Run ALL AST analyzers (capability, credential, governance, scope)
15
+ * 5. Merge AST findings with static findings using defense-in-depth rules
16
+ * 6. Return merged findings + integrity status
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.runNanoMindScan = runNanoMindScan;
20
+ exports.mergeFindings = mergeFindings;
21
+ const promises_1 = require("node:fs/promises");
22
+ const node_path_1 = require("node:path");
23
+ const semantic_compiler_js_1 = require("./compiler/semantic-compiler.js");
24
+ const capability_analyzer_js_1 = require("./analyzers/capability-analyzer.js");
25
+ const credential_analyzer_js_1 = require("./analyzers/credential-analyzer.js");
26
+ const governance_analyzer_js_1 = require("./analyzers/governance-analyzer.js");
27
+ const scope_analyzer_js_1 = require("./analyzers/scope-analyzer.js");
28
+ const defense_in_depth_js_1 = require("./security/defense-in-depth.js");
29
+ const integrity_verifier_js_1 = require("./security/integrity-verifier.js");
30
+ // ============================================================================
31
+ // Constants
32
+ // ============================================================================
33
+ /**
34
+ * File extensions and names that are security-relevant and should be compiled
35
+ * into SecurityASTs. Kept intentionally broad -- the compiler's artifact
36
+ * classifier will set type to 'unknown' for non-matching content, and
37
+ * analyzers simply produce no findings for unknowns.
38
+ */
39
+ const SECURITY_RELEVANT_EXTENSIONS = new Set([
40
+ '.md', '.json', '.yaml', '.yml', '.toml',
41
+ '.ts', '.js', '.py', '.go', '.rs',
42
+ '.env', '.cfg', '.ini', '.conf',
43
+ ]);
44
+ const SECURITY_RELEVANT_NAMES = new Set([
45
+ '.env', '.cursorrules', '.clinerules', '.windsurfrules',
46
+ 'mcp.json', 'agent.json', 'SOUL.md', 'SKILL.md', 'CLAUDE.md',
47
+ ]);
48
+ /** Maximum file size to compile (1 MB). Larger files are skipped. */
49
+ const MAX_FILE_SIZE = 1048576;
50
+ /** Maximum number of files to compile per scan to bound runtime. */
51
+ const MAX_FILES_PER_SCAN = 200;
52
+ /**
53
+ * Run the NanoMind AST-based scan and merge results with existing static
54
+ * findings. This is the main entry point called from the scanner flow.
55
+ *
56
+ * Defense-in-depth rules:
57
+ * - AST findings ADD to the list (never remove static findings)
58
+ * - If AST and static both flag the same issue, use the higher severity
59
+ * - If AST says benign but static flags it, static wins (suppression blocked)
60
+ */
61
+ async function runNanoMindScan(targetDir, existingFindings) {
62
+ // Step 1: Integrity check before anything else
63
+ const integrity = (0, integrity_verifier_js_1.verifyAll)();
64
+ // If quarantined, return existing findings untouched with status
65
+ if (integrity.status === 'QUARANTINE') {
66
+ return {
67
+ mergedFindings: [...existingFindings],
68
+ astFindings: [],
69
+ integrityStatus: 'QUARANTINE',
70
+ compiledArtifacts: 0,
71
+ nanomindAvailable: false,
72
+ };
73
+ }
74
+ // Step 2: Initialize compiler (heuristic-only if degraded)
75
+ const useNanoMind = integrity.status === 'CLEAN';
76
+ const compiler = new semantic_compiler_js_1.SemanticCompiler({ useNanoMind });
77
+ // Step 3: Discover security-relevant files
78
+ const files = await discoverFiles(targetDir);
79
+ // Step 4: Compile each file and run analyzers
80
+ const allASTFindings = [];
81
+ let compiledCount = 0;
82
+ let nanomindUsedAtLeastOnce = false;
83
+ for (const filePath of files) {
84
+ try {
85
+ const content = await (0, promises_1.readFile)(filePath, 'utf-8');
86
+ const relativePath = (0, node_path_1.relative)(targetDir, filePath);
87
+ const result = await compiler.compile(content, relativePath);
88
+ compiledCount++;
89
+ if (result.nanomindUsed) {
90
+ nanomindUsedAtLeastOnce = true;
91
+ }
92
+ // Run ALL four analyzers against this AST
93
+ const verifier = (ast) => compiler.verifyAST(ast);
94
+ const findings = runAllAnalyzers(result.ast, verifier);
95
+ allASTFindings.push(...findings);
96
+ }
97
+ catch {
98
+ // Skip files that fail to read or compile -- do not block the scan
99
+ continue;
100
+ }
101
+ }
102
+ // Step 5: Merge using defense-in-depth rules
103
+ const mergedFindings = mergeFindings(existingFindings, allASTFindings);
104
+ return {
105
+ mergedFindings,
106
+ astFindings: allASTFindings,
107
+ integrityStatus: integrity.status,
108
+ compiledArtifacts: compiledCount,
109
+ nanomindAvailable: nanomindUsedAtLeastOnce || useNanoMind,
110
+ };
111
+ }
112
+ // ============================================================================
113
+ // File Discovery
114
+ // ============================================================================
115
+ /**
116
+ * Recursively discover security-relevant files in the target directory.
117
+ * Skips node_modules, .git, dist, and other non-security directories.
118
+ */
119
+ async function discoverFiles(dir) {
120
+ const results = [];
121
+ await walkDir(dir, results, 0);
122
+ return results.slice(0, MAX_FILES_PER_SCAN);
123
+ }
124
+ const SKIP_DIRS = new Set([
125
+ 'node_modules', '.git', 'dist', 'build', 'coverage',
126
+ '.next', '.nuxt', '__pycache__', '.venv', 'venv',
127
+ '.tox', '.mypy_cache', 'target', '.cache',
128
+ ]);
129
+ async function walkDir(dir, results, depth) {
130
+ if (depth > 10 || results.length >= MAX_FILES_PER_SCAN)
131
+ return;
132
+ let entries;
133
+ try {
134
+ entries = await (0, promises_1.readdir)(dir, { withFileTypes: true });
135
+ }
136
+ catch {
137
+ return; // Permission denied or similar
138
+ }
139
+ for (const entry of entries) {
140
+ if (results.length >= MAX_FILES_PER_SCAN)
141
+ break;
142
+ const fullPath = (0, node_path_1.join)(dir, entry.name);
143
+ if (entry.isDirectory()) {
144
+ if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith('.')) {
145
+ await walkDir(fullPath, results, depth + 1);
146
+ }
147
+ // Also check dotfiles that are security-relevant (e.g., .cursorrules)
148
+ if (entry.name === '.claude') {
149
+ await walkDir(fullPath, results, depth + 1);
150
+ }
151
+ continue;
152
+ }
153
+ if (!entry.isFile())
154
+ continue;
155
+ // Check by exact name first
156
+ if (SECURITY_RELEVANT_NAMES.has(entry.name)) {
157
+ if (await isWithinSizeLimit(fullPath)) {
158
+ results.push(fullPath);
159
+ }
160
+ continue;
161
+ }
162
+ // Check by extension
163
+ const ext = (0, node_path_1.extname)(entry.name).toLowerCase();
164
+ if (SECURITY_RELEVANT_EXTENSIONS.has(ext)) {
165
+ if (await isWithinSizeLimit(fullPath)) {
166
+ results.push(fullPath);
167
+ }
168
+ }
169
+ // Dotfiles without extension (e.g., .env.local)
170
+ if (entry.name.startsWith('.env')) {
171
+ if (await isWithinSizeLimit(fullPath)) {
172
+ results.push(fullPath);
173
+ }
174
+ }
175
+ }
176
+ }
177
+ async function isWithinSizeLimit(filePath) {
178
+ try {
179
+ const s = await (0, promises_1.stat)(filePath);
180
+ return s.size <= MAX_FILE_SIZE && s.size > 0;
181
+ }
182
+ catch {
183
+ return false;
184
+ }
185
+ }
186
+ // ============================================================================
187
+ // Analyzer Orchestration
188
+ // ============================================================================
189
+ /**
190
+ * Run all four AST analyzers against a compiled SecurityAST.
191
+ * Each analyzer independently queries the AST structure.
192
+ */
193
+ function runAllAnalyzers(ast, verifier) {
194
+ const findings = [];
195
+ // Capability analyzer does not require verifier (checks internally)
196
+ findings.push(...(0, capability_analyzer_js_1.analyzeCapabilities)(ast));
197
+ // Credential, governance, and scope analyzers require AST integrity verification
198
+ findings.push(...(0, credential_analyzer_js_1.analyzeCredentials)(ast, verifier));
199
+ findings.push(...(0, governance_analyzer_js_1.analyzeGovernance)(ast, verifier));
200
+ findings.push(...(0, scope_analyzer_js_1.analyzeScope)(ast, verifier));
201
+ return findings;
202
+ }
203
+ // ============================================================================
204
+ // Finding Merge (Defense-in-Depth)
205
+ // ============================================================================
206
+ /**
207
+ * Severity rank for comparison. Higher number = more severe.
208
+ */
209
+ const SEVERITY_RANK = {
210
+ critical: 4,
211
+ high: 3,
212
+ medium: 2,
213
+ low: 1,
214
+ };
215
+ /**
216
+ * Build a dedup key for matching AST findings to static findings.
217
+ * Two findings are considered "the same issue" if they share the same
218
+ * file path and a matching attack class or check ID prefix.
219
+ */
220
+ function findingMatchKey(file, attackClass, checkId) {
221
+ const f = file ?? '__global__';
222
+ const a = attackClass ?? checkId.split('-').slice(0, 2).join('-');
223
+ return `${f}::${a}`;
224
+ }
225
+ /**
226
+ * Merge AST findings into the static findings list following defense-in-depth:
227
+ *
228
+ * 1. Start with ALL static findings (never remove any)
229
+ * 2. For each AST finding:
230
+ * a. If it matches a static finding (same file + attack class), upgrade
231
+ * severity if AST severity is higher. Never downgrade.
232
+ * b. If AST says passed but static says failed for the same issue,
233
+ * the static finding wins (suppression blocked via validateEnhancement).
234
+ * c. If no matching static finding, add the AST finding as a new finding.
235
+ */
236
+ function mergeFindings(staticFindings, astFindings) {
237
+ // Clone static findings so we don't mutate the originals
238
+ const merged = staticFindings.map(f => ({ ...f }));
239
+ // Index static findings by match key for O(1) lookup
240
+ const staticIndex = new Map();
241
+ for (let i = 0; i < merged.length; i++) {
242
+ const key = findingMatchKey(merged[i].file, merged[i].attackClass, merged[i].checkId);
243
+ const indices = staticIndex.get(key) ?? [];
244
+ indices.push(i);
245
+ staticIndex.set(key, indices);
246
+ }
247
+ for (const astFinding of astFindings) {
248
+ // Skip passed AST findings -- they don't add value in defense-in-depth
249
+ // (they can't suppress static findings and don't represent new issues)
250
+ if (astFinding.passed)
251
+ continue;
252
+ const key = findingMatchKey(astFinding.file, astFinding.attackClass, astFinding.checkId);
253
+ const matchIndices = staticIndex.get(key);
254
+ if (matchIndices && matchIndices.length > 0) {
255
+ // Matching static finding(s) exist -- apply defense-in-depth rules
256
+ for (const idx of matchIndices) {
257
+ const staticFinding = merged[idx];
258
+ // Rule: If AST says passed but static says failed, static wins
259
+ if (!(0, defense_in_depth_js_1.validateEnhancement)(staticFinding.passed, astFinding.passed)) {
260
+ // Suppression blocked -- keep static finding as-is
261
+ continue;
262
+ }
263
+ // Rule: Use the higher severity (AST can only upgrade)
264
+ const astSeverity = normalizeSeverity(astFinding.severity);
265
+ const resolvedSeverity = (0, defense_in_depth_js_1.enforceSeverityFloor)(staticFinding.severity, astSeverity);
266
+ merged[idx] = {
267
+ ...staticFinding,
268
+ severity: resolvedSeverity,
269
+ };
270
+ }
271
+ }
272
+ else {
273
+ // No matching static finding -- add as a new finding
274
+ merged.push(astFindingToSecurityFinding(astFinding));
275
+ }
276
+ }
277
+ return merged;
278
+ }
279
+ // ============================================================================
280
+ // Conversion Helpers
281
+ // ============================================================================
282
+ /**
283
+ * Convert an ASTFinding to a SecurityFinding for the merged output.
284
+ * The `file` property must be truthy for findings to pass the scanner filter.
285
+ */
286
+ function astFindingToSecurityFinding(ast) {
287
+ return {
288
+ checkId: ast.checkId,
289
+ name: ast.name,
290
+ description: ast.description,
291
+ category: ast.category,
292
+ severity: normalizeSeverity(ast.severity),
293
+ passed: ast.passed,
294
+ message: ast.message,
295
+ fixable: ast.fixable,
296
+ file: ast.file ?? 'ast-analysis',
297
+ line: ast.line,
298
+ fix: ast.fix,
299
+ guidance: ast.guidance,
300
+ attackClass: ast.attackClass,
301
+ details: {
302
+ source: 'nanomind-ast',
303
+ confidence: ast.confidence,
304
+ evidence: ast.evidence,
305
+ },
306
+ };
307
+ }
308
+ /**
309
+ * Normalize the 'info' severity level (used by AST analyzers) to 'low'
310
+ * (used by SecurityFinding). The SecurityFinding type does not include 'info'.
311
+ */
312
+ function normalizeSeverity(severity) {
313
+ if (severity === 'info')
314
+ return 'low';
315
+ return severity;
316
+ }
317
+ //# sourceMappingURL=scanner-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner-bridge.js","sourceRoot":"","sources":["../../src/nanomind-core/scanner-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * NanoMind Defense-in-Depth
3
+ *
4
+ * Core security principle: NanoMind is ADVISORY, never AUTHORITATIVE.
5
+ * Even a fully compromised NanoMind gains the attacker nothing.
6
+ *
7
+ * Rules:
8
+ * 1. NanoMind can UPGRADE findings (add, increase severity) but NEVER SUPPRESS
9
+ * 2. Static checks always run regardless of NanoMind's opinion
10
+ * 3. Simulation validates independently -- two systems must agree
11
+ * 4. NanoMind has zero access to credentials, secrets, or sensitive data
12
+ * 5. NanoMind daemon is sandboxed: localhost only, no filesystem beyond model
13
+ * 6. AST signatures verified at every consumer
14
+ * 7. Training data provenance tracked and Claude-reviewed
15
+ * 8. A finding from static analysis can never be removed by NanoMind
16
+ */
17
+ import type { SecurityAST, IntentClass } from '../types.js';
18
+ export type SeverityLevel = 'critical' | 'high' | 'medium' | 'low' | 'info';
19
+ /**
20
+ * Enforce that NanoMind can only upgrade severity, never downgrade.
21
+ * If static analysis says HIGH, NanoMind can upgrade to CRITICAL
22
+ * but can NEVER downgrade to LOW or suppress the finding.
23
+ *
24
+ * This means even if NanoMind is compromised and always returns "benign",
25
+ * static findings are never suppressed.
26
+ */
27
+ export declare function enforceSeverityFloor(staticSeverity: SeverityLevel, nanomindSeverity: SeverityLevel): SeverityLevel;
28
+ /**
29
+ * Validate that a NanoMind enhancement never suppresses a static finding.
30
+ * Returns true if the enhancement is valid (doesn't suppress).
31
+ */
32
+ export declare function validateEnhancement(staticFindingPassed: boolean, nanomindSaysPassed: boolean): boolean;
33
+ /**
34
+ * Require agreement between NanoMind and at least one other system
35
+ * before classifying an artifact as definitively benign.
36
+ *
37
+ * NanoMind alone saying "benign" is not sufficient.
38
+ * Static checks must also show zero findings.
39
+ */
40
+ export declare function requireBenignConsensus(nanomindIntent: IntentClass, staticFindingCount: number, simulationVerdict?: 'CLEAN' | 'SUSPICIOUS' | 'MALICIOUS'): {
41
+ finalClassification: IntentClass;
42
+ consensusReached: boolean;
43
+ reason: string;
44
+ };
45
+ /**
46
+ * Strip ALL credential-like content before sending to NanoMind.
47
+ * This goes beyond the input sanitizer (which strips meta-instructions).
48
+ * This strips actual secrets so NanoMind never sees real credentials.
49
+ *
50
+ * Even if the daemon is compromised, it cannot exfiltrate credentials
51
+ * because it never received them.
52
+ */
53
+ export declare function redactSecretsForNanoMind(content: string): string;
54
+ /**
55
+ * Verify AST hasn't been tampered with before any analyzer consumes it.
56
+ * Every analyzer MUST call this before processing.
57
+ */
58
+ export declare function assertASTIntegrity(ast: SecurityAST, verifier: (ast: SecurityAST) => boolean): void;
59
+ export declare class SecurityError extends Error {
60
+ constructor(message: string);
61
+ }
62
+ export interface TrainingDataProvenance {
63
+ /** SHA-256 hash of the training sample */
64
+ contentHash: string;
65
+ /** Where this sample came from */
66
+ source: 'registry_scan' | 'simulation' | 'attack_session' | 'hma_payload' | 'dvaa' | 'manual';
67
+ /** Who/what labeled it */
68
+ labeledBy: 'heuristic' | 'nanomind' | 'claude_review' | 'human';
69
+ /** Confidence in the label */
70
+ confidence: number;
71
+ /** When it was created */
72
+ createdAt: string;
73
+ /** Has this been reviewed by Claude? */
74
+ claudeReviewed: boolean;
75
+ /** Signature of the provenance record */
76
+ signature: string;
77
+ }
78
+ /**
79
+ * Verify that a training sample has valid provenance.
80
+ * Samples without provenance are rejected from training.
81
+ */
82
+ export declare function verifyTrainingProvenance(provenance: TrainingDataProvenance): boolean;
83
+ export interface NanoMindAuditEvent {
84
+ timestamp: string;
85
+ event: 'classification' | 'suppression_blocked' | 'ast_tamper_detected' | 'secret_redacted' | 'manipulation_detected' | 'consensus_override';
86
+ details: string;
87
+ artifactHash?: string;
88
+ severity: 'info' | 'warning' | 'critical';
89
+ }
90
+ /**
91
+ * Log a NanoMind security event. These events are immutable and
92
+ * should be forwarded to the transparency log.
93
+ */
94
+ export declare function logSecurityEvent(event: Omit<NanoMindAuditEvent, 'timestamp'>): void;
95
+ /**
96
+ * Get all audit events since a given timestamp.
97
+ */
98
+ export declare function getAuditEvents(since?: string): NanoMindAuditEvent[];
99
+ //# sourceMappingURL=defense-in-depth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defense-in-depth.d.ts","sourceRoot":"","sources":["../../../src/nanomind-core/security/defense-in-depth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM5D,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAU5E;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,aAAa,EAC7B,gBAAgB,EAAE,aAAa,GAC9B,aAAa,CAMf;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,mBAAmB,EAAE,OAAO,EAC5B,kBAAkB,EAAE,OAAO,GAC1B,OAAO,CAMT;AAMD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,MAAM,EAC1B,iBAAiB,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,WAAW,GACvD;IACD,mBAAmB,EAAE,WAAW,CAAC;IACjC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CA8CA;AAMD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAqBhE;AAMD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,GACtC,IAAI,CAaN;AAED,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AAMD,MAAM,WAAW,sBAAsB;IACrC,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,MAAM,EAAE,eAAe,GAAG,YAAY,GAAG,gBAAgB,GAAG,aAAa,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC9F,0BAA0B;IAC1B,SAAS,EAAE,WAAW,GAAG,UAAU,GAAG,eAAe,GAAG,OAAO,CAAC;IAChE,8BAA8B;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,cAAc,EAAE,OAAO,CAAC;IACxB,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,sBAAsB,GAAG,OAAO,CAYpF;AAMD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,gBAAgB,GAAG,qBAAqB,GAAG,qBAAqB,GAAG,iBAAiB,GAAG,uBAAuB,GAAG,oBAAoB,CAAC;IAC7I,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;CAC3C;AAID;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,IAAI,CAKnF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAGnE"}
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ /**
3
+ * NanoMind Defense-in-Depth
4
+ *
5
+ * Core security principle: NanoMind is ADVISORY, never AUTHORITATIVE.
6
+ * Even a fully compromised NanoMind gains the attacker nothing.
7
+ *
8
+ * Rules:
9
+ * 1. NanoMind can UPGRADE findings (add, increase severity) but NEVER SUPPRESS
10
+ * 2. Static checks always run regardless of NanoMind's opinion
11
+ * 3. Simulation validates independently -- two systems must agree
12
+ * 4. NanoMind has zero access to credentials, secrets, or sensitive data
13
+ * 5. NanoMind daemon is sandboxed: localhost only, no filesystem beyond model
14
+ * 6. AST signatures verified at every consumer
15
+ * 7. Training data provenance tracked and Claude-reviewed
16
+ * 8. A finding from static analysis can never be removed by NanoMind
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.SecurityError = void 0;
20
+ exports.enforceSeverityFloor = enforceSeverityFloor;
21
+ exports.validateEnhancement = validateEnhancement;
22
+ exports.requireBenignConsensus = requireBenignConsensus;
23
+ exports.redactSecretsForNanoMind = redactSecretsForNanoMind;
24
+ exports.assertASTIntegrity = assertASTIntegrity;
25
+ exports.verifyTrainingProvenance = verifyTrainingProvenance;
26
+ exports.logSecurityEvent = logSecurityEvent;
27
+ exports.getAuditEvents = getAuditEvents;
28
+ const SEVERITY_ORDER = {
29
+ critical: 5,
30
+ high: 4,
31
+ medium: 3,
32
+ low: 2,
33
+ info: 1,
34
+ };
35
+ /**
36
+ * Enforce that NanoMind can only upgrade severity, never downgrade.
37
+ * If static analysis says HIGH, NanoMind can upgrade to CRITICAL
38
+ * but can NEVER downgrade to LOW or suppress the finding.
39
+ *
40
+ * This means even if NanoMind is compromised and always returns "benign",
41
+ * static findings are never suppressed.
42
+ */
43
+ function enforceSeverityFloor(staticSeverity, nanomindSeverity) {
44
+ const staticRank = SEVERITY_ORDER[staticSeverity];
45
+ const nmRank = SEVERITY_ORDER[nanomindSeverity];
46
+ // NanoMind can only make it MORE severe, never less
47
+ return nmRank >= staticRank ? nanomindSeverity : staticSeverity;
48
+ }
49
+ /**
50
+ * Validate that a NanoMind enhancement never suppresses a static finding.
51
+ * Returns true if the enhancement is valid (doesn't suppress).
52
+ */
53
+ function validateEnhancement(staticFindingPassed, nanomindSaysPassed) {
54
+ // Static said FAIL → NanoMind cannot change it to PASS
55
+ if (!staticFindingPassed && nanomindSaysPassed) {
56
+ return false; // BLOCKED: suppression attempt
57
+ }
58
+ return true;
59
+ }
60
+ // ============================================================================
61
+ // Rule 3: Two-System Agreement for Benign Classification
62
+ // ============================================================================
63
+ /**
64
+ * Require agreement between NanoMind and at least one other system
65
+ * before classifying an artifact as definitively benign.
66
+ *
67
+ * NanoMind alone saying "benign" is not sufficient.
68
+ * Static checks must also show zero findings.
69
+ */
70
+ function requireBenignConsensus(nanomindIntent, staticFindingCount, simulationVerdict) {
71
+ // If static found issues, NanoMind's "benign" is overruled
72
+ if (nanomindIntent === 'benign' && staticFindingCount > 0) {
73
+ return {
74
+ finalClassification: 'suspicious',
75
+ consensusReached: false,
76
+ reason: `NanoMind says benign but ${staticFindingCount} static finding(s) exist. Static findings cannot be suppressed.`,
77
+ };
78
+ }
79
+ // If NanoMind says malicious, trust it (it can only upgrade)
80
+ if (nanomindIntent === 'malicious') {
81
+ return {
82
+ finalClassification: 'malicious',
83
+ consensusReached: true,
84
+ reason: 'NanoMind classified as malicious. Malicious classifications are always trusted (can only upgrade).',
85
+ };
86
+ }
87
+ // If simulation ran and disagrees with NanoMind
88
+ if (simulationVerdict === 'MALICIOUS' && nanomindIntent === 'benign') {
89
+ return {
90
+ finalClassification: 'malicious',
91
+ consensusReached: false,
92
+ reason: 'Simulation observed malicious behavior. NanoMind benign classification overruled by behavioral evidence.',
93
+ };
94
+ }
95
+ // Consensus: NanoMind benign + zero static findings + simulation clean (or not run)
96
+ if (nanomindIntent === 'benign' && staticFindingCount === 0) {
97
+ const simClean = !simulationVerdict || simulationVerdict === 'CLEAN';
98
+ return {
99
+ finalClassification: 'benign',
100
+ consensusReached: simClean,
101
+ reason: simClean
102
+ ? 'Consensus: NanoMind benign + zero static findings + simulation clean.'
103
+ : 'NanoMind benign + zero static findings, but simulation not yet run.',
104
+ };
105
+ }
106
+ // Default: suspicious when no consensus
107
+ return {
108
+ finalClassification: 'suspicious',
109
+ consensusReached: false,
110
+ reason: 'No consensus reached. Treated as suspicious until verified.',
111
+ };
112
+ }
113
+ // ============================================================================
114
+ // Rule 4: NanoMind Has Zero Access to Secrets
115
+ // ============================================================================
116
+ /**
117
+ * Strip ALL credential-like content before sending to NanoMind.
118
+ * This goes beyond the input sanitizer (which strips meta-instructions).
119
+ * This strips actual secrets so NanoMind never sees real credentials.
120
+ *
121
+ * Even if the daemon is compromised, it cannot exfiltrate credentials
122
+ * because it never received them.
123
+ */
124
+ function redactSecretsForNanoMind(content) {
125
+ let redacted = content;
126
+ // API keys
127
+ redacted = redacted.replace(/sk-ant-api\d{2}-[a-zA-Z0-9_-]{20,}/g, '[REDACTED_ANTHROPIC_KEY]');
128
+ redacted = redacted.replace(/sk-proj-[a-zA-Z0-9]{20,}/g, '[REDACTED_OPENAI_KEY]');
129
+ redacted = redacted.replace(/AKIA[0-9A-Z]{16}/g, '[REDACTED_AWS_KEY]');
130
+ redacted = redacted.replace(/ghp_[a-zA-Z0-9]{36}/g, '[REDACTED_GITHUB_TOKEN]');
131
+ redacted = redacted.replace(/glpat-[a-zA-Z0-9_-]{20,}/g, '[REDACTED_GITLAB_TOKEN]');
132
+ // Generic secret patterns
133
+ redacted = redacted.replace(/-----BEGIN [A-Z ]+ KEY-----[\s\S]*?-----END [A-Z ]+ KEY-----/g, '[REDACTED_PRIVATE_KEY]');
134
+ redacted = redacted.replace(/(?:password|secret|token|key)\s*[=:]\s*['"][^'"]{8,}['"]/gi, (match) => {
135
+ const prefix = match.split(/[=:]/)[0];
136
+ return `${prefix}=[REDACTED]`;
137
+ });
138
+ // Connection strings
139
+ redacted = redacted.replace(/(?:postgres|mysql|mongodb|redis):\/\/[^\s'"]+/gi, '[REDACTED_CONNECTION_STRING]');
140
+ return redacted;
141
+ }
142
+ // ============================================================================
143
+ // Rule 6: AST Integrity Verification
144
+ // ============================================================================
145
+ /**
146
+ * Verify AST hasn't been tampered with before any analyzer consumes it.
147
+ * Every analyzer MUST call this before processing.
148
+ */
149
+ function assertASTIntegrity(ast, verifier) {
150
+ if (!ast.signature) {
151
+ throw new SecurityError('AST has no signature. Refusing to process unsigned AST.');
152
+ }
153
+ if (!ast.contentHash) {
154
+ throw new SecurityError('AST has no content hash. Refusing to process.');
155
+ }
156
+ if (!verifier(ast)) {
157
+ throw new SecurityError('AST signature verification FAILED. The AST may have been tampered with. ' +
158
+ 'This is a critical security event that should be investigated.');
159
+ }
160
+ }
161
+ class SecurityError extends Error {
162
+ constructor(message) {
163
+ super(message);
164
+ this.name = 'SecurityError';
165
+ }
166
+ }
167
+ exports.SecurityError = SecurityError;
168
+ /**
169
+ * Verify that a training sample has valid provenance.
170
+ * Samples without provenance are rejected from training.
171
+ */
172
+ function verifyTrainingProvenance(provenance) {
173
+ if (!provenance.contentHash)
174
+ return false;
175
+ if (!provenance.source)
176
+ return false;
177
+ if (!provenance.labeledBy)
178
+ return false;
179
+ if (provenance.confidence < 0 || provenance.confidence > 1)
180
+ return false;
181
+ // High-risk: samples from external sources must be Claude-reviewed
182
+ if (provenance.source === 'registry_scan' && !provenance.claudeReviewed) {
183
+ return false; // External data must be validated before training
184
+ }
185
+ return true;
186
+ }
187
+ const auditLog = [];
188
+ /**
189
+ * Log a NanoMind security event. These events are immutable and
190
+ * should be forwarded to the transparency log.
191
+ */
192
+ function logSecurityEvent(event) {
193
+ auditLog.push({
194
+ ...event,
195
+ timestamp: new Date().toISOString(),
196
+ });
197
+ }
198
+ /**
199
+ * Get all audit events since a given timestamp.
200
+ */
201
+ function getAuditEvents(since) {
202
+ if (!since)
203
+ return [...auditLog];
204
+ return auditLog.filter(e => e.timestamp >= since);
205
+ }
206
+ //# sourceMappingURL=defense-in-depth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defense-in-depth.js","sourceRoot":"","sources":["../../../src/nanomind-core/security/defense-in-depth.ts"],"names":[],"mappings":"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"}