fad-checker 2.0.0 → 2.1.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 (139) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +147 -25
  3. package/completions/fad-checker.bash +1 -1
  4. package/completions/fad-checker.zsh +14 -1
  5. package/data/eol-mapping.json +5 -5
  6. package/data/license-policy.json +97 -0
  7. package/fad-checker-report/cve-report.doc +630 -0
  8. package/fad-checker-report/cve-report.html +748 -0
  9. package/fad-checker.js +556 -245
  10. package/lib/cache-archive.js +3 -0
  11. package/lib/codecs/codec.interface.js +3 -0
  12. package/lib/codecs/composer/parse.js +3 -0
  13. package/lib/codecs/composer/registry.js +13 -5
  14. package/lib/codecs/composer.codec.js +3 -0
  15. package/lib/codecs/go/parse.js +65 -0
  16. package/lib/codecs/go/registry.js +74 -0
  17. package/lib/codecs/go.codec.js +76 -0
  18. package/lib/codecs/index.js +7 -2
  19. package/lib/codecs/maven/jar-scan.js +199 -0
  20. package/lib/codecs/maven.codec.js +17 -1
  21. package/lib/codecs/npm/collect.js +37 -17
  22. package/lib/codecs/npm/parse.js +117 -10
  23. package/lib/codecs/npm/registry.js +14 -5
  24. package/lib/codecs/npm.codec.js +4 -1
  25. package/lib/codecs/nuget/parse.js +3 -0
  26. package/lib/codecs/nuget/registry.js +11 -4
  27. package/lib/codecs/nuget.codec.js +7 -2
  28. package/lib/codecs/pypi/parse.js +111 -14
  29. package/lib/codecs/pypi/registry.js +24 -5
  30. package/lib/codecs/pypi.codec.js +30 -6
  31. package/lib/codecs/recipes.js +28 -1
  32. package/lib/codecs/ruby/parse.js +42 -0
  33. package/lib/codecs/ruby/registry.js +76 -0
  34. package/lib/codecs/ruby.codec.js +66 -0
  35. package/lib/codecs/select.js +3 -0
  36. package/lib/codecs/yarn.codec.js +3 -0
  37. package/lib/config.js +3 -0
  38. package/lib/core.js +38 -1
  39. package/lib/cpe.js +30 -5
  40. package/lib/csaf-export.js +159 -0
  41. package/lib/cve-download.js +3 -0
  42. package/lib/cve-match.js +27 -6
  43. package/lib/cve-report.js +157 -28
  44. package/lib/dep-record.js +15 -2
  45. package/lib/deps-descriptor.js +113 -0
  46. package/lib/epss.js +115 -0
  47. package/lib/gate.js +45 -0
  48. package/lib/json-export.js +110 -0
  49. package/lib/kev.js +88 -0
  50. package/lib/license-policy.js +110 -0
  51. package/lib/maven-license.js +52 -0
  52. package/lib/maven-repo.js +3 -0
  53. package/lib/maven-version.js +8 -3
  54. package/lib/nvd.js +17 -6
  55. package/lib/osv.js +75 -23
  56. package/lib/outdated.js +10 -2
  57. package/lib/priority.js +90 -0
  58. package/lib/purl.js +77 -0
  59. package/lib/retire.js +80 -13
  60. package/lib/sarif-export.js +134 -0
  61. package/lib/sbom-export.js +153 -0
  62. package/lib/scan-completeness.js +3 -0
  63. package/lib/snyk.js +3 -0
  64. package/lib/suppress.js +113 -0
  65. package/lib/transitive.js +6 -3
  66. package/lib/ui.js +90 -0
  67. package/package.json +49 -2
  68. package/CLAUDE.md +0 -147
  69. package/docs/ARCHITECTURE.md +0 -182
  70. package/docs/USAGE.md +0 -187
  71. package/docs/superpowers/plans/2026-05-29-codec-composer.md +0 -556
  72. package/docs/superpowers/plans/2026-05-29-codec-foundation.md +0 -851
  73. package/docs/superpowers/plans/2026-05-29-codec-nuget.md +0 -432
  74. package/docs/superpowers/plans/2026-05-29-codec-pypi.md +0 -450
  75. package/docs/superpowers/specs/2026-05-29-codecs-multi-ecosystem-design.md +0 -251
  76. package/test/cli-ecosystem.test.js +0 -30
  77. package/test/codec-edge-cases.test.js +0 -131
  78. package/test/codec-integration.test.js +0 -119
  79. package/test/codecs.test.js +0 -92
  80. package/test/composer.test.js +0 -71
  81. package/test/core.test.js +0 -153
  82. package/test/cpe.test.js +0 -166
  83. package/test/cve-download.test.js +0 -39
  84. package/test/cve-match.test.js +0 -217
  85. package/test/cve-report.test.js +0 -180
  86. package/test/dep-record.test.js +0 -31
  87. package/test/fixtures/complex-enterprise/api/pom.xml +0 -32
  88. package/test/fixtures/complex-enterprise/build/pom.xml +0 -46
  89. package/test/fixtures/complex-enterprise/dao/pom.xml +0 -37
  90. package/test/fixtures/complex-enterprise/pom.xml +0 -66
  91. package/test/fixtures/complex-enterprise/web/pom.xml +0 -77
  92. package/test/fixtures/csharp-config/packages.config +0 -4
  93. package/test/fixtures/csharp-csproj/Directory.Packages.props +0 -5
  94. package/test/fixtures/csharp-csproj/app.csproj +0 -7
  95. package/test/fixtures/csharp-lock/packages.lock.json +0 -6
  96. package/test/fixtures/cve-samples/cve-non-java.json +0 -19
  97. package/test/fixtures/cve-samples/cve-product-only.json +0 -31
  98. package/test/fixtures/cve-samples/cve-with-packagename.json +0 -37
  99. package/test/fixtures/cve-samples/nvd-log4shell.json +0 -40
  100. package/test/fixtures/cve-samples/nvd-npm-lodash.json +0 -22
  101. package/test/fixtures/monorepo-mixed/libs/common-bom/pom.xml +0 -26
  102. package/test/fixtures/monorepo-mixed/packages/cli/package.json +0 -14
  103. package/test/fixtures/monorepo-mixed/packages/cli/yarn.lock +0 -41
  104. package/test/fixtures/monorepo-mixed/packages/no-lock/package.json +0 -10
  105. package/test/fixtures/monorepo-mixed/packages/web-app/package-lock.json +0 -71
  106. package/test/fixtures/monorepo-mixed/packages/web-app/package.json +0 -17
  107. package/test/fixtures/monorepo-mixed/pom.xml +0 -29
  108. package/test/fixtures/monorepo-mixed/services/api/pom.xml +0 -27
  109. package/test/fixtures/monorepo-mixed/services/worker/pom.xml +0 -28
  110. package/test/fixtures/php-app/composer.json +0 -5
  111. package/test/fixtures/php-app/composer.lock +0 -10
  112. package/test/fixtures/polyglot/cs/packages.lock.json +0 -1
  113. package/test/fixtures/polyglot/js/package-lock.json +0 -1
  114. package/test/fixtures/polyglot/js/package.json +0 -1
  115. package/test/fixtures/polyglot/mvn/pom.xml +0 -7
  116. package/test/fixtures/polyglot/php/composer.lock +0 -1
  117. package/test/fixtures/polyglot/py/poetry.lock +0 -3
  118. package/test/fixtures/private-lib-detection/core/pom.xml +0 -26
  119. package/test/fixtures/private-lib-detection/plugin/pom.xml +0 -23
  120. package/test/fixtures/private-lib-detection/pom.xml +0 -35
  121. package/test/fixtures/python-pipenv/Pipfile.lock +0 -1
  122. package/test/fixtures/python-poetry/poetry.lock +0 -7
  123. package/test/fixtures/python-reqs/requirements.txt +0 -5
  124. package/test/fixtures/python-uv/uv.lock +0 -3
  125. package/test/fixtures/simple/app/pom.xml +0 -28
  126. package/test/fixtures/simple/lib/pom.xml +0 -18
  127. package/test/fixtures/simple/pom.xml +0 -24
  128. package/test/maven-repo.test.js +0 -111
  129. package/test/maven-version.test.js +0 -57
  130. package/test/monorepo.test.js +0 -132
  131. package/test/npm-registry.test.js +0 -64
  132. package/test/npm.test.js +0 -150
  133. package/test/nuget.test.js +0 -66
  134. package/test/osv.test.js +0 -62
  135. package/test/outdated.test.js +0 -101
  136. package/test/pypi.test.js +0 -72
  137. package/test/snyk.test.js +0 -64
  138. package/test/transitive.test.js +0 -305
  139. package/test/webjar.test.js +0 -33
@@ -0,0 +1,748 @@
1
+ <!doctype html>
2
+ <html><head><meta charset="utf-8"><title>FAD-Checker Report</title><style>
3
+ * { box-sizing: border-box; }
4
+ body { font-family: -apple-system, "Segoe UI", Roboto, sans-serif; color: #1f2937; margin: 24px; background: #f9fafb; }
5
+ .report-header { border-bottom: 3px solid #6366f1; padding-bottom: 16px; margin-bottom: 20px; }
6
+ h1 { margin: 0 0 4px 0; font-size: 28px; letter-spacing: -.5px; }
7
+ .report-subtitle { color: #6b7280; font-size: 14px; font-weight: 500; margin-bottom: 12px; letter-spacing: .3px; }
8
+ h2 { margin: 32px 0 12px; font-size: 20px; border-bottom: 2px solid #e5e7eb; padding-bottom: 6px; }
9
+ .meta { color: #6b7280; font-size: 13px; margin-bottom: 16px; }
10
+ .summary { display: flex; flex-wrap: wrap; gap: 12px; margin: 16px 0; }
11
+ .summary .card { padding: 10px 16px; border-radius: 6px; background: #fff; border: 1px solid #e5e7eb; min-width: 120px; }
12
+ .summary .card .v { font-size: 24px; font-weight: 700; }
13
+ .summary .card .l { font-size: 11px; text-transform: uppercase; color: #6b7280; letter-spacing: .5px; }
14
+ .summary .card.sev-critical { border-left: 4px solid #dc2626; }
15
+ .summary .card.sev-critical .v { color: #dc2626; }
16
+ .summary .card.sev-high { border-left: 4px solid #f97316; }
17
+ .summary .card.sev-high .v { color: #f97316; }
18
+ .summary .card.sev-medium { border-left: 4px solid #f59e0b; }
19
+ .summary .card.sev-medium .v { color: #b45309; }
20
+ .summary .card.sev-low { border-left: 4px solid #2563eb; }
21
+ .summary .card.sev-low .v { color: #2563eb; }
22
+ .summary .card.sev-vendored { border-left: 4px solid #6366f1; }
23
+ .summary .card.sev-warn { border-left: 4px solid #f59e0b; background: #fffbeb; }
24
+ .toc { position: sticky; top: 0; z-index: 50; background: #fff; border: 1px solid #e5e7eb; border-radius: 6px; padding: 8px 12px; margin: 16px 0; display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12px; box-shadow: 0 1px 4px rgba(0,0,0,.04); }
25
+ .toc a { color: #4338ca; text-decoration: none; padding: 2px 6px; border-radius: 3px; }
26
+ .toc a:hover { background: #eef2ff; }
27
+ .exec-summary .exec-top { margin-top: 8px; padding-top: 10px; border-top: 1px dashed #e5e7eb; }
28
+ .exec-summary .exec-top-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .8px; color: #6b7280; margin-bottom: 6px; }
29
+ .exec-summary .exec-top-list { list-style: none; padding: 0; margin: 0; font-size: 12px; }
30
+ .exec-summary .exec-top-list li { display: flex; align-items: center; gap: 8px; padding: 3px 0; font-family: ui-monospace, monospace; }
31
+ .exec-summary .exec-cve-link { color: #1d4ed8; text-decoration: none; font-weight: 600; }
32
+ .exec-summary .exec-cve-link:hover { text-decoration: underline; }
33
+ .exec-summary .exec-ver { color: #6b7280; }
34
+ .exec-summary .exec-fix { color: #065f46; font-weight: 600; }
35
+ .fp-intro { background: #f3f4f6; border-left: 3px solid #6b7280; padding: 10px 14px; margin: 8px 0 16px; font-size: 12px; color: #4b5563; line-height: 1.5; }
36
+ td.prio { white-space: normal; }
37
+ td.prio .prio-band { white-space: nowrap; }
38
+ td.prio .kev-chip { display: block; margin-top: 3px; font-size: 10px; font-weight: 700; color: #7c0008; white-space: nowrap; }
39
+ td.prio .epss-chip { display: block; margin-top: 2px; font-size: 10px; color: #6b7280; font-family: ui-monospace, monospace; white-space: nowrap; }
40
+ .summary .card.sev-kev { border-left: 4px solid #7c0008; background: #fff1f2; }
41
+ .summary .card.sev-kev .v { color: #7c0008; }
42
+ .lic-group { margin: 14px 0; }
43
+ .lic-group .lic-h { font-size: 14px; margin: 8px 0 4px; padding: 4px 8px; border-radius: 4px; }
44
+ .lic-group .lic-n { font-size: 11px; color: #6b7280; font-weight: 500; }
45
+ .lic-group.lic-strong .lic-h { background: #fee2e2; color: #7c0008; }
46
+ .lic-group.lic-weak .lic-h { background: #fef3c7; color: #92400e; }
47
+ .lic-group.lic-unknown .lic-h { background: #e5e7eb; color: #374151; }
48
+ .lic-group.lic-ok .lic-h { background: #dcfce7; color: #065f46; }
49
+ td.cwe { font-family: ui-monospace, monospace; font-size: 11px; color: #4b5563; }
50
+ td.cwe .cwe-link { color: #6366f1; text-decoration: none; }
51
+ td.cwe .cwe-link:hover { text-decoration: underline; }
52
+ td.cwe .cwe-empty { color: #d1d5db; }
53
+ td.cwe .cwe-more { color: #9ca3af; font-style: italic; font-size: 10px; }
54
+ td.cwe .cwe-name { font-family: -apple-system, "Segoe UI", Roboto, sans-serif; font-size: 10px; color: #6b7280; line-height: 1.3; margin-top: 1px; max-width: 220px; }
55
+ .cwe-list { list-style: none; padding: 0; margin: 0; }
56
+ .cwe-list li { padding: 3px 0; font-size: 12px; line-height: 1.5; }
57
+ .cwe-list li .cwe-link { font-family: ui-monospace, monospace; color: #4338ca; text-decoration: none; font-weight: 600; }
58
+ .cwe-list li .cwe-link:hover { text-decoration: underline; }
59
+ .cwe-list li .cwe-name-inline { color: #374151; }
60
+ .cwe-list li .cwe-empty { color: #9ca3af; font-style: italic; }
61
+ /* CWE chip in the exec summary */
62
+ .exec-summary .exec-cwe { display: inline-flex; align-items: baseline; gap: 4px; font-size: 11px; color: #4b5563; background: #eef2ff; border: 1px solid #c7d2fe; padding: 1px 6px; border-radius: 3px; margin-left: 2px; }
63
+ .exec-summary .exec-cwe .exec-cwe-id { font-family: ui-monospace, monospace; font-weight: 600; color: #4338ca; }
64
+ .exec-summary .exec-cwe .exec-cwe-name { color: #4b5563; }
65
+ td.published { font-family: ui-monospace, monospace; font-size: 11px; color: #6b7280; white-space: nowrap; }
66
+ tr.cve-row.cpe-fp td { opacity: .55; }
67
+ .jump-badge { display: inline-block; padding: 1px 8px; border-radius: 4px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; }
68
+ .jump-badge.jump-major { background: #fee2e2; color: #991b1b; }
69
+ .jump-badge.jump-minor { background: #fef3c7; color: #92400e; }
70
+ .jump-badge.jump-patch { background: #e0f2fe; color: #075985; }
71
+ .jump-badge.jump-pre, .jump-badge.jump-unknown { background: #f3f4f6; color: #6b7280; }
72
+ tr.jump-patch td, tr.jump-pre td, tr.jump-unknown td { opacity: .75; }
73
+ tr.cve-row .cpe-tag { display: inline-block; margin-top: 2px; font-size: 9px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; background: #f3f4f6; color: #6b7280; padding: 1px 5px; border-radius: 3px; }
74
+ table { width: 100%; border-collapse: collapse; background: #fff; margin: 8px 0 24px; font-size: 13px; }
75
+ th, td { padding: 8px 10px; text-align: left; border-bottom: 1px solid #e5e7eb; vertical-align: top; }
76
+ th { background: #f3f4f6; font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: .5px; color: #4b5563; }
77
+ tr:nth-child(even) { background: #fafafa; }
78
+ td.dep { font-family: ui-monospace, monospace; font-size: 12px; }
79
+ .defined-in { margin-top: 4px; font-family: ui-monospace, monospace; font-size: 10px; color: #6b7280; line-height: 1.4; }
80
+ .defined-in .defined-label { color: #9ca3af; font-family: -apple-system, "Segoe UI", Roboto, sans-serif; text-transform: uppercase; letter-spacing: .4px; font-size: 9px; margin-right: 4px; }
81
+ .defined-in code { background: #f3f4f6; padding: 1px 4px; border-radius: 3px; color: #374151; word-break: break-all; }
82
+ code.path { font-family: ui-monospace, monospace; font-size: 0.9em; background: #f3f4f6; padding: 1px 6px; border-radius: 3px; color: #1f2937; font-weight: 400; }
83
+ .exec-summary { border: 1px solid #e5e7eb; border-radius: 8px; padding: 16px 20px; margin: 16px 0; background: #fff; display: flex; flex-direction: column; gap: 8px; }
84
+ .exec-summary .exec-head { display: flex; align-items: center; gap: 12px; }
85
+ .exec-summary .exec-level { font-size: 12px; font-weight: 700; letter-spacing: 1px; padding: 4px 12px; border-radius: 999px; }
86
+ .exec-summary .exec-title { font-size: 18px; font-weight: 600; color: #111827; }
87
+ .exec-summary .exec-copy-btn { margin-left: auto; }
88
+ .exec-summary .exec-meta { font-size: 12px; color: #6b7280; }
89
+ .exec-summary .exec-bullets { margin: 4px 0 0; padding-left: 22px; font-size: 13px; color: #374151; line-height: 1.6; }
90
+ .exec-summary.exec-critical { border-color: #dc2626; }
91
+ .exec-summary.exec-critical .exec-level { background: #dc2626; color: #fff; }
92
+ .exec-summary.exec-high { border-color: #f97316; }
93
+ .exec-summary.exec-high .exec-level { background: #f97316; color: #fff; }
94
+ .exec-summary.exec-medium { border-color: #f59e0b; }
95
+ .exec-summary.exec-medium .exec-level { background: #f59e0b; color: #fff; }
96
+ .exec-summary.exec-low { border-color: #2563eb; }
97
+ .exec-summary.exec-low .exec-level { background: #2563eb; color: #fff; }
98
+ .exec-summary.exec-info { border-color: #10b981; }
99
+ .exec-summary.exec-info .exec-level { background: #10b981; color: #fff; }
100
+ .exec-summary.exec-unknown { border-color: #6b7280; }
101
+ .exec-summary.exec-unknown .exec-level { background: #6b7280; color: #fff; }
102
+ .defined-in .defined-more { color: #9ca3af; font-style: italic; }
103
+ td.cve a { color: #1d4ed8; text-decoration: none; font-family: ui-monospace, monospace; }
104
+ td.cve a:hover { text-decoration: underline; }
105
+ td.desc { color: #4b5563; max-width: 480px; }
106
+ .empty { color: #9ca3af; font-style: italic; padding: 12px 0; }
107
+ .warnings { background: #fffbeb; border: 1px solid #fcd34d; padding: 12px 16px; border-radius: 6px; margin: 16px 0; }
108
+ .warnings h3 { margin: 0 0 10px; font-size: 14px; color: #92400e; }
109
+ .warnings .warn-block { background: #fff; border-left: 3px solid #f59e0b; padding: 8px 12px; margin: 8px 0; border-radius: 0 4px 4px 0; }
110
+ .warnings .warn-block.warn-unresolved-versions { border-left-color: #ef4444; background: #fef2f2; }
111
+ .warnings .warn-block.warn-private-libs { border-left-color: #6366f1; background: #eef2ff; }
112
+ .warnings .warn-head { font-size: 13px; color: #92400e; margin-bottom: 4px; }
113
+ .warnings .warn-unresolved-versions .warn-head { color: #991b1b; }
114
+ .warnings .warn-private-libs .warn-head { color: #312e81; }
115
+ .warnings .warn-private-libs code { background: #e0e7ff; }
116
+ .warnings .warn-defined { font-size: 10px; color: #6b7280; margin-top: 2px; padding-left: 14px; }
117
+ .warnings .warn-defined code.path { background: #f3f4f6; color: #374151; font-size: 10px; padding: 1px 4px; }
118
+ .warnings .warn-defined-more { color: #9ca3af; font-style: italic; }
119
+ .warnings .count { color: #6b7280; font-weight: 400; }
120
+ .warnings .warn-path { font-size: 11px; color: #6b7280; margin-bottom: 4px; }
121
+ .warnings .warn-msg { font-size: 12px; color: #374151; line-height: 1.45; }
122
+ .warnings .warn-items { margin: 6px 0 0; padding-left: 18px; font-size: 11px; max-height: 180px; overflow: auto; }
123
+ .warnings .warn-items li { margin-bottom: 2px; }
124
+ .warnings .warn-items .more { color: #6b7280; font-style: italic; }
125
+ .warnings code { background: #fef3c7; padding: 1px 4px; border-radius: 3px; font-size: 11px; }
126
+ .warnings .warn-unresolved-versions code { background: #fecaca; }
127
+ .confidence { font-size: 10px; color: #9ca3af; text-transform: uppercase; }
128
+ .source { display: inline-block; padding: 1px 6px; border-radius: 3px; font-size: 10px; background: #e5e7eb; color: #374151; margin: 1px 2px 1px 0; }
129
+ .source.both { background: #c7d2fe; color: #312e81; }
130
+ .source.snyk { background: #fce7f3; color: #831843; }
131
+ .source.osv { background: #dcfce7; color: #166534; }
132
+ .source.fad { background: #fef3c7; color: #92400e; }
133
+ .source.nvd { background: #cffafe; color: #155e75; }
134
+ .chip { display: inline-block; padding: 1px 6px; border-radius: 3px; font-size: 10px; margin-left: 4px; }
135
+ .chip.transitive { background: #fef3c7; color: #92400e; }
136
+ .chip.direct { background: #d1fae5; color: #065f46; }
137
+ .chip.parent { background: #ddd6fe; color: #5b21b6; }
138
+ /* Maven / npm scope qualifiers added next to .chip.direct when relevant */
139
+ .chip.scope-test { background: #fee2e2; color: #991b1b; }
140
+ .chip.scope-provided { background: #fed7aa; color: #9a3412; }
141
+ .chip.scope-runtime { background: #cffafe; color: #155e75; }
142
+ .chip.scope-system { background: #f3f4f6; color: #4b5563; }
143
+ .chip.scope-dev { background: #fee2e2; color: #991b1b; }
144
+ .chip.scope-peer { background: #ede9fe; color: #5b21b6; }
145
+ .chip.scope-optional { background: #f3f4f6; color: #6b7280; }
146
+ .chip.scope-vendored { background: #e0e7ff; color: #3730a3; }
147
+ .via { font-size: 10px; color: #6b7280; margin-top: 2px; font-family: ui-monospace, monospace; max-width: 220px; word-break: break-all; }
148
+ h3 { margin: 24px 0 10px; font-size: 16px; color: #374151; }
149
+ details.report-section { margin: 28px 0 0; }
150
+ details.report-section[open] { margin-bottom: 8px; }
151
+ details.report-section > summary { cursor: pointer; list-style: none; user-select: none; outline: none; padding: 0; }
152
+ details.report-section > summary::-webkit-details-marker { display: none; }
153
+ details.report-section > summary h2 { margin: 0; display: flex; align-items: center; gap: 8px; }
154
+ details.report-section > summary h2::before { content: "▾"; color: #6366f1; font-size: 14px; transition: transform .15s ease; display: inline-block; }
155
+ details.report-section:not([open]) > summary h2::before { transform: rotate(-90deg); }
156
+ details.report-section > summary:hover h2 { color: #4338ca; }
157
+ details.report-subsection { margin: 16px 0 0; }
158
+ details.report-subsection > summary { cursor: pointer; list-style: none; user-select: none; outline: none; padding: 0; }
159
+ details.report-subsection > summary::-webkit-details-marker { display: none; }
160
+ details.report-subsection > summary h3 { margin: 0; display: flex; align-items: center; gap: 8px; }
161
+ details.report-subsection > summary h3::before { content: "▾"; color: #9ca3af; font-size: 12px; transition: transform .15s ease; display: inline-block; }
162
+ details.report-subsection:not([open]) > summary h3::before { transform: rotate(-90deg); }
163
+ details.report-subsection > summary:hover h3 { color: #4b5563; }
164
+ /* Hierarchical indentation: every subsection's content gets a padded,
165
+ bordered container. Nested subsections inherit + add to the indent so
166
+ children visually nest under their parent. */
167
+ details.report-subsection > div { padding-left: 22px; margin-left: 6px; border-left: 2px solid #f3f4f6; padding-top: 4px; }
168
+ details.report-subsection details.report-subsection > summary h3 { font-size: 14px; color: #4b5563; }
169
+ details.report-subsection details.report-subsection details.report-subsection > summary h3 { font-size: 13px; color: #6b7280; font-weight: 500; }
170
+ details.report-subsection details.report-subsection > div { border-left-color: #e5e7eb; }
171
+ details.report-subsection details.report-subsection details.report-subsection > div { border-left-color: #d1d5db; }
172
+ .toolbar { display: flex; gap: 8px; margin: 12px 0 8px; flex-wrap: wrap; align-items: center; }
173
+ .toolbar .btn { display: inline-flex; align-items: center; gap: 4px; padding: 5px 12px; font-size: 12px; background: #fff; border: 1px solid #d1d5db; border-radius: 4px; cursor: pointer; color: #374151; font-family: inherit; }
174
+ .toolbar .btn:hover { background: #f3f4f6; border-color: #9ca3af; }
175
+ .toolbar .btn.primary { background: #4f46e5; color: #fff; border-color: #4f46e5; }
176
+ .toolbar .btn.primary:hover { background: #4338ca; }
177
+ .toolbar .toolbar-label { font-size: 11px; color: #6b7280; }
178
+ /* Table copy controls — one toolbar per table */
179
+ .table-wrap { margin: 8px 0 24px; }
180
+ .table-wrap > table { margin: 0; }
181
+ .table-actions { display: flex; justify-content: flex-end; gap: 6px; margin-bottom: 4px; }
182
+ .btn-copy { display: inline-flex; align-items: center; gap: 4px; padding: 3px 10px; font-size: 11px; background: #fff; border: 1px solid #d1d5db; border-radius: 4px; cursor: pointer; color: #4b5563; font-family: inherit; transition: all .15s ease; }
183
+ .btn-copy:hover { background: #eef2ff; border-color: #6366f1; color: #4338ca; }
184
+ .btn-copy.flashing-ok { background: #10b981; color: #fff; border-color: #10b981; }
185
+ .btn-copy.flashing-err { background: #dc2626; color: #fff; border-color: #dc2626; }
186
+ .fix-recipe { background: #fff7ed; border: 1px solid #fed7aa; border-left: 4px solid #f97316; padding: 10px 14px; border-radius: 4px; margin: 6px 0; font-size: 12px; }
187
+ .fix-recipe code { display: block; background: #1f2937; color: #f3f4f6; padding: 8px 10px; border-radius: 3px; font-size: 11px; margin-top: 6px; white-space: pre; overflow-x: auto; }
188
+ .fix-recipe .recipe-title { font-weight: 600; margin-bottom: 2px; }
189
+ .fix-recipe .recipe-meta { color: #92400e; }
190
+ td.action { font-size: 11px; max-width: 280px; }
191
+ td.action .pin { font-family: ui-monospace, monospace; background: #f3f4f6; padding: 2px 4px; border-radius: 2px; }
192
+ td.action .update-hint { color: #6b7280; font-size: 10px; margin-top: 2px; }
193
+ tr.cve-row { cursor: pointer; }
194
+ tr.cve-row:hover { background: #eef2ff !important; }
195
+ tr.cve-row.open { background: #e0e7ff !important; }
196
+ tr.cve-row td:first-child::before { content: "▸"; display: inline-block; margin-right: 6px; color: #6b7280; transition: transform .15s ease; }
197
+ tr.cve-row.open td:first-child::before { transform: rotate(90deg); color: #6366f1; }
198
+ tr.detail-row { display: none; }
199
+ tr.detail-row.open { display: table-row; }
200
+ tr.detail-row > td { padding: 0; border-bottom: 2px solid #c7d2fe; background: #f9fafb; }
201
+ .detail-panel { background: #f9fafb; border-left: 4px solid #6366f1; padding: 16px 24px; font-size: 12px; line-height: 1.6; width: 100%; }
202
+ .detail-panel .panel-block { margin: 0; padding: 10px 0; border-bottom: 1px solid #e5e7eb; }
203
+ .detail-panel .panel-block:last-child { border-bottom: none; }
204
+ .detail-panel .panel-block .panel-title { font-size: 11px; color: #6b7280; text-transform: uppercase; letter-spacing: .5px; font-weight: 600; margin-bottom: 6px; }
205
+ .detail-panel .panel-block .panel-title .count { color: #9ca3af; text-transform: none; letter-spacing: 0; font-weight: 400; margin-left: 4px; }
206
+ .detail-panel .full-desc { white-space: pre-wrap; color: #1f2937; max-width: 1100px; line-height: 1.55; }
207
+ .detail-panel .cvss-vector { font-family: ui-monospace, monospace; font-size: 11px; background: #1f2937; color: #f3f4f6; padding: 4px 8px; border-radius: 3px; display: inline-block; }
208
+ .detail-panel .ref-group { margin: 6px 0; }
209
+ .detail-panel .ref-group .ref-label { display: inline-block; font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; padding: 1px 6px; border-radius: 3px; margin-right: 4px; }
210
+ .detail-panel .ref-group .ref-label.patch { background: #d1fae5; color: #065f46; }
211
+ .detail-panel .ref-group .ref-label.exploit { background: #fee2e2; color: #991b1b; }
212
+ .detail-panel .ref-group .ref-label.advisory { background: #dbeafe; color: #1e40af; }
213
+ .detail-panel .ref-group .ref-label.vendor { background: #ede9fe; color: #5b21b6; }
214
+ .detail-panel .ref-group .ref-label.third-party { background: #fef3c7; color: #92400e; }
215
+ .detail-panel .ref-group .ref-label.mailing { background: #f3f4f6; color: #4b5563; }
216
+ .detail-panel .ref-group .ref-label.fix { background: #d1fae5; color: #065f46; }
217
+ .detail-panel .ref-group .ref-label.web { background: #f3f4f6; color: #6b7280; }
218
+ .detail-panel .ref-group .ref-label.other { background: #f3f4f6; color: #6b7280; }
219
+ .detail-panel .ref-list { margin: 4px 0 8px; padding-left: 18px; max-height: 220px; overflow-y: auto; }
220
+ .detail-panel .ref-list li { font-size: 11px; word-break: break-all; line-height: 1.6; }
221
+ .detail-panel .ref-list a { color: #1d4ed8; text-decoration: none; }
222
+ .detail-panel .ref-list a:hover { text-decoration: underline; }
223
+ .detail-panel .kv { display: flex; gap: 16px; flex-wrap: wrap; }
224
+ .detail-panel .kv > div { min-width: 200px; }
225
+ .detail-panel .kv label { display: block; font-size: 10px; color: #6b7280; text-transform: uppercase; letter-spacing: .5px; }
226
+ .detail-panel .kv span { font-family: ui-monospace, monospace; font-size: 12px; }
227
+ .detail-panel .via-list { font-family: ui-monospace, monospace; font-size: 11px; color: #4b5563; max-height: 200px; overflow-y: auto; }
228
+ .detail-panel .via-list div { padding: 2px 0; }
229
+ </style></head>
230
+ <body>
231
+ <header class="report-header">
232
+ <h1>FAD-Checker Report</h1>
233
+ <div class="report-subtitle">Multi-ecosystem dependency security audit</div>
234
+ <div class="meta">
235
+ Project: <strong>emb</strong> · <code class="path">/tmp/emb</code><br>
236
+ Generated: 2026-06-01T11:50:17.518Z · fad-checker 2.0.2 · CVE data: 2026-06-01T09:36:42.393Z
237
+ </div>
238
+ </header>
239
+ <div class="exec-summary exec-medium">
240
+ <div class="exec-head">
241
+ <span class="exec-level">MEDIUM</span>
242
+ <span class="exec-title">Executive Summary</span>
243
+ <button class="btn-copy exec-copy-btn" type="button" title="Copy the executive summary — paste it into Word with formatting preserved">📋 Copy summary</button><template class="exec-copy-rich"><div style="font-family:Calibri,Arial,sans-serif; font-size:11pt; color:#1f2937;"><p style="font-size:14pt; font-weight:bold; margin:0 0 2px;">Executive Summary — MEDIUM</p><p style="margin:0 0 8px; color:#4b5563;">3 dependencies scanned</p><ul style="margin:4px 0 0; padding-left:22px;"><li style="margin:2px 0;">2 CVE in production deps (critical=0, high=0, medium=1, low=1)</li><li style="margin:2px 0;">1 scan-completeness alert — see chapter 0</li></ul></div></template><textarea class="exec-copy-plain" aria-hidden="true" tabindex="-1" style="position:absolute;left:-9999px;top:0;width:1px;height:1px;opacity:0;">EXECUTIVE SUMMARY — MEDIUM
244
+ 3 dependencies scanned
245
+
246
+ - 2 CVE in production deps (critical=0, high=0, medium=1, low=1)
247
+ - 1 scan-completeness alert — see chapter 0</textarea>
248
+ </div>
249
+ <div class="exec-meta">3 dependencies scanned</div>
250
+ <ul class="exec-bullets">
251
+ <li><strong>2</strong> CVE in production deps (critical=0, high=0, medium=1, low=1)</li><li><strong>1</strong> scan-completeness alert — see chapter 0</li>
252
+ </ul>
253
+
254
+ </div>
255
+ <div class="summary"><div class="card sev-critical"><div class="v">0</div><div class="l">Critical</div></div><div class="card sev-high"><div class="v">0</div><div class="l">High</div></div><div class="card sev-medium"><div class="v">1</div><div class="l">Medium</div></div><div class="card sev-low"><div class="v">1</div><div class="l">Low</div></div><div class="card"><div class="v">2</div><div class="l">Total CVEs</div></div><div class="card"><div class="v">2</div><div class="l">in Direct</div></div><div class="card"><div class="v">0</div><div class="l">in Transitive</div></div><div class="card sev-vendored"><div class="v">0</div><div class="l">Vendored JS</div></div><div class="card"><div class="v">0</div><div class="l">EOL</div></div><div class="card"><div class="v">0</div><div class="l">Obsolete</div></div><div class="card"><div class="v">0</div><div class="l">Outdated</div></div><div class="card sev-warn"><div class="v">1</div><div class="l">Scan alerts</div></div></div>
256
+ <nav class="toc"><a href="#ch0">0. Warnings</a><a href="#ch1">1. Prod CVE (2)</a><a href="#ch1e">1B. Embedded (3)</a><a href="#ch2">2. Vendored JS (0)</a><a href="#ch3">3. Dev CVE (0)</a><a href="#ch4">4. EOL (0)</a><a href="#ch5">5. Obsolete (0)</a><a href="#ch6">6. Outdated (0)</a><a href="#ch7">7. Licenses (0)</a><a href="#ch8">8. Fix Recos</a></nav>
257
+ <div class="toolbar">
258
+ <button class="btn" type="button" data-action="expand-all">⊕ Expand all</button>
259
+ <button class="btn" type="button" data-action="collapse-all">⊖ Collapse all</button>
260
+ <button class="btn primary" type="button" data-action="expand-cves">↧ Expand all CVE details</button>
261
+ <button class="btn" type="button" data-action="collapse-cves">↥ Collapse all CVE details</button>
262
+ <span class="toolbar-label">Click a section header or a CVE row to toggle.</span>
263
+ </div>
264
+
265
+ <details class="report-section" open id="ch0">
266
+ <summary><h2>0. Warnings & scan-completeness (1)</h2></summary>
267
+ <div><div class="warnings warnings-chapter"><div class="warn-block warn-embedded-jar">
268
+ <div class="warn-head">⚠️ <strong>embedded-jar</strong></div>
269
+
270
+ <div class="warn-msg">embedded archive with no resolvable Maven coordinate (not scanned): dist/app.jar!/BOOT-INF/lib/mystery.jar</div>
271
+
272
+ </div></div></div>
273
+ </details>
274
+ <details class="report-section" open id="ch1">
275
+ <summary><h2>1. CVE Vulnerabilities — production (2)</h2></summary>
276
+ <div><details class="report-subsection" open>
277
+ <summary><h3>1.a Maven (2)</h3></summary>
278
+ <div><details class="report-subsection" open>
279
+ <summary><h3>1.a.0 All (2)</h3></summary>
280
+ <div><details class="report-subsection" open>
281
+ <summary><h3>All — direct (2)</h3></summary>
282
+ <div><div class="table-wrap"><div class="table-actions"><button class="btn-copy" type="button" title="Copy this table — paste it into Word with formatting preserved">📋 Copy table</button></div><table>
283
+ <thead><tr><th>Priority</th><th>Severity</th><th>CVE ID</th><th>Dependency</th><th>CWE</th><th>Published</th><th>Description</th><th>Fix Version</th><th>Source</th></tr></thead>
284
+ <tbody><tr class="cve-row">
285
+ <td class="prio"><span class="prio-band" style="display:inline-block;padding:2px 7px;border-radius:3px;background:#ca8a04;color:#fff;font-weight:700;font-size:10px;letter-spacing:.4px">MEDIUM</span></td>
286
+ <td><span style="display:inline-block;padding:2px 8px;border-radius:3px;background:#f08c00;color:#fff;font-weight:600;font-size:11px;letter-spacing:.5px">MEDIUM</span><div class="confidence">5.5</div></td>
287
+ <td class="cve"><a href="https://nvd.nist.gov/vuln/detail/CVE-2023-2976" target="_blank">CVE-2023-2976</a><div class="confidence">probable</div></td>
288
+ <td class="dep">com.google.guava:<br>guava<br><span style="color:#6b7280">30.0-jre</span> <span class="chip direct">direct</span><div class="defined-in"><span class="defined-label">defined in:</span> <code>pom.xml</code></div></td>
289
+ <td class="cwe"><span class="cwe-empty">—</span></td>
290
+ <td class="published">—</td>
291
+ <td class="desc">Use of Java's default temporary directory for file creation in `FileBackedOutputStream` in Google Guava versions 1.0 to 31.1 on Unix systems and Android Ice Cream Sandwich allows other users and apps on the machine with access to the defaul…</td>
292
+ <td class="dep">32.0.0</td>
293
+ <td><span class="source fad">fad</span></td>
294
+
295
+ </tr>
296
+ <tr class="detail-row"><td colspan="9"><div class="detail-panel"><div class="panel-block">
297
+ <div class="panel-title">Description</div>
298
+ <div><div class="full-desc">Use of Java's default temporary directory for file creation in `FileBackedOutputStream` in Google Guava versions 1.0 to 31.1 on Unix systems and Android Ice Cream Sandwich allows other users and apps on the machine with access to the default Java temporary directory to be able to access the files created by the class.
299
+
300
+ Even though the security vulnerability is fixed in version 32.0.0, we recommend…</div></div>
301
+ </div><div class="panel-block">
302
+ <div class="panel-title">Metadata</div>
303
+ <div><div class="kv"><div><label>Base score</label><span>5.5 (MEDIUM)</span></div><div><label>Priority</label><span>MEDIUM · 55/100</span></div><div><label>Fix version</label><span>32.0.0</span></div><div><label>Match confidence</label><span>probable</span></div><div><label>Sources</label><span>fad</span></div></div></div>
304
+ </div><div class="panel-block">
305
+ <div class="panel-title">Declared in <span class="count">(1 POM)</span></div>
306
+ <div><div class="via-list"><div>pom.xml</div></div></div>
307
+ </div></div></td></tr>
308
+ <tr class="cve-row">
309
+ <td class="prio"><span class="prio-band" style="display:inline-block;padding:2px 7px;border-radius:3px;background:#2563eb;color:#fff;font-weight:700;font-size:10px;letter-spacing:.4px">LOW</span></td>
310
+ <td><span style="display:inline-block;padding:2px 8px;border-radius:3px;background:#3b82f6;color:#fff;font-weight:600;font-size:11px;letter-spacing:.5px">LOW</span><div class="confidence">3.3</div></td>
311
+ <td class="cve"><a href="https://nvd.nist.gov/vuln/detail/CVE-2020-8908" target="_blank">CVE-2020-8908</a><div class="confidence">probable</div></td>
312
+ <td class="dep">com.google.guava:<br>guava<br><span style="color:#6b7280">30.0-jre</span> <span class="chip direct">direct</span><div class="defined-in"><span class="defined-label">defined in:</span> <code>pom.xml</code></div></td>
313
+ <td class="cwe"><span class="cwe-empty">—</span></td>
314
+ <td class="published">—</td>
315
+ <td class="desc">A temp directory creation vulnerability exists in all versions of Guava, allowing an attacker with access to the machine to potentially access data in a temporary directory created by the Guava API com.google.common.io.Files.createTempDir()…</td>
316
+ <td class="dep">32.0</td>
317
+ <td><span class="source fad">fad</span></td>
318
+
319
+ </tr>
320
+ <tr class="detail-row"><td colspan="9"><div class="detail-panel"><div class="panel-block">
321
+ <div class="panel-title">Description</div>
322
+ <div><div class="full-desc">A temp directory creation vulnerability exists in all versions of Guava, allowing an attacker with access to the machine to potentially access data in a temporary directory created by the Guava API com.google.common.io.Files.createTempDir(). By default, on unix-like systems, the created directory is world-readable (readable by an attacker with access to the system). The method in question has been…</div></div>
323
+ </div><div class="panel-block">
324
+ <div class="panel-title">Metadata</div>
325
+ <div><div class="kv"><div><label>Base score</label><span>3.3 (LOW)</span></div><div><label>Priority</label><span>LOW · 33/100</span></div><div><label>Fix version</label><span>32.0</span></div><div><label>Match confidence</label><span>probable</span></div><div><label>Sources</label><span>fad</span></div></div></div>
326
+ </div><div class="panel-block">
327
+ <div class="panel-title">Declared in <span class="count">(1 POM)</span></div>
328
+ <div><div class="via-list"><div>pom.xml</div></div></div>
329
+ </div></div></td></tr></tbody>
330
+ </table></div></div>
331
+ </details><details class="report-subsection" open>
332
+ <summary><h3>All — transitive (0)</h3></summary>
333
+ <div><div class="empty">No CVEs matched.</div></div>
334
+ </details></div>
335
+ </details><details class="report-subsection">
336
+ <summary><h3>By pom.xml (1 file)</h3></summary>
337
+ <div><details class="report-subsection" open>
338
+ <summary><h3><code class="path">pom.xml</code> (2)</h3></summary>
339
+ <div><div class="table-wrap"><div class="table-actions"><button class="btn-copy" type="button" title="Copy this table — paste it into Word with formatting preserved">📋 Copy table</button></div><table>
340
+ <thead><tr><th>Priority</th><th>Severity</th><th>CVE ID</th><th>Dependency</th><th>CWE</th><th>Published</th><th>Description</th><th>Fix Version</th><th>Source</th></tr></thead>
341
+ <tbody><tr class="cve-row">
342
+ <td class="prio"><span class="prio-band" style="display:inline-block;padding:2px 7px;border-radius:3px;background:#ca8a04;color:#fff;font-weight:700;font-size:10px;letter-spacing:.4px">MEDIUM</span></td>
343
+ <td><span style="display:inline-block;padding:2px 8px;border-radius:3px;background:#f08c00;color:#fff;font-weight:600;font-size:11px;letter-spacing:.5px">MEDIUM</span><div class="confidence">5.5</div></td>
344
+ <td class="cve"><a href="https://nvd.nist.gov/vuln/detail/CVE-2023-2976" target="_blank">CVE-2023-2976</a><div class="confidence">probable</div></td>
345
+ <td class="dep">com.google.guava:<br>guava<br><span style="color:#6b7280">30.0-jre</span> <span class="chip direct">direct</span><div class="defined-in"><span class="defined-label">defined in:</span> <code>pom.xml</code></div></td>
346
+ <td class="cwe"><span class="cwe-empty">—</span></td>
347
+ <td class="published">—</td>
348
+ <td class="desc">Use of Java's default temporary directory for file creation in `FileBackedOutputStream` in Google Guava versions 1.0 to 31.1 on Unix systems and Android Ice Cream Sandwich allows other users and apps on the machine with access to the defaul…</td>
349
+ <td class="dep">32.0.0</td>
350
+ <td><span class="source fad">fad</span></td>
351
+
352
+ </tr>
353
+ <tr class="detail-row"><td colspan="9"><div class="detail-panel"><div class="panel-block">
354
+ <div class="panel-title">Description</div>
355
+ <div><div class="full-desc">Use of Java's default temporary directory for file creation in `FileBackedOutputStream` in Google Guava versions 1.0 to 31.1 on Unix systems and Android Ice Cream Sandwich allows other users and apps on the machine with access to the default Java temporary directory to be able to access the files created by the class.
356
+
357
+ Even though the security vulnerability is fixed in version 32.0.0, we recommend…</div></div>
358
+ </div><div class="panel-block">
359
+ <div class="panel-title">Metadata</div>
360
+ <div><div class="kv"><div><label>Base score</label><span>5.5 (MEDIUM)</span></div><div><label>Priority</label><span>MEDIUM · 55/100</span></div><div><label>Fix version</label><span>32.0.0</span></div><div><label>Match confidence</label><span>probable</span></div><div><label>Sources</label><span>fad</span></div></div></div>
361
+ </div><div class="panel-block">
362
+ <div class="panel-title">Declared in <span class="count">(1 POM)</span></div>
363
+ <div><div class="via-list"><div>pom.xml</div></div></div>
364
+ </div></div></td></tr>
365
+ <tr class="cve-row">
366
+ <td class="prio"><span class="prio-band" style="display:inline-block;padding:2px 7px;border-radius:3px;background:#2563eb;color:#fff;font-weight:700;font-size:10px;letter-spacing:.4px">LOW</span></td>
367
+ <td><span style="display:inline-block;padding:2px 8px;border-radius:3px;background:#3b82f6;color:#fff;font-weight:600;font-size:11px;letter-spacing:.5px">LOW</span><div class="confidence">3.3</div></td>
368
+ <td class="cve"><a href="https://nvd.nist.gov/vuln/detail/CVE-2020-8908" target="_blank">CVE-2020-8908</a><div class="confidence">probable</div></td>
369
+ <td class="dep">com.google.guava:<br>guava<br><span style="color:#6b7280">30.0-jre</span> <span class="chip direct">direct</span><div class="defined-in"><span class="defined-label">defined in:</span> <code>pom.xml</code></div></td>
370
+ <td class="cwe"><span class="cwe-empty">—</span></td>
371
+ <td class="published">—</td>
372
+ <td class="desc">A temp directory creation vulnerability exists in all versions of Guava, allowing an attacker with access to the machine to potentially access data in a temporary directory created by the Guava API com.google.common.io.Files.createTempDir()…</td>
373
+ <td class="dep">32.0</td>
374
+ <td><span class="source fad">fad</span></td>
375
+
376
+ </tr>
377
+ <tr class="detail-row"><td colspan="9"><div class="detail-panel"><div class="panel-block">
378
+ <div class="panel-title">Description</div>
379
+ <div><div class="full-desc">A temp directory creation vulnerability exists in all versions of Guava, allowing an attacker with access to the machine to potentially access data in a temporary directory created by the Guava API com.google.common.io.Files.createTempDir(). By default, on unix-like systems, the created directory is world-readable (readable by an attacker with access to the system). The method in question has been…</div></div>
380
+ </div><div class="panel-block">
381
+ <div class="panel-title">Metadata</div>
382
+ <div><div class="kv"><div><label>Base score</label><span>3.3 (LOW)</span></div><div><label>Priority</label><span>LOW · 33/100</span></div><div><label>Fix version</label><span>32.0</span></div><div><label>Match confidence</label><span>probable</span></div><div><label>Sources</label><span>fad</span></div></div></div>
383
+ </div><div class="panel-block">
384
+ <div class="panel-title">Declared in <span class="count">(1 POM)</span></div>
385
+ <div><div class="via-list"><div>pom.xml</div></div></div>
386
+ </div></div></td></tr></tbody>
387
+ </table></div></div>
388
+ </details></div>
389
+ </details></div>
390
+ </details></div>
391
+ </details>
392
+ <details class="report-section" open id="ch1e">
393
+ <summary><h2>1B. Embedded binaries — JAR/WAR/EAR (3)</h2></summary>
394
+ <div><div class="fp-intro">Maven coordinates discovered inside committed <code>.jar</code>/<code>.war</code>/<code>.ear</code> binaries (vendored libs, fat-jars) — not declared in any <code>pom.xml</code>. Patch by rebuilding/replacing the containing archive.</div><div class="eco-block"><h3 class="eco-h">📦 dist/app.jar <span class="eco-count">(3)</span></h3><div class="table-wrap"><div class="table-actions"><button class="btn-copy" type="button" title="Copy this table — paste it into Word with formatting preserved">📋 Copy table</button></div><table>
395
+ <thead><tr><th>Priority</th><th>Severity</th><th>CVE ID</th><th>Dependency</th><th>CWE</th><th>Published</th><th>Description</th><th>Fix Version</th><th>Source</th></tr></thead>
396
+ <tbody><tr class="cve-row">
397
+ <td class="prio"><span class="prio-band" style="display:inline-block;padding:2px 7px;border-radius:3px;background:#ca8a04;color:#fff;font-weight:700;font-size:10px;letter-spacing:.4px">MEDIUM</span></td>
398
+ <td><span style="display:inline-block;padding:2px 8px;border-radius:3px;background:#f08c00;color:#fff;font-weight:600;font-size:11px;letter-spacing:.5px">MEDIUM</span><div class="confidence">6.3</div></td>
399
+ <td class="cve"><a href="https://nvd.nist.gov/vuln/detail/CVE-2025-68161" target="_blank">CVE-2025-68161</a><div class="confidence">exact</div></td>
400
+ <td class="dep">org.apache.logging.log4j:<br>log4j-core<br><span style="color:#6b7280">2.14.0</span> <span class="chip direct">direct</span><div class="defined-in"><span class="defined-label">defined in:</span> <code>dist/app.jar!/BOOT-INF/lib/log4j-core-2.14.0.jar</code></div></td>
401
+ <td class="cwe"><span class="cwe-empty">—</span></td>
402
+ <td class="published">—</td>
403
+ <td class="desc">The Socket Appender in Apache Log4j Core versions 2.0-beta9 through 2.25.2 does not perform TLS hostname verification of the peer certificate, even when the verifyHostName https://logging.apache.org/log4j/2.x/manual/appenders/network.html#…</td>
404
+ <td class="dep">2.25.3</td>
405
+ <td><span class="source fad">fad</span></td>
406
+
407
+ </tr>
408
+ <tr class="detail-row"><td colspan="9"><div class="detail-panel"><div class="panel-block">
409
+ <div class="panel-title">Description</div>
410
+ <div><div class="full-desc">The Socket Appender in Apache Log4j Core versions 2.0-beta9 through 2.25.2 does not perform TLS hostname verification of the peer certificate, even when the verifyHostName https://logging.apache.org/log4j/2.x/manual/appenders/network.html#SslConfiguration-attr-verifyHostName configuration attribute or the log4j2.sslVerifyHostName https://logging.apache.org/log4j/2.x/manual/systemproperties.html…</div></div>
411
+ </div><div class="panel-block">
412
+ <div class="panel-title">Metadata</div>
413
+ <div><div class="kv"><div><label>Base score</label><span>6.3 (MEDIUM)</span></div><div><label>Priority</label><span>MEDIUM · 63/100</span></div><div><label>Fix version</label><span>2.25.3</span></div><div><label>Match confidence</label><span>exact</span></div><div><label>Sources</label><span>fad</span></div></div></div>
414
+ </div><div class="panel-block">
415
+ <div class="panel-title">Declared in <span class="count">(1 POM)</span></div>
416
+ <div><div class="via-list"><div>dist/app.jar!/BOOT-INF/lib/log4j-core-2.14.0.jar</div></div></div>
417
+ </div></div></td></tr>
418
+ <tr class="cve-row">
419
+ <td class="prio"><span class="prio-band" style="display:inline-block;padding:2px 7px;border-radius:3px;background:#ca8a04;color:#fff;font-weight:700;font-size:10px;letter-spacing:.4px">MEDIUM</span><div class="epss-chip" title="EPSS score 0.0%">EPSS 11%</div></td>
420
+ <td><span style="display:inline-block;padding:2px 8px;border-radius:3px;background:#f08c00;color:#fff;font-weight:600;font-size:11px;letter-spacing:.5px">MEDIUM</span><div class="confidence">6.9</div></td>
421
+ <td class="cve"><a href="https://nvd.nist.gov/vuln/detail/CVE-2026-34480" target="_blank">CVE-2026-34480</a><div class="confidence">exact</div></td>
422
+ <td class="dep">org.apache.logging.log4j:<br>log4j-core<br><span style="color:#6b7280">2.14.0</span> <span class="chip direct">direct</span><div class="defined-in"><span class="defined-label">defined in:</span> <code>dist/app.jar!/BOOT-INF/lib/log4j-core-2.14.0.jar</code></div></td>
423
+ <td class="cwe"><a href="https://cwe.mitre.org/data/definitions/116.html" target="_blank" rel="noopener" class="cwe-link" title="CWE-116: Improper Encoding or Escaping of Output">CWE-116</a><div class="cwe-name">Improper Encoding or Escaping of Output</div></td>
424
+ <td class="published">2026-04-10</td>
425
+ <td class="desc">Apache Log4j Core's XmlLayout https://logging.apache.org/log4j/2.x/manual/layouts.html#XmlLayout , in versions up to and including 2.25.3, fails to sanitize characters forbidden by the XML 1.0 specification https://www.w3.org/TR/xml/#char…</td>
426
+ <td class="dep">2.25.4</td>
427
+ <td><span class="source fad">fad</span><span class="source nvd">nvd</span></td>
428
+
429
+ </tr>
430
+ <tr class="detail-row"><td colspan="9"><div class="detail-panel"><div class="panel-block">
431
+ <div class="panel-title">Description</div>
432
+ <div><div class="full-desc">Apache Log4j Core's XmlLayout https://logging.apache.org/log4j/2.x/manual/layouts.html#XmlLayout , in versions up to and including 2.25.3, fails to sanitize characters forbidden by the XML 1.0 specification https://www.w3.org/TR/xml/#charsets producing invalid XML output whenever a log message or MDC value contains such characters.
433
+
434
+ The impact depends on the StAX implementation in use:
435
+
436
+ * JRE built-in StAX: Forbidden characters are silently written to the output, producing malformed XML. Conforming parsers must reject such documents with a fatal error, which may cause downstream log-processing systems to drop the affected records.
437
+ * Alternative StAX implementations (e.g., Woodstox https://github.com/FasterXML/woodstox , a transitive dependency of the Jackson XML Dataformat module): An exception is thrown during the logging call, and the log event is never delivered to its intended appender, only to Log4j's internal status logger.
438
+
439
+
440
+ Users are advised to upgrade to Apache Log4j Core 2.25.4, which corrects this issue by sanitizing forbidden characters before XML output.</div></div>
441
+ </div><div class="panel-block">
442
+ <div class="panel-title">Weaknesses (CWE) <span class="count">(1)</span></div>
443
+ <div><ul class="cwe-list"><li>
444
+ <a href="https://cwe.mitre.org/data/definitions/116.html" target="_blank" rel="noopener" class="cwe-link">CWE-116</a>
445
+ <span class="cwe-name-inline">— Improper Encoding or Escaping of Output</span>
446
+ </li></ul></div>
447
+ </div><div class="panel-block">
448
+ <div class="panel-title">Metadata</div>
449
+ <div><div class="kv"><div><label>CVSS:V40</label><span class="cvss-vector">CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X</span></div><div><label>Base score</label><span>6.9 (MEDIUM)</span></div><div><label>Priority</label><span>MEDIUM · 57.3/100</span></div><div><label>EPSS</label><span>0.0% prob · 11th pct</span></div><div><label>Fix version</label><span>2.25.4</span></div><div><label>Published</label><span>2026-04-10</span></div><div><label>Modified</label><span>2026-04-24</span></div><div><label>Match confidence</label><span>exact</span></div><div><label>Sources</label><span>fad+nvd</span></div></div></div>
450
+ </div><div class="panel-block">
451
+ <div class="panel-title">External links <span class="count">(6)</span></div>
452
+ <div><div class="ref-group">
453
+ <span class="ref-label patch">Patch / Commit</span><span style="color:#9ca3af;font-size:11px">1 link</span>
454
+ <ul class="ref-list"><li><a href="https://github.com/apache/logging-log4j2/pull/4077" target="_blank">https://github.com/apache/logging-log4j2/pull/4077</a></li></ul>
455
+ </div><div class="ref-group">
456
+ <span class="ref-label vendor">Vendor advisory</span><span style="color:#9ca3af;font-size:11px">2 links</span>
457
+ <ul class="ref-list"><li><a href="https://lists.apache.org/thread/5x0hcnng0chhghp6jgjdp3qmbbhfjzhb" target="_blank">https://lists.apache.org/thread/5x0hcnng0chhghp6jgjdp3qmbbhfjzhb</a></li><li><a href="https://logging.apache.org/security.html#CVE-2026-34480" target="_blank">https://logging.apache.org/security.html#CVE-2026-34480</a></li></ul>
458
+ </div><div class="ref-group">
459
+ <span class="ref-label third-party">Third-party advisory</span><span style="color:#9ca3af;font-size:11px">1 link</span>
460
+ <ul class="ref-list"><li><a href="http://www.openwall.com/lists/oss-security/2026/04/10/9" target="_blank">http://www.openwall.com/lists/oss-security/2026/04/10/9</a></li></ul>
461
+ </div><div class="ref-group">
462
+ <span class="ref-label web">Other</span><span style="color:#9ca3af;font-size:11px">2 links</span>
463
+ <ul class="ref-list"><li><a href="https://logging.apache.org/cyclonedx/vdr.xml" target="_blank">https://logging.apache.org/cyclonedx/vdr.xml</a></li><li><a href="https://logging.apache.org/log4j/2.x/manual/layouts.html#XmlLayout" target="_blank">https://logging.apache.org/log4j/2.x/manual/layouts.html#XmlLayout</a></li></ul>
464
+ </div></div>
465
+ </div><div class="panel-block">
466
+ <div class="panel-title">Affected CPE configurations <span class="count">(7)</span></div>
467
+ <div><ul class="ref-list"><li>cpe:2.3:a:apache:log4j:*:*:*:*:*:*:*:*</li><li>cpe:2.3:a:apache:log4j:3.0.0:alpha1:*:*:*:*:*:*</li><li>cpe:2.3:a:apache:log4j:3.0.0:alpha1_rc1:*:*:*:*:*:*</li><li>cpe:2.3:a:apache:log4j:3.0.0:alpha1_rc2:*:*:*:*:*:*</li><li>cpe:2.3:a:apache:log4j:3.0.0:beta1:*:*:*:*:*:*</li><li>cpe:2.3:a:apache:log4j:3.0.0:beta2:*:*:*:*:*:*</li><li>cpe:2.3:a:apache:log4j:3.0.0:beta3:*:*:*:*:*:*</li></ul></div>
468
+ </div><div class="panel-block">
469
+ <div class="panel-title">Declared in <span class="count">(1 POM)</span></div>
470
+ <div><div class="via-list"><div>dist/app.jar!/BOOT-INF/lib/log4j-core-2.14.0.jar</div></div></div>
471
+ </div></div></td></tr>
472
+ <tr class="cve-row">
473
+ <td class="prio"><span class="prio-band" style="display:inline-block;padding:2px 7px;border-radius:3px;background:#ca8a04;color:#fff;font-weight:700;font-size:10px;letter-spacing:.4px">MEDIUM</span><div class="epss-chip" title="EPSS score 0.0%">EPSS 12%</div></td>
474
+ <td><span style="display:inline-block;padding:2px 8px;border-radius:3px;background:#f08c00;color:#fff;font-weight:600;font-size:11px;letter-spacing:.5px">MEDIUM</span><div class="confidence">6.3</div></td>
475
+ <td class="cve"><a href="https://nvd.nist.gov/vuln/detail/CVE-2026-34477" target="_blank">CVE-2026-34477</a><div class="confidence">exact</div></td>
476
+ <td class="dep">org.apache.logging.log4j:<br>log4j-core<br><span style="color:#6b7280">2.14.0</span> <span class="chip direct">direct</span><div class="defined-in"><span class="defined-label">defined in:</span> <code>dist/app.jar!/BOOT-INF/lib/log4j-core-2.14.0.jar</code></div></td>
477
+ <td class="cwe"><a href="https://cwe.mitre.org/data/definitions/297.html" target="_blank" rel="noopener" class="cwe-link" title="CWE-297: Improper Validation of Certificate with Host Mismatch">CWE-297</a><div class="cwe-name">Improper Validation of Certificate with Host Mismatch</div> <a href="https://cwe.mitre.org/data/definitions/295.html" target="_blank" rel="noopener" class="cwe-link" title="CWE-295: Improper Certificate Validation">CWE-295</a><div class="cwe-name">Improper Certificate Validation</div></td>
478
+ <td class="published">2026-04-10</td>
479
+ <td class="desc">The fix for CVE-2025-68161 https://logging.apache.org/security.html#CVE-2025-68161 was incomplete: it addressed hostname verification only when enabled via the log4j2.sslVerifyHostName https://logging.apache.org/log4j/2.x/manual/systempr…</td>
480
+ <td class="dep">2.25.4</td>
481
+ <td><span class="source fad">fad</span><span class="source nvd">nvd</span></td>
482
+
483
+ </tr>
484
+ <tr class="detail-row"><td colspan="9"><div class="detail-panel"><div class="panel-block">
485
+ <div class="panel-title">Description</div>
486
+ <div><div class="full-desc">The fix for CVE-2025-68161 https://logging.apache.org/security.html#CVE-2025-68161 was incomplete: it addressed hostname verification only when enabled via the log4j2.sslVerifyHostName https://logging.apache.org/log4j/2.x/manual/systemproperties.html#log4j2.sslVerifyHostName system property, but not when configured through the verifyHostName https://logging.apache.org/log4j/2.x/manual/appenders/network.html#SslConfiguration-attr-verifyHostName attribute of the &lt;Ssl&gt; element.
487
+
488
+ Although the verifyHostName configuration attribute was introduced in Log4j Core 2.12.0, it was silently ignored in all versions through 2.25.3, leaving TLS connections vulnerable to interception regardless of the configured value.
489
+
490
+ A network-based attacker may be able to perform a man-in-the-middle attack when all of the following conditions are met:
491
+
492
+ * An SMTP, Socket, or Syslog appender is in use.
493
+ * TLS is configured via a nested &lt;Ssl&gt; element.
494
+ * The attacker can present a certificate issued by a CA trusted by the appender's configured trust store, or by the default Java trust store if none is configured.
495
+ This issue does not affect users of the HTTP appender, which uses a separate verifyHostname https://logging.apache.org/log4j/2.x/manual/appenders/network.html#HttpAppender-attr-verifyHostName attribute that was not subject to this bug and verifies host names by default.
496
+
497
+ Users are advised to upgrade to Apache Log4j Core 2.25.4, which corrects this issue.</div></div>
498
+ </div><div class="panel-block">
499
+ <div class="panel-title">Weaknesses (CWE) <span class="count">(2)</span></div>
500
+ <div><ul class="cwe-list"><li>
501
+ <a href="https://cwe.mitre.org/data/definitions/297.html" target="_blank" rel="noopener" class="cwe-link">CWE-297</a>
502
+ <span class="cwe-name-inline">— Improper Validation of Certificate with Host Mismatch</span>
503
+ </li><li>
504
+ <a href="https://cwe.mitre.org/data/definitions/295.html" target="_blank" rel="noopener" class="cwe-link">CWE-295</a>
505
+ <span class="cwe-name-inline">— Improper Certificate Validation</span>
506
+ </li></ul></div>
507
+ </div><div class="panel-block">
508
+ <div class="panel-title">Metadata</div>
509
+ <div><div class="kv"><div><label>CVSS:V40</label><span class="cvss-vector">CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X</span></div><div><label>Base score</label><span>6.3 (MEDIUM)</span></div><div><label>Priority</label><span>MEDIUM · 52.8/100</span></div><div><label>EPSS</label><span>0.0% prob · 12th pct</span></div><div><label>Fix version</label><span>2.25.4</span></div><div><label>Published</label><span>2026-04-10</span></div><div><label>Modified</label><span>2026-05-06</span></div><div><label>Match confidence</label><span>exact</span></div><div><label>Sources</label><span>fad+nvd</span></div></div></div>
510
+ </div><div class="panel-block">
511
+ <div class="panel-title">External links <span class="count">(5)</span></div>
512
+ <div><div class="ref-group">
513
+ <span class="ref-label patch">Patch / Commit</span><span style="color:#9ca3af;font-size:11px">1 link</span>
514
+ <ul class="ref-list"><li><a href="https://github.com/apache/logging-log4j2/pull/4075" target="_blank">https://github.com/apache/logging-log4j2/pull/4075</a></li></ul>
515
+ </div><div class="ref-group">
516
+ <span class="ref-label vendor">Vendor advisory</span><span style="color:#9ca3af;font-size:11px">2 links</span>
517
+ <ul class="ref-list"><li><a href="https://logging.apache.org/cyclonedx/vdr.xml" target="_blank">https://logging.apache.org/cyclonedx/vdr.xml</a></li><li><a href="https://logging.apache.org/security.html#CVE-2026-34477" target="_blank">https://logging.apache.org/security.html#CVE-2026-34477</a></li></ul>
518
+ </div><div class="ref-group">
519
+ <span class="ref-label mailing">Mailing list</span><span style="color:#9ca3af;font-size:11px">1 link</span>
520
+ <ul class="ref-list"><li><a href="https://lists.apache.org/thread/lkx8cl46t2bvkcwfcb2pd43ygc097lq4" target="_blank">https://lists.apache.org/thread/lkx8cl46t2bvkcwfcb2pd43ygc097lq4</a></li></ul>
521
+ </div><div class="ref-group">
522
+ <span class="ref-label web">Other</span><span style="color:#9ca3af;font-size:11px">1 link</span>
523
+ <ul class="ref-list"><li><a href="https://logging.apache.org/log4j/2.x/manual/appenders/network.html#SslConfiguration-attr-verifyHostName" target="_blank">https://logging.apache.org/log4j/2.x/manual/appenders/network.html#SslConfiguration-attr-verifyHostName</a></li></ul>
524
+ </div></div>
525
+ </div><div class="panel-block">
526
+ <div class="panel-title">Affected CPE configurations <span class="count">(7)</span></div>
527
+ <div><ul class="ref-list"><li>cpe:2.3:a:apache:log4j:*:*:*:*:*:*:*:*</li><li>cpe:2.3:a:apache:log4j:3.0.0:alpha1:*:*:*:*:*:*</li><li>cpe:2.3:a:apache:log4j:3.0.0:alpha1_rc1:*:*:*:*:*:*</li><li>cpe:2.3:a:apache:log4j:3.0.0:alpha1_rc2:*:*:*:*:*:*</li><li>cpe:2.3:a:apache:log4j:3.0.0:beta1:*:*:*:*:*:*</li><li>cpe:2.3:a:apache:log4j:3.0.0:beta2:*:*:*:*:*:*</li><li>cpe:2.3:a:apache:log4j:3.0.0:beta3:*:*:*:*:*:*</li></ul></div>
528
+ </div><div class="panel-block">
529
+ <div class="panel-title">Declared in <span class="count">(1 POM)</span></div>
530
+ <div><div class="via-list"><div>dist/app.jar!/BOOT-INF/lib/log4j-core-2.14.0.jar</div></div></div>
531
+ </div></div></td></tr></tbody>
532
+ </table></div></div></div>
533
+ </details>
534
+ <details class="report-section" id="ch2">
535
+ <summary><h2>2. Vendored JS scan — retire.js (0)</h2></summary>
536
+ <div><div class="empty">No vulnerable vendored JavaScript files detected (or retire.js was skipped).</div></div>
537
+ </details>
538
+ <details class="report-section" id="ch3">
539
+ <summary><h2>3. CVE in dev dependencies (0)</h2></summary>
540
+ <div><div class="empty">No CVE matches.</div></div>
541
+ </details>
542
+ <details class="report-section" open id="ch4">
543
+ <summary><h2>4. End-of-Life Frameworks (0)</h2></summary>
544
+ <div><div class="empty">No end-of-life frameworks detected.</div></div>
545
+ </details>
546
+ <details class="report-section" open id="ch5">
547
+ <summary><h2>5. Obsolete / Deprecated Libraries (0)</h2></summary>
548
+ <div><div class="empty">No obsolete / deprecated libraries detected.</div></div>
549
+ </details>
550
+ <details class="report-section" open id="ch6">
551
+ <summary><h2>6. Outdated Libraries (0)</h2></summary>
552
+ <div><div class="empty">No outdated libraries (or --allLibs not set).</div></div>
553
+ </details>
554
+ <details class="report-section" id="ch7">
555
+ <summary><h2>7. Licenses (0)</h2></summary>
556
+ <div><div class="empty">No license data resolved (offline, or registries returned none).</div></div>
557
+ </details>
558
+ <details class="report-section" id="ch8">
559
+ <summary><h2>8. Fix Recommendations</h2></summary>
560
+ <div><details class="report-subsection" open>
561
+ <summary><h3>7.0 Direct deps to update (1)</h3></summary>
562
+ <div><div class="fp-intro">Every direct dep with at least one CVE matched. The "Pin to ≥" column shows the highest fix-version declared across the CVEs for that dep. When that's missing, the dep needs a manual triage (no clean fix is published).</div><div class="table-wrap"><div class="table-actions"><button class="btn-copy" type="button" title="Copy this table — paste it into Word with formatting preserved">📋 Copy table</button></div><table>
563
+ <thead><tr><th>Worst sev</th><th>Direct dependency</th><th>Current</th><th>Pin to ≥</th><th>Maven Central latest</th><th>CVEs covered</th></tr></thead>
564
+ <tbody><tr>
565
+ <td><span style="display:inline-block;padding:2px 8px;border-radius:3px;background:#f08c00;color:#fff;font-weight:600;font-size:11px;letter-spacing:.5px">MEDIUM</span></td>
566
+ <td class="dep">com.google.guava:guava</td>
567
+ <td class="dep">30.0-jre</td>
568
+ <td class="dep"><span style="color:#065f46;font-weight:600">32.0.0</span></td>
569
+ <td class="dep"><span style="color:#9ca3af">—</span></td>
570
+ <td class="confidence">2 CVE: CVE-2023-2976, CVE-2020-8908</td>
571
+ </tr></tbody>
572
+ </table></div></div>
573
+ </details></div>
574
+ </details>
575
+
576
+
577
+ <script>
578
+ (function(){
579
+ function isInteractive(el){
580
+ if(!el) return false;
581
+ var t = el.tagName;
582
+ return t === 'A' || t === 'BUTTON' || t === 'INPUT' || t === 'SUMMARY' || t === 'DETAILS' || t === 'LABEL';
583
+ }
584
+ // CVE row click → toggle its detail panel
585
+ document.querySelectorAll('tr.cve-row').forEach(function(row){
586
+ row.addEventListener('click', function(e){
587
+ var t = e.target;
588
+ while(t && t !== row){
589
+ if(isInteractive(t)) return;
590
+ t = t.parentNode;
591
+ }
592
+ var next = row.nextElementSibling;
593
+ if(next && next.classList.contains('detail-row')){
594
+ var nowOpen = next.classList.toggle('open');
595
+ row.classList.toggle('open', nowOpen);
596
+ }
597
+ });
598
+ });
599
+ // Toolbar buttons
600
+ document.querySelectorAll('.toolbar .btn').forEach(function(btn){
601
+ btn.addEventListener('click', function(){
602
+ var action = btn.getAttribute('data-action');
603
+ if(action === 'expand-all'){
604
+ document.querySelectorAll('details').forEach(function(d){ d.open = true; });
605
+ document.querySelectorAll('tr.cve-row').forEach(function(r){
606
+ r.classList.add('open');
607
+ var n = r.nextElementSibling;
608
+ if(n && n.classList.contains('detail-row')) n.classList.add('open');
609
+ });
610
+ } else if(action === 'collapse-all'){
611
+ document.querySelectorAll('details').forEach(function(d){ d.open = false; });
612
+ document.querySelectorAll('tr.cve-row.open').forEach(function(r){ r.classList.remove('open'); });
613
+ document.querySelectorAll('tr.detail-row.open').forEach(function(r){ r.classList.remove('open'); });
614
+ } else if(action === 'expand-cves'){
615
+ document.querySelectorAll('tr.cve-row').forEach(function(r){
616
+ r.classList.add('open');
617
+ var n = r.nextElementSibling;
618
+ if(n && n.classList.contains('detail-row')) n.classList.add('open');
619
+ });
620
+ } else if(action === 'collapse-cves'){
621
+ document.querySelectorAll('tr.cve-row.open').forEach(function(r){ r.classList.remove('open'); });
622
+ document.querySelectorAll('tr.detail-row.open').forEach(function(r){ r.classList.remove('open'); });
623
+ }
624
+ });
625
+ });
626
+ })();
627
+ </script>
628
+ <script>
629
+ (function(){
630
+ // Inline styles applied to clipboard-bound table so it survives pasting into
631
+ // Word with reasonable formatting (Word ignores most external CSS classes,
632
+ // but honours inline style="…" attributes).
633
+ function inlineStylesForWord(table){
634
+ var clone = table.cloneNode(true);
635
+ // Drop expandable detail rows (they would paste as huge empty cells)
636
+ clone.querySelectorAll('tr.detail-row').forEach(function(r){ r.remove(); });
637
+ // Strip our interactive classes so Word doesn't try to interpret them
638
+ clone.querySelectorAll('tr.cve-row').forEach(function(r){
639
+ r.classList.remove('cve-row');
640
+ r.classList.remove('open');
641
+ r.classList.remove('cpe-fp');
642
+ });
643
+ clone.setAttribute('border', '1');
644
+ clone.setAttribute('cellspacing', '0');
645
+ clone.setAttribute('cellpadding', '6');
646
+ clone.setAttribute('width', '100%');
647
+ clone.setAttribute('style', 'width:100%; border-collapse:collapse; font-family:Calibri,Arial,sans-serif; font-size:10pt; color:#1f2937;');
648
+ clone.querySelectorAll('th').forEach(function(th){
649
+ th.setAttribute('style', 'background:#f3f4f6; padding:6px 8px; border:1px solid #d1d5db; text-align:left; font-weight:bold; font-size:9pt; text-transform:uppercase; letter-spacing:.5px; color:#4b5563;');
650
+ });
651
+ clone.querySelectorAll('td').forEach(function(td){
652
+ var prev = td.getAttribute('style') || '';
653
+ td.setAttribute('style', 'padding:6px 8px; border:1px solid #e5e7eb; vertical-align:top; ' + prev);
654
+ });
655
+ // Replace severity badges with plain coloured text so they survive paste
656
+ clone.querySelectorAll('span[style*="border-radius"]').forEach(function(s){
657
+ var m = (s.getAttribute('style') || '').match(/background:\s*(#[0-9a-fA-F]{3,6})/);
658
+ var bg = m ? m[1] : '#666';
659
+ s.setAttribute('style', 'background:' + bg + '; color:#fff; padding:2px 6px; font-weight:bold; font-size:9pt;');
660
+ });
661
+ return clone;
662
+ }
663
+ function wordWrapper(tableHtml){
664
+ return '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-html40"><head><meta charset="utf-8"></head><body>' + tableHtml + '</body></html>';
665
+ }
666
+ function tableToTsv(table){
667
+ var rows = Array.prototype.filter.call(table.querySelectorAll('tr'), function(r){ return !r.classList.contains('detail-row'); });
668
+ return rows.map(function(r){
669
+ return Array.prototype.map.call(r.querySelectorAll('th, td'), function(c){
670
+ return (c.innerText || c.textContent || '').replace(/[\t\r\n]+/g, ' ').trim();
671
+ }).join('\t');
672
+ }).join('\n');
673
+ }
674
+ function flash(btn, cls, msg){
675
+ var old = btn.textContent;
676
+ btn.textContent = msg;
677
+ btn.classList.add(cls);
678
+ setTimeout(function(){
679
+ btn.textContent = old;
680
+ btn.classList.remove(cls);
681
+ }, 1500);
682
+ }
683
+ // Write rich HTML (+ plain-text fallback) to the clipboard. Shared by the
684
+ // table buttons and the executive-summary button. richInner is the HTML
685
+ // fragment; we wrap it with the Office namespaces so Word keeps formatting.
686
+ async function writeClipboard(richInner, plain, btn){
687
+ var html = wordWrapper(richInner);
688
+ // Modern path: ClipboardItem with text/html + text/plain
689
+ try {
690
+ if (window.ClipboardItem && navigator.clipboard && navigator.clipboard.write) {
691
+ await navigator.clipboard.write([
692
+ new ClipboardItem({
693
+ 'text/html': new Blob([html], { type: 'text/html' }),
694
+ 'text/plain': new Blob([plain], { type: 'text/plain' })
695
+ })
696
+ ]);
697
+ flash(btn, 'flashing-ok', '✓ Copied!');
698
+ return;
699
+ }
700
+ } catch(e) { /* fall through to legacy path */ }
701
+ // Legacy path: select a contenteditable clone, execCommand('copy')
702
+ try {
703
+ var temp = document.createElement('div');
704
+ temp.setAttribute('contenteditable', 'true');
705
+ temp.style.position = 'fixed';
706
+ temp.style.left = '-9999px';
707
+ temp.style.top = '0';
708
+ temp.innerHTML = richInner;
709
+ document.body.appendChild(temp);
710
+ var range = document.createRange();
711
+ range.selectNodeContents(temp);
712
+ var sel = window.getSelection();
713
+ sel.removeAllRanges();
714
+ sel.addRange(range);
715
+ var ok = document.execCommand('copy');
716
+ sel.removeAllRanges();
717
+ document.body.removeChild(temp);
718
+ flash(btn, ok ? 'flashing-ok' : 'flashing-err', ok ? '✓ Copied!' : '✗ Copy failed');
719
+ } catch(e) {
720
+ flash(btn, 'flashing-err', '✗ Copy failed');
721
+ }
722
+ }
723
+ function copyTable(table, btn){
724
+ var clone = inlineStylesForWord(table);
725
+ return writeClipboard(clone.outerHTML, tableToTsv(table), btn);
726
+ }
727
+ document.querySelectorAll('.btn-copy').forEach(function(btn){
728
+ // The executive-summary button is wired separately (it copies a prose
729
+ // summary, not a table).
730
+ if (btn.classList.contains('exec-copy-btn')) return;
731
+ btn.addEventListener('click', function(e){
732
+ e.stopPropagation();
733
+ var wrap = btn.closest('.table-wrap');
734
+ var table = wrap && wrap.querySelector('table');
735
+ if (table) copyTable(table, btn);
736
+ });
737
+ });
738
+ var execBtn = document.querySelector('.exec-copy-btn');
739
+ if (execBtn) execBtn.addEventListener('click', function(e){
740
+ e.stopPropagation();
741
+ var tpl = document.querySelector('.exec-copy-rich');
742
+ var ta = document.querySelector('.exec-copy-plain');
743
+ var rich = tpl ? (tpl.innerHTML || '') : '';
744
+ var plain = ta ? (ta.value || '') : '';
745
+ writeClipboard(rich, plain, execBtn);
746
+ });
747
+ })();
748
+ </script></body></html>