hackmyagent 0.11.13 → 0.11.14

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 (66) hide show
  1. package/dist/attack-engine/feedback-loop.d.ts +36 -0
  2. package/dist/attack-engine/feedback-loop.d.ts.map +1 -0
  3. package/dist/attack-engine/feedback-loop.js +261 -0
  4. package/dist/attack-engine/feedback-loop.js.map +1 -0
  5. package/dist/attack-engine/index.d.ts +13 -0
  6. package/dist/attack-engine/index.d.ts.map +1 -0
  7. package/dist/attack-engine/index.js +21 -0
  8. package/dist/attack-engine/index.js.map +1 -0
  9. package/dist/attack-engine/payload-generator.d.ts +21 -0
  10. package/dist/attack-engine/payload-generator.d.ts.map +1 -0
  11. package/dist/attack-engine/payload-generator.js +210 -0
  12. package/dist/attack-engine/payload-generator.js.map +1 -0
  13. package/dist/attack-engine/target-reader.d.ts +15 -0
  14. package/dist/attack-engine/target-reader.d.ts.map +1 -0
  15. package/dist/attack-engine/target-reader.js +152 -0
  16. package/dist/attack-engine/target-reader.js.map +1 -0
  17. package/dist/attack-engine/training-pipeline.d.ts +57 -0
  18. package/dist/attack-engine/training-pipeline.d.ts.map +1 -0
  19. package/dist/attack-engine/training-pipeline.js +146 -0
  20. package/dist/attack-engine/training-pipeline.js.map +1 -0
  21. package/dist/attack-engine/types.d.ts +133 -0
  22. package/dist/attack-engine/types.d.ts.map +1 -0
  23. package/dist/attack-engine/types.js +22 -0
  24. package/dist/attack-engine/types.js.map +1 -0
  25. package/dist/cli.js +186 -10
  26. package/dist/cli.js.map +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +9 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/output/asff.d.ts.map +1 -1
  32. package/dist/output/asff.js +2 -1
  33. package/dist/output/asff.js.map +1 -1
  34. package/dist/semantic/index.d.ts +2 -0
  35. package/dist/semantic/index.d.ts.map +1 -1
  36. package/dist/semantic/index.js +9 -1
  37. package/dist/semantic/index.js.map +1 -1
  38. package/dist/semantic/nanomind-analyzer.d.ts +77 -0
  39. package/dist/semantic/nanomind-analyzer.d.ts.map +1 -0
  40. package/dist/semantic/nanomind-analyzer.js +165 -0
  41. package/dist/semantic/nanomind-analyzer.js.map +1 -0
  42. package/dist/simulation/engine.d.ts +69 -0
  43. package/dist/simulation/engine.d.ts.map +1 -0
  44. package/dist/simulation/engine.js +297 -0
  45. package/dist/simulation/engine.js.map +1 -0
  46. package/dist/simulation/index.d.ts +15 -0
  47. package/dist/simulation/index.d.ts.map +1 -0
  48. package/dist/simulation/index.js +31 -0
  49. package/dist/simulation/index.js.map +1 -0
  50. package/dist/simulation/llm-executor.d.ts +58 -0
  51. package/dist/simulation/llm-executor.d.ts.map +1 -0
  52. package/dist/simulation/llm-executor.js +297 -0
  53. package/dist/simulation/llm-executor.js.map +1 -0
  54. package/dist/simulation/mock-tools.d.ts +35 -0
  55. package/dist/simulation/mock-tools.d.ts.map +1 -0
  56. package/dist/simulation/mock-tools.js +181 -0
  57. package/dist/simulation/mock-tools.js.map +1 -0
  58. package/dist/simulation/probes.d.ts +17 -0
  59. package/dist/simulation/probes.d.ts.map +1 -0
  60. package/dist/simulation/probes.js +295 -0
  61. package/dist/simulation/probes.js.map +1 -0
  62. package/dist/simulation/types.d.ts +79 -0
  63. package/dist/simulation/types.d.ts.map +1 -0
  64. package/dist/simulation/types.js +25 -0
  65. package/dist/simulation/types.js.map +1 -0
  66. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1743,8 +1743,9 @@ Examples:
1743
1743
  .option('-b, --benchmark <name>', 'Run benchmark compliance check (e.g., oasb-1)')
1744
1744
  .option('-l, --level <level>', 'Benchmark level: L1 (Essential), L2 (Standard), L3 (Hardened)', 'L1')
1745
1745
  .option('-c, --category <name>', 'Filter to specific benchmark category')
1746
- .option('--deep', 'Enable LLM-powered semantic analysis (requires ANTHROPIC_API_KEY)')
1747
- .option('--scan-depth <depth>', 'CAAT scan depth: quick (config+creds only), standard (default), deep (+ LLM analysis)', 'standard')
1746
+ .option('--deep', 'Maximum analysis: static + NanoMind + behavioral simulation + adaptive attacks (~30s per artifact)')
1747
+ .option('--static-only', 'Disable NanoMind and simulation (static checks only, fast, deterministic)')
1748
+ .option('--scan-depth <depth>', 'CAAT scan depth: quick (config+creds only), standard (default), deep (+ simulation)', 'standard')
1748
1749
  .option('--ci-publish', 'Submit scan results to registry CI endpoint (requires CI_SCAN_HMAC_SECRET env)')
1749
1750
  .option('--publish', 'Push scan results to the OpenA2A Registry')
1750
1751
  .option('--registry-report', 'Post results to OpenA2A Registry')
@@ -1817,17 +1818,41 @@ Examples:
1817
1818
  console.error(`Error: Invalid scan depth '${options.scanDepth}'. Use: ${validDepths.join(', ')}`);
1818
1819
  process.exit(1);
1819
1820
  }
1820
- // Deep mode: --deep flag OR --scan-depth deep
1821
+ // Analysis mode: smart defaults, minimal flags
1822
+ // Default: static + NanoMind (if daemon available)
1823
+ // --deep: everything (static + NanoMind + simulation + adaptive attacks)
1824
+ // --static-only: just static checks (CI/deterministic)
1825
+ // --ci: implies --static-only
1826
+ const isStaticOnly = options.staticOnly ?? false;
1821
1827
  const isDeep = options.deep ?? (scanDepth === 'deep');
1822
- const onProgress = isDeep && format === 'text'
1828
+ // Auto-detect NanoMind daemon
1829
+ let nanomindAvailable = false;
1830
+ if (!isStaticOnly && !options.ci) {
1831
+ try {
1832
+ const { isDaemonAvailable } = await Promise.resolve().then(() => __importStar(require('./semantic/nanomind-analyzer.js')));
1833
+ nanomindAvailable = await isDaemonAvailable();
1834
+ }
1835
+ catch { /* daemon not installed */ }
1836
+ }
1837
+ const onProgress = format === 'text'
1823
1838
  ? (msg) => process.stdout.write(msg)
1824
1839
  : undefined;
1825
- if (isDeep && format === 'text') {
1826
- if (!process.env.ANTHROPIC_API_KEY) {
1827
- console.log(`Layer 3: Semantic analysis — skipped (no ANTHROPIC_API_KEY)`);
1828
- console.log(` Tip: Add HackMyAgent as an MCP server for free LLM analysis:`);
1829
- console.log(` npx ${CLI_PREFIX} init-mcp\n`);
1840
+ // Show analysis mode to user
1841
+ if (format === 'text') {
1842
+ if (isStaticOnly || options.ci) {
1843
+ // Static only -- no extra output
1844
+ }
1845
+ else if (nanomindAvailable && isDeep) {
1846
+ console.log(`Analysis: static + NanoMind + behavioral simulation + adaptive attacks\n`);
1847
+ }
1848
+ else if (nanomindAvailable) {
1849
+ console.log(`Analysis: static + NanoMind (enhanced accuracy)\n`);
1830
1850
  }
1851
+ else if (isDeep) {
1852
+ console.log(`Analysis: static + behavioral simulation\n`);
1853
+ console.log(` Tip: Install NanoMind for even better results: nanomind-daemon start\n`);
1854
+ }
1855
+ // Default static-only: no message needed, it's the baseline
1831
1856
  }
1832
1857
  if (scanDepth === 'quick' && format === 'text') {
1833
1858
  console.log(`Scan depth: quick (config checks + credential detection only)\n`);
@@ -1845,6 +1870,53 @@ Examples:
1845
1870
  onProgress,
1846
1871
  });
1847
1872
  const scanDurationMs = Date.now() - scanStartMs;
1873
+ // Behavioral simulation: auto-runs on --deep, or when NanoMind detects ambiguity
1874
+ if (isDeep && format === 'text') {
1875
+ try {
1876
+ const { SimulationEngine, parseSkillProfile } = await Promise.resolve().then(() => __importStar(require('./simulation/index.js')));
1877
+ const { readFileSync, readdirSync, statSync } = await Promise.resolve().then(() => __importStar(require('node:fs')));
1878
+ const { join } = await Promise.resolve().then(() => __importStar(require('node:path')));
1879
+ // Find skill files in target directory
1880
+ const skillFiles = [];
1881
+ const findSkills = (dir) => {
1882
+ try {
1883
+ for (const entry of readdirSync(dir)) {
1884
+ const fullPath = join(dir, entry);
1885
+ const stat = statSync(fullPath);
1886
+ if (stat.isDirectory() && !entry.startsWith('.') && entry !== 'node_modules') {
1887
+ findSkills(fullPath);
1888
+ }
1889
+ else if (entry.endsWith('.md') || entry.endsWith('.yaml') || entry.endsWith('.yml')) {
1890
+ skillFiles.push(fullPath);
1891
+ }
1892
+ }
1893
+ }
1894
+ catch { /* skip inaccessible dirs */ }
1895
+ };
1896
+ findSkills(targetDir);
1897
+ if (skillFiles.length === 0) {
1898
+ process.stdout.write(`\n[Simulation] No skill/SOUL/MCP artifacts found. Simulation skipped.\n\n`);
1899
+ }
1900
+ else {
1901
+ process.stdout.write(`\n[Simulation] Running behavioral simulation on ${skillFiles.length} artifact(s)...\n`);
1902
+ const sim = new SimulationEngine({ useLLM: nanomindAvailable });
1903
+ for (const file of skillFiles.slice(0, 10)) { // Cap at 10 files
1904
+ const content = readFileSync(file, 'utf-8');
1905
+ const profile = parseSkillProfile(content, file.split('/').pop() ?? 'unknown');
1906
+ const simResult = await sim.runLayer3(profile);
1907
+ const icon = simResult.verdict === 'CLEAN' ? 'PASS' : simResult.verdict === 'SUSPICIOUS' ? 'WARN' : 'FAIL';
1908
+ process.stdout.write(` [${icon}] ${file.split('/').pop()} — ${simResult.verdict} (${(simResult.confidence * 100).toFixed(0)}% confidence, ${simResult.failedProbes.length}/${simResult.probeCount} probes failed)\n`);
1909
+ // Auto-export training data
1910
+ const { exportSimulationTraining } = await Promise.resolve().then(() => __importStar(require('./attack-engine/training-pipeline.js')));
1911
+ exportSimulationTraining(content, simResult);
1912
+ }
1913
+ process.stdout.write(`[Simulation] Complete.\n\n`);
1914
+ } // end skillFiles.length > 0
1915
+ }
1916
+ catch (err) {
1917
+ process.stdout.write(`[Simulation] Skipped: ${err instanceof Error ? err.message : 'unknown error'}\n\n`);
1918
+ }
1919
+ }
1848
1920
  // OASB-2 composite mode: infrastructure (50%) + governance (50%)
1849
1921
  if (isOasb2) {
1850
1922
  const infraResult = generateBenchmarkReport(result.allFindings || result.findings, level, options.category);
@@ -4412,7 +4484,8 @@ Examples:
4412
4484
  .option('--tier <tier>', 'Override agent tier detection (BASIC, TOOL-USING, AGENTIC, MULTI-AGENT)')
4413
4485
  .option('--profile <profile>', 'Override agent profile (conversational, code-assistant, tool-agent, autonomous, orchestrator, custom)')
4414
4486
  .option('--fail-below <score>', 'Exit 1 if score below threshold (0-100)')
4415
- .option('--deep', 'Enable LLM semantic analysis for ambiguous controls (requires claude CLI or ANTHROPIC_API_KEY)')
4487
+ .option('--deep', 'Maximum analysis: NanoMind + SOUL governance simulation (~15s)')
4488
+ .option('--static-only', 'Disable NanoMind (static governance checks only)')
4416
4489
  .option('--publish', 'Push scan results to the OpenA2A Registry')
4417
4490
  .option('--registry-url <url>', 'Registry URL (default: REGISTRY_URL env)', validateRegistryUrl(process.env.REGISTRY_URL || 'https://api.oa2a.org'))
4418
4491
  .option('--contribute', 'Share anonymized scan findings with OpenA2A Registry (overrides config)')
@@ -5047,6 +5120,109 @@ program
5047
5120
  writeJsonStdout({ totalChecks: Object.keys(metadata).length, checks: metadata });
5048
5121
  });
5049
5122
  // Show help and exit 0 when no arguments provided
5123
+ // explain command: NanoMind-powered finding explanation
5124
+ program
5125
+ .command('explain')
5126
+ .argument('<findingId>', 'Finding ID to explain (e.g., SKILL-SEMANTIC-007 or CRED-001)')
5127
+ .description('Explain a security finding in plain English using NanoMind')
5128
+ .action(async (findingId) => {
5129
+ console.log(`Explaining finding: ${findingId}\n`);
5130
+ // Try NanoMind daemon first for dynamic explanation
5131
+ const { isDaemonAvailable, explainFinding } = await Promise.resolve().then(() => __importStar(require('./semantic/nanomind-analyzer.js')));
5132
+ const available = await isDaemonAvailable();
5133
+ if (available) {
5134
+ const explanation = await explainFinding(JSON.stringify({ findingId }));
5135
+ if (explanation) {
5136
+ console.log(explanation);
5137
+ return;
5138
+ }
5139
+ }
5140
+ // Fallback: static explanation from check metadata
5141
+ const checkId = findingId.toUpperCase();
5142
+ const staticExplanations = {
5143
+ 'CRED-001': 'Hardcoded credential detected. API keys, tokens, or passwords are embedded directly in source code. Replace with environment variable references ($VAR_NAME) and rotate the exposed credential immediately.',
5144
+ 'CRED-002': 'OpenAI API key pattern detected (sk-...). Move to environment variable OPENAI_API_KEY.',
5145
+ 'CRED-003': 'Anthropic API key pattern detected (sk-ant-...). Move to environment variable ANTHROPIC_API_KEY.',
5146
+ 'CRED-004': 'AWS credential pattern detected. Use AWS SDK credential chain or environment variables.',
5147
+ 'MCP-001': 'MCP server running without TLS. Agent-to-server communication is unencrypted.',
5148
+ 'SKILL-005': 'External endpoint in skill capability declaration. Verify the endpoint is trusted.',
5149
+ };
5150
+ const explanation = staticExplanations[checkId];
5151
+ if (explanation) {
5152
+ console.log(`${checkId}: ${explanation}`);
5153
+ }
5154
+ else {
5155
+ console.log(`No explanation available for ${findingId}.`);
5156
+ if (!available) {
5157
+ console.log(`\nFor dynamic explanations, install NanoMind: npm install -g @nanomind/cli && nanomind-daemon start`);
5158
+ }
5159
+ }
5160
+ });
5161
+ // red-team command: NanoMind-powered adaptive attack engine
5162
+ program
5163
+ .command('red-team')
5164
+ .argument('<target>', 'Path to artifact to red-team (skill, SOUL.md, MCP config, system prompt)')
5165
+ .description('Run adaptive attack session against an artifact. NanoMind generates target-specific attacks, observes responses, adapts, and maps defenses.')
5166
+ .option('--iterations <n>', 'Max attack iterations per category', '5')
5167
+ .option('--json', 'Output results as JSON')
5168
+ .action(async (target, options) => {
5169
+ const { readFileSync } = await Promise.resolve().then(() => __importStar(require('node:fs')));
5170
+ const { runAttackSession, exportTrainingData } = await Promise.resolve().then(() => __importStar(require('./attack-engine/feedback-loop.js')));
5171
+ const { exportAttackTraining } = await Promise.resolve().then(() => __importStar(require('./attack-engine/training-pipeline.js')));
5172
+ let content;
5173
+ try {
5174
+ content = readFileSync(target, 'utf-8');
5175
+ }
5176
+ catch {
5177
+ console.error(`Cannot read file: ${target}`);
5178
+ process.exit(1);
5179
+ }
5180
+ const artifactType = target.toLowerCase().includes('soul') ? 'soul'
5181
+ : target.toLowerCase().includes('mcp') ? 'mcp_tool'
5182
+ : 'skill';
5183
+ const name = target.split('/').pop() ?? 'unknown';
5184
+ if (!options.json) {
5185
+ console.log(`\nAdaptive Attack Engine`);
5186
+ console.log(`Target: ${name} (${artifactType})`);
5187
+ console.log(`Max iterations: ${options.iterations ?? 5} per category\n`);
5188
+ }
5189
+ const result = await runAttackSession(content, artifactType, name, {
5190
+ maxIterations: parseInt(options.iterations ?? '5', 10),
5191
+ });
5192
+ if (options.json) {
5193
+ console.log(JSON.stringify(result, null, 2));
5194
+ }
5195
+ else {
5196
+ console.log(`Results:`);
5197
+ console.log(` Payloads generated: ${result.totalPayloads}`);
5198
+ console.log(` Successful attacks: ${result.successCount}`);
5199
+ console.log(` Partial successes: ${result.partialCount}`);
5200
+ console.log(` Resilience score: ${(result.defenseMap.resilienceScore * 100).toFixed(0)}%`);
5201
+ console.log(` Duration: ${result.durationMs}ms\n`);
5202
+ if (result.vulnerabilities.length > 0) {
5203
+ console.log(`Vulnerabilities Found:`);
5204
+ for (const vuln of result.vulnerabilities) {
5205
+ console.log(` [${vuln.severity.toUpperCase()}] ${vuln.title}`);
5206
+ console.log(` ${vuln.description}`);
5207
+ console.log(` Fix: ${vuln.remediation}\n`);
5208
+ }
5209
+ }
5210
+ else {
5211
+ console.log(`No vulnerabilities found. All defenses held.\n`);
5212
+ }
5213
+ if (result.defenseMap.strongCategories.length > 0) {
5214
+ console.log(`Strong defenses: ${result.defenseMap.strongCategories.join(', ')}`);
5215
+ }
5216
+ if (result.defenseMap.weakCategories.length > 0) {
5217
+ console.log(`Weak defenses: ${result.defenseMap.weakCategories.join(', ')}`);
5218
+ }
5219
+ }
5220
+ // Auto-export training data
5221
+ const trainingCount = exportAttackTraining(result);
5222
+ if (!options.json && trainingCount > 0) {
5223
+ console.log(`\n${trainingCount} training samples exported to NanoMind corpus.`);
5224
+ }
5225
+ });
5050
5226
  if (process.argv.length <= 2) {
5051
5227
  program.outputHelp();
5052
5228
  process.exit(0);