progmune-runtime 2.1.6 → 3.2.1

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 (356) hide show
  1. package/README.md +119 -461
  2. package/dist/ablation-study.js +144 -0
  3. package/dist/ablation-study.test.js +18 -0
  4. package/dist/action-runtime.js +3 -1
  5. package/dist/active-learning.js +211 -0
  6. package/dist/analytics.js +139 -0
  7. package/dist/asset-factory.js +309 -0
  8. package/dist/asset-growth.js +244 -0
  9. package/dist/asset-promotion.js +382 -0
  10. package/dist/asset-quality.js +550 -0
  11. package/dist/audit/business-translator.js +285 -0
  12. package/dist/audit/cli.js +66 -0
  13. package/dist/audit/formatters/html.js +379 -0
  14. package/dist/audit/formatters/json.js +11 -0
  15. package/dist/audit/formatters/markdown.js +192 -0
  16. package/dist/audit/formatters/terminal.js +189 -0
  17. package/dist/audit/index.js +25 -0
  18. package/dist/audit/report-builder.js +318 -0
  19. package/dist/audit/types.js +8 -0
  20. package/dist/audit.js +3 -3
  21. package/dist/auto-benchmark-generator.js +137 -0
  22. package/dist/auto-benchmark-generator.test.js +45 -0
  23. package/dist/auto-protocol-synthesizer.js +362 -0
  24. package/dist/auto-protocol-synthesizer.test.js +82 -0
  25. package/dist/autonomous-patch.js +175 -0
  26. package/dist/autonomous-patch.test.js +128 -0
  27. package/dist/badge/badge-server.js +98 -0
  28. package/dist/behavior-miner.js +442 -0
  29. package/dist/belief-layer.js +475 -0
  30. package/dist/benchmark-count.js +5 -0
  31. package/dist/benchmark-generator.js +211 -0
  32. package/dist/benchmark-harness.js +201 -0
  33. package/dist/benchmark-pass-rate.js +7 -0
  34. package/dist/benchmark-report.js +8 -3
  35. package/dist/benchmark-save.js +14 -1
  36. package/dist/bootstrap-validation.js +197 -0
  37. package/dist/bootstrap-validation.test.js +51 -0
  38. package/dist/branch-ledger.js +1 -1
  39. package/dist/capability-gap.js +130 -0
  40. package/dist/certify-html.js +351 -0
  41. package/dist/certify.js +326 -0
  42. package/dist/check.js +4 -4
  43. package/dist/compliance-miner.js +447 -0
  44. package/dist/continuous-benchmark.js +194 -0
  45. package/dist/continuous-benchmark.test.js +116 -0
  46. package/dist/corpus-stats.js +173 -0
  47. package/dist/counterfactual-engine.js +288 -0
  48. package/dist/coverage-dashboard.js +109 -0
  49. package/dist/coverage-system.test.js +205 -0
  50. package/dist/cross-repo-precision.js +352 -0
  51. package/dist/cve-benchmark.js +180 -0
  52. package/dist/cve-benchmark.test.js +28 -0
  53. package/dist/cve-collector.js +73 -0
  54. package/dist/data-quality.js +141 -0
  55. package/dist/decision-engine.js +388 -0
  56. package/dist/derive-metadata.js +250 -0
  57. package/dist/difficulty-active.test.js +198 -0
  58. package/dist/difficulty-map.js +244 -0
  59. package/dist/discovery-analytics.js +125 -0
  60. package/dist/discovery-model.js +149 -0
  61. package/dist/discovery-optimize.test.js +199 -0
  62. package/dist/discovery-trace.js +276 -0
  63. package/dist/discovery-trace.test.js +97 -0
  64. package/dist/emitter.js +83 -1
  65. package/dist/enterprise-dashboard.js +405 -0
  66. package/dist/eval-hardening.js +297 -0
  67. package/dist/eval-hardening.test.js +85 -0
  68. package/dist/evaluation-campaign.js +359 -0
  69. package/dist/evaluation-campaign.test.js +181 -0
  70. package/dist/evidence-growth.js +143 -0
  71. package/dist/evidence-repository.js +209 -0
  72. package/dist/evidence-system.js +441 -0
  73. package/dist/execute.js +15 -7
  74. package/dist/experimental/software-physics.js +291 -0
  75. package/dist/experimental/state-inference.js +516 -0
  76. package/dist/experimental/unsupervised-physics.js +230 -0
  77. package/dist/extract-ir-python.js +54 -7
  78. package/dist/extract-ir.js +376 -12
  79. package/dist/failure-collector.js +2 -2
  80. package/dist/failure-corpus.js +322 -9
  81. package/dist/feedback.js +16 -5
  82. package/dist/feedback.test.js +49 -0
  83. package/dist/file-lock.js +1 -1
  84. package/dist/flywheel-batch.js +292 -0
  85. package/dist/frameworks/express-cli.js +237 -0
  86. package/dist/frameworks/express-detector.js +445 -0
  87. package/dist/frameworks/express-detector.test.js +206 -0
  88. package/dist/frameworks/index.js +30 -0
  89. package/dist/frameworks/nestjs-detector.js +302 -0
  90. package/dist/frameworks/trpc-detector.js +161 -0
  91. package/dist/frameworks/version-awareness.js +179 -0
  92. package/dist/function-synonyms.js +164 -0
  93. package/dist/function-synonyms.test.js +68 -0
  94. package/dist/generalization.test.js +352 -0
  95. package/dist/goal-annotator.js +113 -0
  96. package/dist/goal-planner.js +563 -0
  97. package/dist/gold-cve.js +164 -0
  98. package/dist/gold-cve.test.js +104 -0
  99. package/dist/gold-quality.js +206 -0
  100. package/dist/gold-tiers.js +241 -0
  101. package/dist/governance-dashboard.js +327 -0
  102. package/dist/graph-viz.js +240 -0
  103. package/dist/guided-frontier.js +195 -0
  104. package/dist/hierarchical-planner.js +148 -0
  105. package/dist/identifier-parser.js +260 -0
  106. package/dist/immune-metrics.js +93 -0
  107. package/dist/immune-receiver.js +158 -0
  108. package/dist/immune-reporter.js +1 -1
  109. package/dist/improvement-orchestrator.js +206 -0
  110. package/dist/inject-p0-vocabulary.js +300 -0
  111. package/dist/intent-parser.js +218 -0
  112. package/dist/invariant-algebra.js +476 -0
  113. package/dist/invariant-calculus.js +533 -0
  114. package/dist/ir-utils.js +70 -0
  115. package/dist/ir-utils.test.js +50 -0
  116. package/dist/knowledge-api.js +312 -0
  117. package/dist/knowledge-evolution.js +452 -0
  118. package/dist/knowledge-explorer.js +506 -0
  119. package/dist/knowledge-flywheel.js +274 -0
  120. package/dist/knowledge-governance.js +338 -0
  121. package/dist/knowledge-governance.test.js +150 -0
  122. package/dist/knowledge-graph.js +181 -0
  123. package/dist/knowledge-guided-synth.js +246 -0
  124. package/dist/knowledge-loop.test.js +77 -0
  125. package/dist/knowledge-object.js +316 -0
  126. package/dist/knowledge-package.js +98 -0
  127. package/dist/kpi-dashboard.js +561 -0
  128. package/dist/l3-cross-function.js +280 -0
  129. package/dist/learning-ranker.js +148 -0
  130. package/dist/learning-ranker.test.js +291 -0
  131. package/dist/ledger/accountability.js +322 -0
  132. package/dist/ledger/chain-builder.js +185 -0
  133. package/dist/ledger/cli.js +222 -0
  134. package/dist/ledger/index.js +13 -0
  135. package/dist/ledger/signatures.js +193 -0
  136. package/dist/ledger/types.js +9 -0
  137. package/dist/llm.js +74 -3
  138. package/dist/load-benchmarks.js +8 -3
  139. package/dist/logger.js +66 -0
  140. package/dist/logger.test.js +37 -0
  141. package/dist/logistic-reward.js +339 -0
  142. package/dist/logistic-reward.test.js +180 -0
  143. package/dist/macro-graph.js +193 -0
  144. package/dist/macro-repair.js +183 -0
  145. package/dist/mcp-server.mjs +1202 -483
  146. package/dist/memory-layer.js +42 -5
  147. package/dist/multi-repo-precision.js +422 -0
  148. package/dist/name-free-protocol.js +425 -0
  149. package/dist/name-free-protocol.test.js +170 -0
  150. package/dist/name-scrambling.js +138 -0
  151. package/dist/name-scrambling.test.js +16 -0
  152. package/dist/p3-observability.test.js +281 -0
  153. package/dist/p5-orchestrator.test.js +225 -0
  154. package/dist/pairwise-preference.js +294 -0
  155. package/dist/pairwise-preference.test.js +140 -0
  156. package/dist/planner-constraints.js +104 -0
  157. package/dist/planner-prompts.js +155 -0
  158. package/dist/planner-telemetry.js +415 -0
  159. package/dist/planner-trace.js +214 -0
  160. package/dist/planner.js +162 -167
  161. package/dist/plsb/artifact.js +116 -0
  162. package/dist/plsb/cli.js +71 -0
  163. package/dist/plsb/index.js +19 -0
  164. package/dist/plsb/leaderboard.js +249 -0
  165. package/dist/plsb/report-md.js +156 -0
  166. package/dist/plsb/schema.js +179 -0
  167. package/dist/plsb-benchmark.js +284 -0
  168. package/dist/plsb-benchmark.test.js +119 -0
  169. package/dist/policy/cli.js +134 -0
  170. package/dist/policy/engine.js +333 -0
  171. package/dist/policy/index.js +12 -0
  172. package/dist/policy/types.js +59 -0
  173. package/dist/policy-miner.js +505 -0
  174. package/dist/precision-analyze.js +229 -0
  175. package/dist/precision-benchmark.js +147 -0
  176. package/dist/precision-label-c.js +134 -0
  177. package/dist/precision-label.js +193 -0
  178. package/dist/precision-report-c.js +149 -0
  179. package/dist/precision-report.js +246 -0
  180. package/dist/progmune-status.js +108 -0
  181. package/dist/proof-engine.js +479 -0
  182. package/dist/proof-provenance.js +315 -0
  183. package/dist/protocol-coverage.js +294 -0
  184. package/dist/protocol-detector.js +1189 -0
  185. package/dist/protocol-embedding-expanded.js +297 -0
  186. package/dist/protocol-embedding-expanded.test.js +97 -0
  187. package/dist/protocol-embedding.js +195 -0
  188. package/dist/protocol-embedding.test.js +82 -0
  189. package/dist/protocol-extractor-v2.js +354 -0
  190. package/dist/protocol-extractor-v2.test.js +140 -0
  191. package/dist/protocol-extractor.js +310 -0
  192. package/dist/protocol-extractor.test.js +113 -0
  193. package/dist/protocol-foundation.js +322 -0
  194. package/dist/protocol-foundation.test.js +163 -0
  195. package/dist/protocol-frontier.js +243 -0
  196. package/dist/protocol-frontier.test.js +92 -0
  197. package/dist/protocol-gap-analyzer.js +228 -0
  198. package/dist/protocol-gap-analyzer.test.js +49 -0
  199. package/dist/protocol-invariants.js +276 -0
  200. package/dist/protocol-invariants.test.js +111 -0
  201. package/dist/protocol-knowledge.js +464 -0
  202. package/dist/protocol-miner.js +343 -0
  203. package/dist/protocol-mining.js +207 -0
  204. package/dist/protocol-mining.test.js +37 -0
  205. package/dist/protocol-registry.js +1 -1
  206. package/dist/protocol-security-benchmark.js +222 -0
  207. package/dist/protocol-vulnerability.js +257 -0
  208. package/dist/protocol-vulnerability.test.js +60 -0
  209. package/dist/python-benchmark.js +120 -0
  210. package/dist/python-emitter.js +163 -45
  211. package/dist/python-protocol-extractor.js +187 -0
  212. package/dist/python-protocol-extractor.test.js +116 -0
  213. package/dist/realworld-benchmark.js +646 -0
  214. package/dist/realworld-benchmark.test.js +36 -0
  215. package/dist/repair-arch.test.js +411 -0
  216. package/dist/repair-evolution.test.js +454 -0
  217. package/dist/repair-executor.js +719 -0
  218. package/dist/repair-proposal.js +4 -4
  219. package/dist/repair-ranker.js +141 -0
  220. package/dist/repair-strategies.js +419 -0
  221. package/dist/repair-taxonomy.js +234 -0
  222. package/dist/repair-types.js +12 -0
  223. package/dist/repo-evaluator.js +250 -0
  224. package/dist/repo-evaluator.test.js +128 -0
  225. package/dist/resource-abstraction.js +242 -0
  226. package/dist/resource-detector.js +211 -0
  227. package/dist/result.test.js +43 -0
  228. package/dist/reward-system.js +411 -0
  229. package/dist/reward-system.test.js +175 -0
  230. package/dist/risk-model.js +215 -0
  231. package/dist/rule-miner.js +234 -7
  232. package/dist/rule-specificity.js +254 -0
  233. package/dist/runtime-types.js +27 -0
  234. package/dist/scaffold.js +208 -0
  235. package/dist/scale-collector.test.js +101 -0
  236. package/dist/scale-trajectory-collector.js +128 -0
  237. package/dist/sdk.js +250 -0
  238. package/dist/search-planner.js +4 -41
  239. package/dist/semantic-snapshot.js +1 -1
  240. package/dist/semantic-topology.js +121 -0
  241. package/dist/semantic-trace.js +310 -317
  242. package/dist/sequence-extractor.js +343 -0
  243. package/dist/skill-library.js +245 -0
  244. package/dist/skill-planner.test.js +189 -0
  245. package/dist/software-physics.js +291 -0
  246. package/dist/software-physics.test.js +81 -0
  247. package/dist/ssg-precision.js +478 -0
  248. package/dist/ssg-validator.js +71 -21
  249. package/dist/state-inference-doubleblind.test.js +160 -0
  250. package/dist/state-inference.js +516 -0
  251. package/dist/state-inference.test.js +115 -0
  252. package/dist/state-machine-fingerprint.js +345 -0
  253. package/dist/state-machine-fingerprint.test.js +120 -0
  254. package/dist/state-miner.js +386 -0
  255. package/dist/state-name-inference.js +213 -0
  256. package/dist/state-name-inference.test.js +69 -0
  257. package/dist/strategy-planner.js +262 -96
  258. package/dist/strategy-planner.test.js +135 -0
  259. package/dist/telemetry-analytics.test.js +402 -0
  260. package/dist/terminal-format.js +68 -0
  261. package/dist/terminal-format.test.js +83 -0
  262. package/dist/topology-factory.js +196 -0
  263. package/dist/topology-representation.js +242 -0
  264. package/dist/topology-representation.test.js +27 -0
  265. package/dist/trajectory-augmentation.js +254 -0
  266. package/dist/trajectory-augmentation.test.js +63 -0
  267. package/dist/trajectory-corpus.js +440 -0
  268. package/dist/trajectory-corpus.test.js +32 -0
  269. package/dist/trajectory-feedback.test.js +116 -0
  270. package/dist/transition-synthesizer.js +286 -0
  271. package/dist/transition-synthesizer.test.js +123 -0
  272. package/dist/trust/api-semantic-mapper.js +809 -0
  273. package/dist/trust/call-graph-propagator.js +225 -0
  274. package/dist/trust/cli.js +122 -0
  275. package/dist/trust/compliance-scorer.js +283 -0
  276. package/dist/trust/confidence-calculator.js +261 -0
  277. package/dist/trust/engine.js +1145 -0
  278. package/dist/trust/explainability.js +85 -0
  279. package/dist/trust/formatters/ci.js +42 -0
  280. package/dist/trust/formatters/json.js +11 -0
  281. package/dist/trust/formatters/terminal.js +152 -0
  282. package/dist/trust/index.js +39 -0
  283. package/dist/trust/phase1-verify.js +171 -0
  284. package/dist/trust/protocol-domain-validator.js +697 -0
  285. package/dist/trust/score-calculator.js +282 -0
  286. package/dist/trust/ssg-bridge.js +641 -0
  287. package/dist/trust/ssg-bridge.test.js +269 -0
  288. package/dist/trust/types.js +67 -0
  289. package/dist/trust/violation-trace.js +335 -0
  290. package/dist/trust-api.js +179 -0
  291. package/dist/trust-calibration.js +279 -0
  292. package/dist/unknown-protocol-discovery.js +339 -0
  293. package/dist/unknown-protocol-discovery.test.js +102 -0
  294. package/dist/unsupervised-physics.js +230 -0
  295. package/dist/unsupervised-physics.test.js +95 -0
  296. package/dist/utils.test.js +37 -0
  297. package/dist/validator.js +187 -10
  298. package/dist/verification-intelligence.js +475 -0
  299. package/dist/verify-api.js +432 -0
  300. package/dist/vi-impact-report.js +293 -0
  301. package/dist/wl-fingerprint.js +162 -0
  302. package/dist/wl-fingerprint.test.js +130 -0
  303. package/dist/zeroshot-strategy.js +139 -0
  304. package/docs/Progmune_/346/212/225/350/265/204/344/272/272/347/231/275/347/232/256/344/271/246_v2.0.html +576 -0
  305. package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +721 -0
  306. package/package.json +73 -6
  307. package/protocols.json +1956 -50
  308. package/.dockerignore +0 -14
  309. package/.mcp.json +0 -11
  310. package/.progmune_allowlist +0 -50
  311. package/.test_report/test_report.md +0 -87
  312. package/Dockerfile +0 -9
  313. package/FAQ.md +0 -167
  314. package/WHITEPAPER.md +0 -540
  315. package/demo-project/auth.ts +0 -55
  316. package/demo-project/tsconfig.json +0 -8
  317. package/dist/acl-breakdown.js +0 -13
  318. package/dist/all-sessions.js +0 -11
  319. package/dist/antibody-stats.js +0 -11
  320. package/dist/branch-tree-count.js +0 -14
  321. package/dist/common-fixpath.js +0 -12
  322. package/dist/constraint-types.js +0 -12
  323. package/dist/exec-metrics.js +0 -11
  324. package/dist/failure-report.js +0 -11
  325. package/dist/fast-path-hits.js +0 -13
  326. package/dist/fingerprint-list.js +0 -15
  327. package/dist/gen-history-log.js +0 -13
  328. package/dist/heatmap-data.js +0 -11
  329. package/dist/recent-session.js +0 -12
  330. package/dist/svl-distribution.js +0 -11
  331. package/dist/terminal-status.js +0 -11
  332. package/dist/token-savings.js +0 -11
  333. package/dist/total-repairs.js +0 -12
  334. package/dist/unresolved-count.js +0 -12
  335. package/dist/valid-fingerprints.js +0 -13
  336. package/dist/verify-ledgers.js +0 -11
  337. package/docs/whitepaper-style.css +0 -77
  338. package/docs/whitepaper-v2.1.md +0 -609
  339. package/docs/whitepaper-v2.2.md +0 -1064
  340. package/docs/whitepaper-v2.2.pdf +0 -0
  341. package/fly.toml +0 -31
  342. package/public/dashboard.html +0 -119
  343. package/server/hub.js +0 -116
  344. package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
  345. package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
  346. package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
  347. package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
  348. package/test/replay-golden.ts +0 -84
  349. package/test_benchmark.js +0 -165
  350. package/test_comprehensive.mjs +0 -638
  351. package/test_concurrency.js +0 -129
  352. package/test_ir_robustness.js +0 -85
  353. package/test_semantic_contracts.js +0 -269
  354. package/test_ssg_stress.js +0 -156
  355. package/test_svl3.js +0 -58
  356. package/tsconfig.json +0 -17
@@ -0,0 +1,697 @@
1
+ "use strict";
2
+ /**
3
+ * Phase 1: Protocol Domain Validator
4
+ *
5
+ * Validates semantic sequences against known protocol domains.
6
+ * REPLACES the old anomaly-detection approach ("deviation from norm = violation")
7
+ * with domain-aware validation ("does this sequence follow valid protocol patterns?").
8
+ *
9
+ * Core principle: if a call sequence can be semantically mapped to a known
10
+ * protocol domain, and the sequence follows sensible patterns for that domain,
11
+ * it is CLEAN — regardless of whether the SSG has seen this exact pattern before.
12
+ *
13
+ * Architecture:
14
+ * SemanticSequence → Domain Grouping → Pattern Matching → Violation[]
15
+ * (empty violations = CLEAN)
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.SPECIFIC_VIOLATION_CHECKS = void 0;
19
+ exports.validateSemanticSequence = validateSemanticSequence;
20
+ exports.checkSpecificViolations = checkSpecificViolations;
21
+ exports.batchValidateSequences = batchValidateSequences;
22
+ const DOMAIN_GROUPS = [
23
+ {
24
+ name: "TLS/SSL",
25
+ description: "TLS 连接建立、证书验证、会话管理",
26
+ domains: ["tls_config", "tls_handshake", "tls_cert", "tls_session", "tls_alpn"],
27
+ isWellKnown: true,
28
+ },
29
+ {
30
+ name: "Authentication",
31
+ description: "用户认证、凭证管理、SASL/SSPI/GSSAPI 协商",
32
+ domains: ["auth_cred", "auth_mech", "auth_hash", "auth_spn", "auth_gssapi"],
33
+ isWellKnown: true,
34
+ },
35
+ {
36
+ name: "LDAP",
37
+ description: "LDAP 目录服务协议",
38
+ domains: ["ldap_ops"],
39
+ isWellKnown: true,
40
+ },
41
+ {
42
+ name: "FTP",
43
+ description: "FTP 文件传输协议",
44
+ domains: ["ftp_ops"],
45
+ isWellKnown: true,
46
+ },
47
+ {
48
+ name: "SMTP",
49
+ description: "SMTP 邮件传输协议",
50
+ domains: ["smtp_ops"],
51
+ isWellKnown: true,
52
+ },
53
+ {
54
+ name: "IMAP",
55
+ description: "IMAP 邮件访问协议",
56
+ domains: ["imap_ops"],
57
+ isWellKnown: true,
58
+ },
59
+ {
60
+ name: "MQTT",
61
+ description: "MQTT 物联网消息协议",
62
+ domains: ["mqtt_ops"],
63
+ isWellKnown: true,
64
+ },
65
+ {
66
+ name: "SMB",
67
+ description: "SMB 文件共享协议",
68
+ domains: ["smb_ops"],
69
+ isWellKnown: true,
70
+ },
71
+ {
72
+ name: "SSH/SFTP",
73
+ description: "SSH 安全外壳 + SFTP 文件传输",
74
+ domains: ["ssh_ops"],
75
+ isWellKnown: true,
76
+ },
77
+ {
78
+ name: "Telnet",
79
+ description: "Telnet 远程终端协议",
80
+ domains: ["telnet_ops"],
81
+ isWellKnown: true,
82
+ },
83
+ {
84
+ name: "DNS/DoH",
85
+ description: "DNS 解析 + DNS-over-HTTPS",
86
+ domains: ["dns_ops"],
87
+ isWellKnown: true,
88
+ },
89
+ {
90
+ name: "HTTP",
91
+ description: "HTTP/1.x 请求/响应处理",
92
+ domains: ["http_ops"],
93
+ isWellKnown: true,
94
+ },
95
+ {
96
+ name: "HTTP/2",
97
+ description: "HTTP/2 会话管理",
98
+ domains: ["http2_ops"],
99
+ isWellKnown: true,
100
+ },
101
+ {
102
+ name: "Connection Management",
103
+ description: "连接生命周期、轮询、事件循环",
104
+ domains: ["conn_mgmt", "conn_poll"],
105
+ isWellKnown: true,
106
+ },
107
+ ];
108
+ // Noise domains that appear in all protocol implementations
109
+ const NOISE_DOMAINS = [
110
+ "util", "mem_alloc", "mem_free", "mem_util",
111
+ "str_util", "str_format", "buf_util", "net_util",
112
+ "platform_util", "debug_trace", "error_handle",
113
+ ];
114
+ // ═══════════════════════════════════════════════════════════════
115
+ // Compatibility Matrix — which groups can coexist in a valid seq
116
+ // ═══════════════════════════════════════════════════════════════
117
+ /**
118
+ * Groups that commonly appear together in valid protocol implementations.
119
+ * e.g., TLS + Auth together is normal (mutual TLS auth),
120
+ * LDAP + Auth is normal (LDAP bind with SASL),
121
+ * HTTP + TLS is normal (HTTPS).
122
+ */
123
+ const COMPATIBLE_GROUPS = {
124
+ "TLS/SSL": ["Authentication", "HTTP", "HTTP/2", "FTP", "SMTP", "IMAP", "LDAP", "SSH/SFTP", "Connection Management", "DNS/DoH"],
125
+ "Authentication": ["TLS/SSL", "LDAP", "SSH/SFTP", "SMTP", "IMAP", "HTTP", "Connection Management"],
126
+ "LDAP": ["TLS/SSL", "Authentication", "Connection Management"],
127
+ "FTP": ["TLS/SSL", "Connection Management"],
128
+ "SMTP": ["TLS/SSL", "Authentication", "Connection Management"],
129
+ "IMAP": ["TLS/SSL", "Authentication", "HTTP", "Connection Management"],
130
+ "MQTT": ["TLS/SSL", "Connection Management"],
131
+ "SMB": ["Connection Management"],
132
+ "SSH/SFTP": ["TLS/SSL", "Authentication", "Connection Management"],
133
+ "Telnet": ["Connection Management"],
134
+ "DNS/DoH": ["TLS/SSL", "HTTP", "Connection Management"],
135
+ "HTTP": ["TLS/SSL", "Authentication", "HTTP/2", "IMAP", "SMTP", "Connection Management"],
136
+ "HTTP/2": ["TLS/SSL", "HTTP", "Connection Management"],
137
+ "Connection Management": ["TLS/SSL", "Authentication", "LDAP", "FTP", "SMTP", "IMAP", "MQTT", "SMB", "SSH/SFTP", "Telnet", "DNS/DoH", "HTTP", "HTTP/2"],
138
+ };
139
+ /**
140
+ * Classify a ProtocolDomain into its DomainGroup name.
141
+ */
142
+ function classifyDomain(domain) {
143
+ for (const group of DOMAIN_GROUPS) {
144
+ if (group.domains.includes(domain)) {
145
+ return group.name;
146
+ }
147
+ }
148
+ return null;
149
+ }
150
+ /**
151
+ * Check if two domain groups are compatible (can appear together in a valid sequence).
152
+ */
153
+ function areGroupsCompatible(group1, group2) {
154
+ if (group1 === group2)
155
+ return true;
156
+ const compat = COMPATIBLE_GROUPS[group1];
157
+ return compat ? compat.includes(group2) : false;
158
+ }
159
+ /**
160
+ * Validate a semantic sequence against known protocol domains.
161
+ *
162
+ * Algorithm:
163
+ * 1. Extract non-noise domains from the sequence
164
+ * 2. Group consecutive domains into domain groups
165
+ * 3. Check if all groups are mutually compatible
166
+ * 4. If yes → CLEAN (valid protocol operation)
167
+ * 5. If no → flag as potential cross-domain violation
168
+ *
169
+ * This is intentionally lenient — it only flags sequences that clearly
170
+ * mix incompatible protocol domains without proper transitions.
171
+ */
172
+ function validateSemanticSequence(seq) {
173
+ // Extract non-noise, non-util domains
174
+ const significantDomains = seq.domains.filter(d => !NOISE_DOMAINS.includes(d) && d !== "util");
175
+ // If no significant domains → can't validate, assume clean
176
+ if (significantDomains.length === 0) {
177
+ return {
178
+ valid: true,
179
+ groups: [],
180
+ primaryGroup: null,
181
+ };
182
+ }
183
+ // Map to groups, deduplicate
184
+ const groupSet = new Set();
185
+ for (const domain of significantDomains) {
186
+ const group = classifyDomain(domain);
187
+ if (group)
188
+ groupSet.add(group);
189
+ }
190
+ const groups = [...groupSet];
191
+ // Single group → always valid
192
+ if (groups.length <= 1) {
193
+ return {
194
+ valid: true,
195
+ groups,
196
+ primaryGroup: groups[0] || null,
197
+ };
198
+ }
199
+ // Multiple groups → check compatibility
200
+ for (let i = 0; i < groups.length; i++) {
201
+ for (let j = i + 1; j < groups.length; j++) {
202
+ if (!areGroupsCompatible(groups[i], groups[j])) {
203
+ return {
204
+ valid: false,
205
+ groups,
206
+ primaryGroup: groups[0],
207
+ reason: `Incompatible protocol domains: ${groups[i]} and ${groups[j]} cannot appear together without proper transitions`,
208
+ };
209
+ }
210
+ }
211
+ }
212
+ // All groups compatible → valid protocol operation
213
+ return {
214
+ valid: true,
215
+ groups,
216
+ primaryGroup: groups[0],
217
+ };
218
+ }
219
+ function classifyTlsAction(step) {
220
+ const api = step.api.toLowerCase();
221
+ // Actual handshake execution
222
+ // Only unambiguously handshake-only operations.
223
+ // "_connect(" as a function call (not "connection"), or explicit handshake calls.
224
+ // cr_send/send excluded: can be post-handshake data transfer.
225
+ if ((api.includes("_connect") && !api.includes("connection")) ||
226
+ api.includes("_do_handshake") ||
227
+ (api.includes("_handshake") && !api.includes("_is_handshaking"))) {
228
+ return "handshake_exec";
229
+ }
230
+ // CTX management (setup, not handshake)
231
+ if (api.includes("_ctx_new") ||
232
+ api.includes("_ctx_free") ||
233
+ api.includes("_client_method") ||
234
+ api.includes("_server_method") ||
235
+ api.includes("_init_backend") ||
236
+ api.includes("acquire_credential_handle") // Schannel cred acquisition
237
+ ) {
238
+ return "ctx_init";
239
+ }
240
+ // Status/info queries
241
+ if (api.includes("_is_handshaking") ||
242
+ api.includes("_get_version") ||
243
+ api.includes("_get_peer_cert") ||
244
+ api.includes("_get_ciphersuite") ||
245
+ api.includes("_get_negotiated_") ||
246
+ api.includes("_get_protocol_version")) {
247
+ return "status_query";
248
+ }
249
+ return "other";
250
+ }
251
+ exports.SPECIFIC_VIOLATION_CHECKS = [
252
+ // ═══════════════════════════════════════════════════════
253
+ // TLS-001: TLS handshake without certificate verification
254
+ //
255
+ // Phase 3: Only counts actual handshake execution steps
256
+ // (connect, handshake), NOT CTX creation or status queries.
257
+ // Excludes session reuse (cert was verified in original session).
258
+ // ═══════════════════════════════════════════════════════
259
+ {
260
+ ruleId: "TLS_NO_CERT_VERIFY",
261
+ description: "TLS handshake performed without certificate verification. " +
262
+ "Server identity must be cryptographically verified to prevent MITM attacks.",
263
+ check: (steps) => {
264
+ // Phase 3: only count actual handshake execution
265
+ const handshakeExecSteps = steps.filter((s) => s.domain === "tls_handshake" &&
266
+ classifyTlsAction(s) === "handshake_exec");
267
+ const hasActualHandshake = handshakeExecSteps.length >= 1;
268
+ const hasCertVerify = steps.some((s) => s.domain === "tls_cert");
269
+ const hasSessionReuse = steps.some((s) => s.domain === "tls_session" ||
270
+ s.api.toLowerCase().includes("scache") ||
271
+ s.api.toLowerCase().includes("session_reuse") ||
272
+ s.api.toLowerCase().includes("session_set_data") ||
273
+ s.api.toLowerCase().includes("session_resume"));
274
+ return hasActualHandshake && !hasCertVerify && !hasSessionReuse;
275
+ },
276
+ },
277
+ // ═══════════════════════════════════════════════════════
278
+ // AUTH-001: Plaintext auth credentials in network context
279
+ //
280
+ // Only triggers when auth data is being actively prepared AND
281
+ // network transmission is occurring without TLS protection.
282
+ // ═══════════════════════════════════════════════════════
283
+ {
284
+ ruleId: "PLAINTEXT_AUTH_WITHOUT_TLS",
285
+ description: "Authentication credentials transmitted without TLS protection. " +
286
+ "SASL PLAIN, LOGIN, or credential data must be sent over an encrypted channel.",
287
+ check: (steps) => {
288
+ // Auth data being prepared (credentials + mechanism)
289
+ const hasAuthCred = steps.some((s) => s.domain === "auth_cred");
290
+ const hasAuthCreate = steps.some((s) => s.domain === "auth_mech" &&
291
+ (s.api.toLowerCase().includes("create") ||
292
+ s.api.toLowerCase().includes("build") ||
293
+ s.api.toLowerCase().includes("encode")));
294
+ // Network activity — data being sent or connection being used
295
+ const hasNetworkTx = steps.some((s) => s.domain === "conn_mgmt" &&
296
+ (s.api.toLowerCase().includes("send") ||
297
+ s.api.toLowerCase().includes("flush") ||
298
+ s.api.toLowerCase().includes("connect") ||
299
+ s.api.toLowerCase().includes("write") ||
300
+ s.api.toLowerCase().includes("perform") ||
301
+ s.api.toLowerCase().includes("get_current_host")));
302
+ // TLS protection present
303
+ const hasTls = steps.some((s) => s.domain === "tls_handshake" ||
304
+ s.domain === "tls_cert" ||
305
+ s.domain === "tls_session" ||
306
+ (s.domain === "tls_config" &&
307
+ (s.api.toLowerCase().includes("is_ssl") ||
308
+ s.api.toLowerCase().includes("ssl_cf"))));
309
+ // Only flag if auth is being actively created for network transmission
310
+ return (hasAuthCred || hasAuthCreate) && hasNetworkTx && !hasTls;
311
+ },
312
+ },
313
+ // ═══════════════════════════════════════════════════════
314
+ // SSH-001: SSH auth without host key verification
315
+ //
316
+ // Looks for SSH auth operations that lack host key checking.
317
+ // The SSH domain itself contains auth state machines; we check
318
+ // that hostkey-related steps appear before auth steps.
319
+ // ═══════════════════════════════════════════════════════
320
+ {
321
+ ruleId: "SSH_NO_HOST_KEY_CHECK",
322
+ description: "SSH authentication proceeds without host key verification. " +
323
+ "The server's host key must be verified before sending credentials.",
324
+ check: (steps) => {
325
+ const sshSteps = steps.filter((s) => s.domain === "ssh_ops");
326
+ // Require substantial SSH activity (not just internal helpers)
327
+ if (sshSteps.length < 4)
328
+ return false;
329
+ const hasHostKey = sshSteps.some((s) => s.api.toLowerCase().includes("hostkey") ||
330
+ s.api.toLowerCase().includes("host_key") ||
331
+ s.api.toLowerCase().includes("known_host"));
332
+ // Only flag if explicit auth operations AND user credential usage
333
+ const hasAuth = sshSteps.some((s) => (s.api.toLowerCase().includes("userauth") ||
334
+ s.api.toLowerCase().includes("auth_pass") ||
335
+ s.api.toLowerCase().includes("auth_pkey") ||
336
+ s.api.toLowerCase().includes("auth_key")) &&
337
+ !s.api.toLowerCase().includes("authlist"));
338
+ // Also require credential operations (not just internal SSH protocol)
339
+ const hasCreds = steps.some((s) => s.domain === "auth_cred" ||
340
+ s.api.toLowerCase().includes("password") ||
341
+ s.api.toLowerCase().includes("credential"));
342
+ return hasAuth && hasCreds && !hasHostKey;
343
+ },
344
+ },
345
+ // ═══════════════════════════════════════════════════════
346
+ // TLS-002: OCSP response parsed without verification
347
+ // ═══════════════════════════════════════════════════════
348
+ {
349
+ ruleId: "OCSP_UNVERIFIED_RESPONSE",
350
+ description: "OCSP stapling response is parsed but the verification result is not checked. " +
351
+ "An unverified OCSP response provides no certificate revocation protection.",
352
+ check: (steps) => {
353
+ const hasOcspParse = steps.some((s) => s.api.toLowerCase().includes("ocsp_response_status") ||
354
+ s.api.toLowerCase().includes("ocsp_response_get"));
355
+ const hasOcspVerify = steps.some((s) => s.api.toLowerCase().includes("ocsp_basic_verify") ||
356
+ s.api.toLowerCase().includes("ocsp_check"));
357
+ return hasOcspParse && !hasOcspVerify;
358
+ },
359
+ },
360
+ // ═══════════════════════════════════════════════════════
361
+ // AUTH-002: SRP authentication (legacy PAKE)
362
+ // ═══════════════════════════════════════════════════════
363
+ {
364
+ ruleId: "AUTH_SRP_USAGE",
365
+ description: "SRP (Secure Remote Password) authentication detected. " +
366
+ "SRP is a legacy PAKE with known limitations. Prefer modern alternatives.",
367
+ check: (steps) => {
368
+ return steps.some((s) => s.api.toLowerCase().includes("srp_") &&
369
+ (s.domain === "auth_cred" || s.domain === "auth_mech"));
370
+ },
371
+ },
372
+ // ═══════════════════════════════════════════════════════
373
+ // TLS-003: Security verification result not consumed
374
+ //
375
+ // Detects when a security verification function is called
376
+ // (OCSP_basic_verify, SSL_get_verify_result, X509_verify_cert)
377
+ // but the result is not checked before proceeding.
378
+ // ═══════════════════════════════════════════════════════
379
+ {
380
+ ruleId: "SECURITY_RESULT_NOT_CHECKED",
381
+ description: "Security verification result may not be checked. " +
382
+ "A verification function was called but no subsequent " +
383
+ "status check or conditional guard was detected.",
384
+ check: (steps) => {
385
+ const verifyApis = [
386
+ "ocsp_basic_verify",
387
+ "ssl_get_verify_result",
388
+ "x509_verify_cert",
389
+ "cert_verify",
390
+ ];
391
+ // Find verification calls
392
+ const verifyIndices = [];
393
+ steps.forEach((s, i) => {
394
+ if (s.domain === "tls_cert" &&
395
+ verifyApis.some((v) => s.api.toLowerCase().includes(v))) {
396
+ verifyIndices.push(i);
397
+ }
398
+ });
399
+ if (verifyIndices.length === 0)
400
+ return false;
401
+ // For the last verify call, check if subsequent steps
402
+ // include error handling or status checks
403
+ const lastVerifyIdx = verifyIndices[verifyIndices.length - 1];
404
+ const subsequentSteps = steps.slice(lastVerifyIdx + 1);
405
+ // Look for: error string functions, status checks, conditional guards
406
+ const hasResultCheck = subsequentSteps.some((s) => s.domain === "error_handle" ||
407
+ s.api.toLowerCase().includes("status") ||
408
+ s.api.toLowerCase().includes("strerror") ||
409
+ s.api.toLowerCase().includes("get_error") ||
410
+ s.api.toLowerCase().includes("_ok") ||
411
+ s.api.toLowerCase().includes("_err"));
412
+ // If verify is called and the NEXT step immediately uses the
413
+ // result of what was verified (e.g., gets peer cert after OCSP verify
414
+ // without checking verify result), it's suspicious
415
+ const immediateUse = subsequentSteps.length > 0 &&
416
+ subsequentSteps[0].domain === "tls_cert" &&
417
+ !hasResultCheck;
418
+ return immediateUse;
419
+ },
420
+ },
421
+ // ═══════════════════════════════════════════════════════
422
+ // SSH-002: SSH host key retrieved but not verified
423
+ //
424
+ // Detects when an SSH host key is obtained (ssh_state_hostkey,
425
+ // ssh_get_publickey_hash) but no known_hosts comparison follows.
426
+ // ═══════════════════════════════════════════════════════
427
+ {
428
+ ruleId: "SSH_HOST_KEY_NOT_VERIFIED",
429
+ description: "SSH host key retrieved but verification against known_hosts " +
430
+ "may be insufficient. Host key must be cryptographically verified.",
431
+ check: (steps) => {
432
+ // Check if hostkey-related step exists
433
+ const hostKeyIdx = steps.findIndex((s) => s.domain === "ssh_ops" &&
434
+ (s.api.toLowerCase().includes("hostkey") ||
435
+ s.api.toLowerCase().includes("host_key")));
436
+ if (hostKeyIdx < 0)
437
+ return false;
438
+ // Check if a verification/comparison step follows
439
+ const afterHostKey = steps.slice(hostKeyIdx + 1);
440
+ const hasVerify = afterHostKey.some((s) => s.api.toLowerCase().includes("verify") ||
441
+ s.api.toLowerCase().includes("check") ||
442
+ s.api.toLowerCase().includes("match") ||
443
+ s.api.toLowerCase().includes("compare") ||
444
+ s.api.toLowerCase().includes("known_host") ||
445
+ s.api.toLowerCase().includes("fingerprint"));
446
+ // Host key present but no verification detected
447
+ return !hasVerify;
448
+ },
449
+ },
450
+ // ═══════════════════════════════════════════════════════
451
+ // TLS-004: SSL connection established but no cert verify visible
452
+ //
453
+ // Phase 4: Cross-function inference. When an SSL connection is
454
+ // clearly being made (conn_is_ssl + do_connect/perform) but no
455
+ // certificate verification is visible in the same function window,
456
+ // this is suspicious. The verification might be in a callback,
457
+ // but we can't confirm from this window alone.
458
+ // Severity: LOW (cross-function uncertainty).
459
+ // ═══════════════════════════════════════════════════════
460
+ {
461
+ ruleId: "TLS_INFERRED_NO_CERT_VERIFY",
462
+ description: "SSL connection established but certificate verification " +
463
+ "not visible in this function window. Verify that cert validation " +
464
+ "is configured in the TLS backend callback or calling function.",
465
+ check: (steps) => {
466
+ // SSL is explicitly confirmed (conn_is_ssl or SSL filter/layer operations)
467
+ const hasSslConfirmed = steps.some((s) => s.api.toLowerCase().includes("conn_is_ssl") ||
468
+ s.api === "do_connect" ||
469
+ (s.domain === "tls_config" &&
470
+ /ssl|tls/i.test(s.api) &&
471
+ !s.api.toLowerCase().includes("close_all")) // closing all SSL is cleanup, not active use
472
+ );
473
+ // Connection is being established (but NOT "connection" which is a noun)
474
+ const hasConnect = steps.some((s) => (s.domain === "conn_mgmt" || s.api === "do_connect") &&
475
+ (/(?<!n)connect(?!i)/i.test(s.api) || // "connect" not in "connection"
476
+ s.api.toLowerCase().includes("perform") ||
477
+ s.api === "do_connect"));
478
+ // No cert verification visible in this window
479
+ const hasCertVerify = steps.some((s) => s.domain === "tls_cert");
480
+ // No session reuse
481
+ const hasSessionReuse = steps.some((s) => s.domain === "tls_session" ||
482
+ s.api.toLowerCase().includes("scache") ||
483
+ s.api.toLowerCase().includes("session_"));
484
+ // Phase 5: SSL filter explicitly added — cert verification is
485
+ // handled inside the filter during connect. Don't flag.
486
+ const hasSslFilterSetup = steps.some((s) => s.api.toLowerCase().includes("ssl_cfilter") ||
487
+ s.api.toLowerCase().includes("ssl_filter_add") ||
488
+ s.api.toLowerCase().includes("ssl_setup"));
489
+ return hasSslConfirmed && hasConnect &&
490
+ !hasCertVerify && !hasSessionReuse && !hasSslFilterSetup;
491
+ },
492
+ },
493
+ // ═══════════════════════════════════════════════════════
494
+ // TLS-005: TLS handshake without hostname verification
495
+ //
496
+ // CVE-2024-2466 pattern: mbedtls_ssl_set_hostname() only called
497
+ // when SNI is set → connecting by IP address skips hostname check.
498
+ // Also covers similar patterns in OpenSSL (SSL_set_tlsext_host_name),
499
+ // GnuTLS (gnutls_server_name_set), wolfSSL (wolfSSL_CTX_set_verify),
500
+ // and Rustls (cr_set_negotiated_alpn with hostname).
501
+ // ═══════════════════════════════════════════════════════
502
+ {
503
+ ruleId: "TLS_NO_HOSTNAME_VERIFY",
504
+ description: "TLS handshake performed without hostname verification. " +
505
+ "Without hostname verification, an attacker can present a valid " +
506
+ "certificate for a different hostname (CVE-2024-2466 pattern).",
507
+ check: (steps) => {
508
+ const hasTlsHandshake = steps.some((s) => s.domain === "tls_handshake" &&
509
+ classifyTlsAction(s) === "handshake_exec");
510
+ // Hostname/SNI verification functions across TLS backends
511
+ const hasHostnameSet = steps.some((s) => s.api.toLowerCase().includes("ssl_set_hostname") || // mbedTLS
512
+ s.api.toLowerCase().includes("set_tlsext_host_name") || // OpenSSL
513
+ s.api.toLowerCase().includes("server_name_set") || // GnuTLS
514
+ s.api.toLowerCase().includes("ctx_set_verify") || // wolfSSL
515
+ s.api.toLowerCase().includes("set_hostname") || // Generic
516
+ s.api.toLowerCase().includes("sni_") // SNI
517
+ );
518
+ // Exclude session reuse / early data / proxy context
519
+ // (hostname was verified when session was established or by proxy)
520
+ const hasPriorContext = steps.some((s) => s.domain === "tls_session" ||
521
+ s.api.toLowerCase().includes("scache") ||
522
+ s.api.toLowerCase().includes("session_") ||
523
+ s.api.toLowerCase().includes("earlydata") || // TLS 1.3 early data
524
+ s.api.toLowerCase().includes("ssl_cf_is_proxy") // proxy handles hostname
525
+ );
526
+ return hasTlsHandshake && !hasHostnameSet && !hasPriorContext;
527
+ },
528
+ },
529
+ // ═══════════════════════════════════════════════════════
530
+ // CRYPTO-001: DH parameters/key not validated
531
+ //
532
+ // libssh FN #36/#41 pattern: Diffie-Hellman parameters generated
533
+ // or key exchanged without validation. Small subgroup attacks
534
+ // (CVE-2016-0701, CVE-2015-4000 LOGJAM) can downgrade or break DH.
535
+ // Must call DH_check/DH_check_pub_key after parameter setup,
536
+ // and check DH_compute_key result for 0 or 1.
537
+ // ═══════════════════════════════════════════════════════
538
+ {
539
+ ruleId: "DH_UNVALIDATED_PARAMETERS",
540
+ description: "DH key exchange performed without parameter validation. " +
541
+ "Unvalidated DH parameters are vulnerable to small subgroup " +
542
+ "attacks (LOGJAM CVE-2015-4000, CVE-2016-0701).",
543
+ check: (steps) => {
544
+ // SSH wrappers handle DH internally — but only suppress if
545
+ // no raw OpenSSL DH operations are also present (mixed = suspicious)
546
+ const hasRawDh = steps.some(s => s.api.toLowerCase().includes("dh_set0") ||
547
+ s.api.toLowerCase().includes("dh_new") ||
548
+ s.api.toLowerCase().includes("dh_compute") ||
549
+ s.api.toLowerCase().includes("derive_init"));
550
+ const wrappedBySsh = steps.some(s => s.api.toLowerCase().includes("dh_init") ||
551
+ s.api.toLowerCase().includes("ssh_dh_keypair"));
552
+ // Mixed: SSH wrapper + raw DH ops → still need to check
553
+ if (wrappedBySsh && !hasRawDh)
554
+ return false;
555
+ const hasDhParams = steps.some(s => s.api.toLowerCase().includes("dh_set0") ||
556
+ s.api.toLowerCase().includes("dh_new") ||
557
+ (s.domain === "auth_hash" && s.api.toLowerCase().includes("dh_")));
558
+ const hasDhCompute = steps.some(s => s.api.toLowerCase().includes("dh_compute") ||
559
+ s.api.toLowerCase().includes("derive_init"));
560
+ const hasDhCheck = steps.some(s => s.api.toLowerCase().includes("dh_check") ||
561
+ s.api.toLowerCase().includes("bn_is_zero") ||
562
+ s.api.toLowerCase().includes("bn_is_one") ||
563
+ s.api.toLowerCase().includes("bn_cmp") ||
564
+ s.api.toLowerCase().includes("dh_param") ||
565
+ s.api.toLowerCase().includes("dh_debug"));
566
+ return (hasDhParams || hasDhCompute) && !hasDhCheck;
567
+ },
568
+ },
569
+ // ═══════════════════════════════════════════════════════
570
+ // AUTH-003: JWT verification without explicit algorithm
571
+ //
572
+ // CVE-2022-23540 pattern: jwt.verify() called without algorithms
573
+ // option → library defaults to "none" → accepts unsigned tokens.
574
+ // Also catches jwt.decode() without verify=true (PyJWT pattern).
575
+ // Severity: HIGH — can lead to complete authentication bypass.
576
+ // ═══════════════════════════════════════════════════════
577
+ {
578
+ ruleId: "JWT_UNSAFE_ALGORITHM",
579
+ description: "JWT verification may not specify required algorithms. " +
580
+ "Without explicit algorithm whitelist, the 'none' algorithm " +
581
+ "can be exploited to accept unsigned tokens (CVE-2022-23540).",
582
+ check: (steps, filePath) => {
583
+ // JWT verification functions being used
584
+ const hasJwtVerify = steps.some((s) => (s.api === "jwt.verify" ||
585
+ s.api === "verify" ||
586
+ s.api.includes("jwt_verify") ||
587
+ s.api.includes("jwtVerify") ||
588
+ s.api.includes("verifyToken")) &&
589
+ (s.domain === "auth_mech" || s.domain === "auth_cred"));
590
+ // Unsafe: jwt.decode without verify (PyJWT pattern)
591
+ const hasJwtDecode = steps.some((s) => (s.api === "jwt.decode" || s.api.includes("jwt_decode")) &&
592
+ !steps.some((t) => t.api.includes("verify")));
593
+ if (!hasJwtVerify && !hasJwtDecode)
594
+ return false;
595
+ // Algorithm explicitly specified as a call name (rare, but possible)
596
+ const hasAlgorithmSpec = steps.some((s) => s.api.toLowerCase().includes("algorithm") ||
597
+ s.api.toLowerCase().includes("alg") ||
598
+ s.api.toLowerCase().includes("hs256") ||
599
+ s.api.toLowerCase().includes("rs256") ||
600
+ s.api.toLowerCase().includes("es256") ||
601
+ s.api.toLowerCase().includes("eddsa"));
602
+ if (hasAlgorithmSpec)
603
+ return false;
604
+ // File-aware check: the `algorithms: ["HS256"]` option is an object
605
+ // literal argument, invisible to call-name analysis. Read the source
606
+ // and verify every jwtVerify/jwt.verify call site has the option nearby.
607
+ if (filePath) {
608
+ try {
609
+ const fs = require("fs");
610
+ const code = fs.readFileSync(filePath, "utf-8");
611
+ const verifyRe = /\b(?:jwtVerify|jwt\.verify|verifyToken|jwt_decode|jwt\.decode)\s*\(/g;
612
+ let found = false;
613
+ let allSafe = true;
614
+ let m;
615
+ while ((m = verifyRe.exec(code)) !== null) {
616
+ found = true;
617
+ // Look at the call's argument window for an algorithms whitelist
618
+ const window = code.slice(m.index, Math.min(m.index + 400, code.length));
619
+ if (!/algorithms\s*:/.test(window)) {
620
+ allSafe = false;
621
+ break;
622
+ }
623
+ }
624
+ if (found && allSafe)
625
+ return false; // every call site whitelists algorithms
626
+ if (found && !allSafe)
627
+ return true; // at least one site lacks the whitelist
628
+ // No verify call sites found in file text → fall through to name-based
629
+ }
630
+ catch {
631
+ // File unreadable → fall through to name-based heuristic
632
+ }
633
+ }
634
+ return true;
635
+ },
636
+ },
637
+ // ═══════════════════════════════════════════════════════
638
+ // QUIC-001: Active migration disabled
639
+ // ═══════════════════════════════════════════════════════
640
+ {
641
+ ruleId: "QUIC_DISABLE_ACTIVE_MIGRATION",
642
+ description: "QUIC connection migration is disabled. This may impact privacy " +
643
+ "and connection resilience. Review if this is intentional.",
644
+ check: (steps) => {
645
+ return steps.some((s) => s.api.toLowerCase().includes("disable_active_migration"));
646
+ },
647
+ },
648
+ ];
649
+ /**
650
+ * Run specific violation checks against a semantic sequence.
651
+ * Returns violations found (empty for Phase 1 MVP).
652
+ */
653
+ function checkSpecificViolations(seq, _filePath) {
654
+ const violations = [];
655
+ for (const check of exports.SPECIFIC_VIOLATION_CHECKS) {
656
+ if (check.check(seq.steps, _filePath)) {
657
+ violations.push({
658
+ ruleId: check.ruleId,
659
+ description: check.description,
660
+ evidence: seq.steps.map(s => `${s.api}[${s.domain}]`).join(" → "),
661
+ });
662
+ }
663
+ }
664
+ return violations;
665
+ }
666
+ /**
667
+ * Batch validate multiple call sequences.
668
+ * This is the main entry point for the Trust Engine integration.
669
+ */
670
+ function batchValidateSequences(sequences, mapSequence) {
671
+ const result = {
672
+ total: sequences.length,
673
+ clean: 0,
674
+ unknown: 0,
675
+ flagged: 0,
676
+ details: [],
677
+ };
678
+ for (const seq of sequences) {
679
+ const semantic = mapSequence(seq.calls);
680
+ const validation = validateSemanticSequence(semantic);
681
+ result.details.push({
682
+ sequence: seq.calls,
683
+ semanticSteps: semantic.steps,
684
+ validation,
685
+ });
686
+ if (validation.valid && validation.primaryGroup !== null) {
687
+ result.clean++;
688
+ }
689
+ else if (validation.primaryGroup === null) {
690
+ result.unknown++;
691
+ }
692
+ else {
693
+ result.flagged++;
694
+ }
695
+ }
696
+ return result;
697
+ }