@blamejs/exceptd-skills 0.14.27 → 0.15.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.
@@ -1507,6 +1507,7 @@
1507
1507
  "CVE-2024-7694",
1508
1508
  "CVE-2024-8068",
1509
1509
  "CVE-2024-8069",
1510
+ "CVE-2025-0282",
1510
1511
  "CVE-2025-10035",
1511
1512
  "CVE-2025-10585",
1512
1513
  "CVE-2025-11371",
@@ -1529,6 +1530,7 @@
1529
1530
  "CVE-2025-21043",
1530
1531
  "CVE-2025-21479",
1531
1532
  "CVE-2025-21480",
1533
+ "CVE-2025-22457",
1532
1534
  "CVE-2025-23254",
1533
1535
  "CVE-2025-24016",
1534
1536
  "CVE-2025-24201",
@@ -1549,7 +1551,9 @@
1549
1551
  "CVE-2025-30202",
1550
1552
  "CVE-2025-30397",
1551
1553
  "CVE-2025-31125",
1554
+ "CVE-2025-31161",
1552
1555
  "CVE-2025-31277",
1556
+ "CVE-2025-31324",
1553
1557
  "CVE-2025-32432",
1554
1558
  "CVE-2025-32433",
1555
1559
  "CVE-2025-32434",
@@ -2645,6 +2649,7 @@
2645
2649
  "CVE-2024-7694",
2646
2650
  "CVE-2024-8068",
2647
2651
  "CVE-2024-8069",
2652
+ "CVE-2025-0282",
2648
2653
  "CVE-2025-10035",
2649
2654
  "CVE-2025-10164",
2650
2655
  "CVE-2025-10585",
@@ -2669,6 +2674,7 @@
2669
2674
  "CVE-2025-21043",
2670
2675
  "CVE-2025-21479",
2671
2676
  "CVE-2025-21480",
2677
+ "CVE-2025-22457",
2672
2678
  "CVE-2025-23254",
2673
2679
  "CVE-2025-23266",
2674
2680
  "CVE-2025-24016",
@@ -2690,7 +2696,9 @@
2690
2696
  "CVE-2025-30202",
2691
2697
  "CVE-2025-30397",
2692
2698
  "CVE-2025-31125",
2699
+ "CVE-2025-31161",
2693
2700
  "CVE-2025-31277",
2701
+ "CVE-2025-31324",
2694
2702
  "CVE-2025-32432",
2695
2703
  "CVE-2025-32433",
2696
2704
  "CVE-2025-32434",
@@ -3404,6 +3412,10 @@
3404
3412
  "evidence_cves": [
3405
3413
  "CVE-2023-3519",
3406
3414
  "CVE-2024-21762",
3415
+ "CVE-2025-0282",
3416
+ "CVE-2025-22457",
3417
+ "CVE-2025-31161",
3418
+ "CVE-2025-31324",
3407
3419
  "CVE-2025-43300",
3408
3420
  "CVE-2025-49844",
3409
3421
  "CVE-2026-31431"
@@ -5206,16 +5218,20 @@
5206
5218
  "CVE-2024-5565",
5207
5219
  "CVE-2024-6587",
5208
5220
  "CVE-2024-9526",
5221
+ "CVE-2025-0282",
5209
5222
  "CVE-2025-10164",
5210
5223
  "CVE-2025-1550",
5211
5224
  "CVE-2025-1753",
5212
5225
  "CVE-2025-1796",
5226
+ "CVE-2025-22457",
5213
5227
  "CVE-2025-23254",
5214
5228
  "CVE-2025-23266",
5215
5229
  "CVE-2025-25297",
5216
5230
  "CVE-2025-27520",
5217
5231
  "CVE-2025-30165",
5218
5232
  "CVE-2025-30202",
5233
+ "CVE-2025-31161",
5234
+ "CVE-2025-31324",
5219
5235
  "CVE-2025-32434",
5220
5236
  "CVE-2025-32444",
5221
5237
  "CVE-2025-3248",
@@ -5825,15 +5841,19 @@
5825
5841
  "CVE-2024-50050",
5826
5842
  "CVE-2024-5565",
5827
5843
  "CVE-2024-9526",
5844
+ "CVE-2025-0282",
5828
5845
  "CVE-2025-10164",
5829
5846
  "CVE-2025-1550",
5830
5847
  "CVE-2025-1753",
5848
+ "CVE-2025-22457",
5831
5849
  "CVE-2025-23254",
5832
5850
  "CVE-2025-23266",
5833
5851
  "CVE-2025-25297",
5834
5852
  "CVE-2025-27520",
5835
5853
  "CVE-2025-30165",
5836
5854
  "CVE-2025-30202",
5855
+ "CVE-2025-31161",
5856
+ "CVE-2025-31324",
5837
5857
  "CVE-2025-32434",
5838
5858
  "CVE-2025-32444",
5839
5859
  "CVE-2025-3248",
@@ -5954,16 +5974,20 @@
5954
5974
  "CVE-2024-5565",
5955
5975
  "CVE-2024-6587",
5956
5976
  "CVE-2024-9526",
5977
+ "CVE-2025-0282",
5957
5978
  "CVE-2025-10164",
5958
5979
  "CVE-2025-1550",
5959
5980
  "CVE-2025-1753",
5960
5981
  "CVE-2025-1796",
5982
+ "CVE-2025-22457",
5961
5983
  "CVE-2025-23254",
5962
5984
  "CVE-2025-23266",
5963
5985
  "CVE-2025-25297",
5964
5986
  "CVE-2025-27520",
5965
5987
  "CVE-2025-30165",
5966
5988
  "CVE-2025-30202",
5989
+ "CVE-2025-31161",
5990
+ "CVE-2025-31324",
5967
5991
  "CVE-2025-32434",
5968
5992
  "CVE-2025-32444",
5969
5993
  "CVE-2025-3248",
@@ -6438,8 +6462,12 @@
6438
6462
  "CVE-2024-12450",
6439
6463
  "CVE-2024-21762",
6440
6464
  "CVE-2024-31462",
6465
+ "CVE-2025-0282",
6441
6466
  "CVE-2025-10164",
6467
+ "CVE-2025-22457",
6442
6468
  "CVE-2025-25297",
6469
+ "CVE-2025-31161",
6470
+ "CVE-2025-31324",
6443
6471
  "CVE-2025-51480",
6444
6472
  "CVE-2025-56520",
6445
6473
  "CVE-2025-68668",
@@ -17,7 +17,7 @@
17
17
  "rebuild_after_days": 365,
18
18
  "note": "Per-entry last_verified governs decay. Skills depending on this catalog must check entry freshness before high-stakes use."
19
19
  },
20
- "entry_count": 68
20
+ "entry_count": 422
21
21
  },
22
22
  "CVE-2026-31431": {
23
23
  "name": "Copy Fail",
@@ -17957,5 +17957,285 @@
17957
17957
  "ai_discovery_source": "human_researcher",
17958
17958
  "ai_discovery_date": "2026-05-19",
17959
17959
  "ai_assist_factor": "none"
17960
+ },
17961
+ "CVE-2025-0282": {
17962
+ "name": "Ivanti Connect Secure stack-overflow preauth RCE (SPAWN ecosystem)",
17963
+ "lesson_date": "2026-05-28",
17964
+ "attack_vector": {
17965
+ "description": "Unauthenticated stack-based buffer overflow in Ivanti Connect Secure reachable over the network. Exploited as a zero-day from mid-December 2024 by the suspected China-nexus cluster UNC5337/UNC5221, deploying the SPAWN malware ecosystem (SPAWNANT/SPAWNMOLE/SPAWNSNAIL), the PHASEJAM dropper, and the DRYHOOK credential stealer, before the 2025-01-08 advisory. Patch-in-place is insufficient where the appliance is already compromised.",
17966
+ "privileges_required": "none (unauthenticated network reach to an internet-facing Connect Secure appliance)",
17967
+ "complexity": "high to weaponize reliably (AC:H), but functioning exploitation was in-the-wild at disclosure and mass-scanning followed",
17968
+ "ai_factor": "Not AI-discovered — vendor/Mandiant incident investigation. No AI involvement documented."
17969
+ },
17970
+ "defense_chain": {
17971
+ "prevention": {
17972
+ "what_would_have_worked": "Upgrade to Connect Secure 22.7R2.5 (Policy Secure 22.7R1.2, Neurons for ZTA 22.7R2.3) under a perimeter-device compressed-SLA tier (NEW-CTRL-030), and restrict the appliance management/web surface to known operator ranges where the tenancy model permits.",
17973
+ "was_this_required": true,
17974
+ "framework_requiring_it": "CISA BOD 22-01 (KEV remediation, added 2025-01-08)",
17975
+ "adequacy": "Patch fixes the overflow but does not evict SPAWN-ecosystem persistence; on any Integrity Checker Tool indicator the device must be factory-reset and rebuilt (NEW-CTRL-032 perimeter-compromise-rebuild-not-patch), not upgraded in place."
17976
+ },
17977
+ "detection": {
17978
+ "what_would_have_worked": "Ivanti Integrity Checker Tool (ICT) scans; alerting on appliance outbound connections to non-management destinations; file-integrity baselining for SPAWN artifacts.",
17979
+ "was_this_required": false,
17980
+ "framework_requiring_it": null,
17981
+ "adequacy": "ICT is necessary to distinguish patch-sufficient from rebuild-required; detection alone does not remediate a confirmed preauth RCE under active exploitation."
17982
+ },
17983
+ "response": {
17984
+ "what_would_have_worked": "Treat any internet-facing Connect Secure exposed before 2025-01-08 as potentially compromised; factory-reset/rebuild on ICT indicators; rotate all appliance and downstream credentials (admin, VPN-user, RADIUS, LDAP bind).",
17985
+ "was_this_required": false,
17986
+ "framework_requiring_it": null,
17987
+ "adequacy": "Operationally expensive but necessary; patch-in-place left SPAWN persistence on compromised devices."
17988
+ }
17989
+ },
17990
+ "framework_coverage": {
17991
+ "NIST-800-53-SI-2": {
17992
+ "covered": true,
17993
+ "adequate": false,
17994
+ "gap": "30-day patch SLA is orders of magnitude longer than the observed exploitation window (zero-day, in-wild weeks before disclosure). Reboot-required firmware breaks the maintenance-window assumption and patch-in-place is insufficient on compromised appliances."
17995
+ },
17996
+ "ISO-27001-2022-A.8.8": {
17997
+ "covered": true,
17998
+ "adequate": false,
17999
+ "gap": "Appropriate timescales undefined; the standard 30-day interpretation is unsafe for an unauthenticated preauth flaw on an internet-facing device/server with public exploitation."
18000
+ },
18001
+ "NIS2-Art21-network-security": {
18002
+ "covered": true,
18003
+ "adequate": false,
18004
+ "gap": "Treats this class as essential-function infrastructure but lacks a CISA-KEV-style compressed remediation SLA."
18005
+ },
18006
+ "DORA-Art-9": {
18007
+ "covered": true,
18008
+ "adequate": false,
18009
+ "gap": "ICT incident management presumes vendor-patch cadence; the exposure window opened inside the financial-entity SLA."
18010
+ },
18011
+ "UK-CAF-B4": {
18012
+ "covered": true,
18013
+ "adequate": false,
18014
+ "gap": "Silent on the reality that a patched device can still carry attacker persistence seeded before the patch; cleanup/rebuild verification is required."
18015
+ },
18016
+ "AU-ISM-1546": {
18017
+ "covered": true,
18018
+ "adequate": false,
18019
+ "gap": "Essential 8 ML3 (48h) is closer to reality than NIST SI-2 but still misses the mass-scanning window for this internet-facing class."
18020
+ }
18021
+ },
18022
+ "compliance_exposure_score": {
18023
+ "percent_audit_passing_orgs_still_exposed": 65,
18024
+ "basis": "Internet-facing VPN concentrators are routinely run by audited orgs without a documented compressed-SLA patch-and-rebuild procedure; the standard 30-day SLA and patch-in-place habit were active exposure for a zero-day with nation-state and later ransomware use.",
18025
+ "theater_pattern": "patch_management"
18026
+ },
18027
+ "ai_discovered_zeroday": false,
18028
+ "ai_discovery_source": "vendor_research",
18029
+ "ai_assist_factor": "none"
18030
+ },
18031
+ "CVE-2025-22457": {
18032
+ "name": "Ivanti Connect Secure stack-overflow preauth RCE (mis-triaged DoS weaponized to RCE)",
18033
+ "lesson_date": "2026-05-28",
18034
+ "attack_vector": {
18035
+ "description": "Unauthenticated stack-based buffer overflow in Ivanti Connect Secure initially assessed as a low-risk DoS and patched in 22.7R2.6 (2025-02-11), then weaponized to RCE and exploited in the wild from mid-March 2025 by UNC5221 using the TRAILBLAZE in-memory dropper and BRUSHFIRE passive backdoor. Fleets that deprioritized the fix on the basis of its initial DoS rating were exploited after the patch shipped.",
18036
+ "privileges_required": "none (unauthenticated network reach to an internet-facing Connect Secure appliance)",
18037
+ "complexity": "high to weaponize (AC:H); the public RCE understanding lagged the patch, extending effective exposure",
18038
+ "ai_factor": "Not AI-discovered — vendor/Mandiant incident investigation. No AI involvement documented."
18039
+ },
18040
+ "defense_chain": {
18041
+ "prevention": {
18042
+ "what_would_have_worked": "Upgrade to Connect Secure 22.7R2.6 (Policy Secure 22.7R1.4, ZTA Gateways 22.8R2.2). Critically: prioritize internet-facing-appliance patches by exposure class (NEW-CTRL-030), not solely by the initially-published CVSS — a DoS-rated flaw on a preauth perimeter surface must be treated as latent-RCE until proven otherwise.",
18043
+ "was_this_required": true,
18044
+ "framework_requiring_it": "CISA BOD 22-01 (KEV remediation, added 2025-04-04)",
18045
+ "adequacy": "Patch is definitive once applied, but SLA models keyed on initial CVSS under-protected fleets; rebuild required on compromise indicators (NEW-CTRL-032)."
18046
+ },
18047
+ "detection": {
18048
+ "what_would_have_worked": "ICT scans; alerting on TRAILBLAZE/BRUSHFIRE artifacts and anomalous appliance egress.",
18049
+ "was_this_required": false,
18050
+ "framework_requiring_it": null,
18051
+ "adequacy": "Necessary to catch exploitation of fleets that delayed the low-rated patch."
18052
+ },
18053
+ "response": {
18054
+ "what_would_have_worked": "Factory-reset/rebuild on compromise indicators; rotate appliance and downstream credentials; re-baseline patch prioritization to flag preauth-perimeter DoS flaws for accelerated remediation.",
18055
+ "was_this_required": false,
18056
+ "framework_requiring_it": null,
18057
+ "adequacy": "Standard appliance-compromise response; the durable lesson is severity mis-triage of a perimeter preauth flaw."
18058
+ }
18059
+ },
18060
+ "framework_coverage": {
18061
+ "NIST-800-53-SI-2": {
18062
+ "covered": true,
18063
+ "adequate": false,
18064
+ "gap": "A flaw patched as low-risk DoS was weaponized to RCE; CVSS-keyed SLA prioritization left fleets unpatched against the real critical risk. The 30-day window far exceeds the weaponization-to-mass-exploitation interval, and reboot-required firmware breaks the maintenance-window assumption."
18065
+ },
18066
+ "ISO-27001-2022-A.8.8": {
18067
+ "covered": true,
18068
+ "adequate": false,
18069
+ "gap": "Appropriate timescales undefined; the standard 30-day interpretation is unsafe for an unauthenticated preauth flaw on an internet-facing device/server with public exploitation."
18070
+ },
18071
+ "NIS2-Art21-network-security": {
18072
+ "covered": true,
18073
+ "adequate": false,
18074
+ "gap": "Treats this class as essential-function infrastructure but lacks a CISA-KEV-style compressed remediation SLA."
18075
+ },
18076
+ "DORA-Art-9": {
18077
+ "covered": true,
18078
+ "adequate": false,
18079
+ "gap": "ICT incident management presumes vendor-patch cadence; the exposure window opened inside the financial-entity SLA."
18080
+ },
18081
+ "UK-CAF-B4": {
18082
+ "covered": true,
18083
+ "adequate": false,
18084
+ "gap": "Silent on the reality that a patched device can still carry attacker persistence seeded before the patch; cleanup/rebuild verification is required."
18085
+ },
18086
+ "AU-ISM-1546": {
18087
+ "covered": true,
18088
+ "adequate": false,
18089
+ "gap": "Essential 8 ML3 (48h) is closer to reality than NIST SI-2 but still misses the mass-scanning window for this internet-facing class."
18090
+ }
18091
+ },
18092
+ "compliance_exposure_score": {
18093
+ "percent_audit_passing_orgs_still_exposed": 70,
18094
+ "basis": "CVSS-keyed patch SLAs are near-universal; a perimeter preauth flaw mis-rated as DoS is exactly the case where that model fails, and most audited orgs had no exposure-class override.",
18095
+ "theater_pattern": "patch_management"
18096
+ },
18097
+ "ai_discovered_zeroday": false,
18098
+ "ai_discovery_source": "vendor_research",
18099
+ "ai_assist_factor": "none"
18100
+ },
18101
+ "CVE-2025-31324": {
18102
+ "name": "SAP NetWeaver Visual Composer Metadata Uploader unauthenticated file-upload RCE",
18103
+ "lesson_date": "2026-05-28",
18104
+ "attack_vector": {
18105
+ "description": "The Visual Composer Metadata Uploader endpoint (/developmentserver/metadatauploader) lacks an authorization check, letting an unauthenticated attacker upload a JSP webshell that runs with SAP service privileges. Mass-exploited from April 2025; frequently chained with the NetWeaver deserialization flaw CVE-2025-42999, with webshell access leading to hands-on-keyboard follow-on including ransomware staging.",
18106
+ "privileges_required": "none (unauthenticated POST to an internet-facing NetWeaver server with Visual Composer enabled)",
18107
+ "complexity": "low — single unauthenticated request; webshell IOCs widely published",
18108
+ "ai_factor": "Not AI-discovered — identified during incident investigation (ReliaQuest). No AI involvement documented."
18109
+ },
18110
+ "defense_chain": {
18111
+ "prevention": {
18112
+ "what_would_have_worked": "Apply SAP Security Note 3594142 promptly under an internet-facing-application compressed SLA (NEW-CTRL-030); where patching is delayed, block /developmentserver/metadatauploader at the proxy and disable Visual Composer if unused.",
18113
+ "was_this_required": true,
18114
+ "framework_requiring_it": "CISA BOD 22-01 (KEV remediation, added 2025-04-29)",
18115
+ "adequacy": "Patch closes the upload path, but patch-in-place without webshell hunting leaves attacker-dropped JSP shells resident — cleanup is a required, separate step."
18116
+ },
18117
+ "detection": {
18118
+ "what_would_have_worked": "Alerting on unauthenticated POSTs to /developmentserver/metadatauploader; file-integrity monitoring of the servlet_jsp/irj root for new JSP files (helper.jsp, cache.jsp, random names); SAP service account spawning shells.",
18119
+ "was_this_required": false,
18120
+ "framework_requiring_it": null,
18121
+ "adequacy": "Webshell detection is necessary to catch resident persistence after patching."
18122
+ },
18123
+ "response": {
18124
+ "what_would_have_worked": "Hunt for and remove JSP webshells under the servlet root; assume service-account credential compromise and rotate; review for the chained CVE-2025-42999 deserialization activity.",
18125
+ "was_this_required": false,
18126
+ "framework_requiring_it": null,
18127
+ "adequacy": "Necessary; many operators patched without removing the resident webshells."
18128
+ }
18129
+ },
18130
+ "framework_coverage": {
18131
+ "NIST-800-53-SI-2": {
18132
+ "covered": true,
18133
+ "adequate": false,
18134
+ "gap": "CVSS 10.0 unauthenticated file-upload RCE on an internet-facing ERP application server; the 30-day patch SLA far exceeds the days-scale mass-exploitation window, and webshell persistence means patch-in-place leaves the attacker resident."
18135
+ },
18136
+ "ISO-27001-2022-A.8.8": {
18137
+ "covered": true,
18138
+ "adequate": false,
18139
+ "gap": "Appropriate timescales undefined; the standard 30-day interpretation is unsafe for an unauthenticated preauth flaw on an internet-facing device/server with public exploitation."
18140
+ },
18141
+ "NIS2-Art21-network-security": {
18142
+ "covered": true,
18143
+ "adequate": false,
18144
+ "gap": "Treats this class as essential-function infrastructure but lacks a CISA-KEV-style compressed remediation SLA."
18145
+ },
18146
+ "DORA-Art-9": {
18147
+ "covered": true,
18148
+ "adequate": false,
18149
+ "gap": "ICT incident management presumes vendor-patch cadence; the exposure window opened inside the financial-entity SLA."
18150
+ },
18151
+ "UK-CAF-B4": {
18152
+ "covered": true,
18153
+ "adequate": false,
18154
+ "gap": "Silent on the reality that a patched device can still carry attacker persistence seeded before the patch; cleanup/rebuild verification is required."
18155
+ },
18156
+ "AU-ISM-1546": {
18157
+ "covered": true,
18158
+ "adequate": false,
18159
+ "gap": "Essential 8 ML3 (48h) is closer to reality than NIST SI-2 but still misses the mass-scanning window for this internet-facing class."
18160
+ }
18161
+ },
18162
+ "compliance_exposure_score": {
18163
+ "percent_audit_passing_orgs_still_exposed": 75,
18164
+ "basis": "SAP NetWeaver estates are business-critical and change-controlled, so emergency patching of an internet-facing component routinely loses to change windows; webshell hunting after patch is rarely part of the documented procedure.",
18165
+ "theater_pattern": "patch_management"
18166
+ },
18167
+ "ai_discovered_zeroday": false,
18168
+ "ai_discovery_source": "vendor_research",
18169
+ "ai_assist_factor": "none"
18170
+ },
18171
+ "CVE-2025-31161": {
18172
+ "name": "CrushFTP HTTP authorization-header authentication bypass (crushadmin takeover)",
18173
+ "lesson_date": "2026-05-28",
18174
+ "attack_vector": {
18175
+ "description": "A crafted HTTP Authorization header bypasses authentication and assumes any known/guessable account, including crushadmin, granting administrative control of the file-transfer server (unless fronted by a DMZ proxy instance). Exploited in the wild March-April 2025. The managed-file-transfer class is a proven ransomware/data-extortion initial-access vector (MOVEit lineage).",
18176
+ "privileges_required": "none (unauthenticated network reach to an internet-facing CrushFTP instance without a DMZ proxy)",
18177
+ "complexity": "low — single crafted request; public exploitation details",
18178
+ "ai_factor": "Not AI-discovered — reported by Outpost24. No AI involvement documented."
18179
+ },
18180
+ "defense_chain": {
18181
+ "prevention": {
18182
+ "what_would_have_worked": "Upgrade to CrushFTP 10.8.4 / 11.3.1 under an internet-facing-service compressed SLA (NEW-CTRL-030); deploy the DMZ proxy instance as a structural mitigation that breaks the direct auth path.",
18183
+ "was_this_required": true,
18184
+ "framework_requiring_it": "CISA BOD 22-01 (KEV remediation, added 2025-04-07)",
18185
+ "adequacy": "Patch is definitive; the DMZ-proxy mode is an architecture-level control that mitigated even pre-patch. Most exposed instances ran without it."
18186
+ },
18187
+ "detection": {
18188
+ "what_would_have_worked": "Alerting on unexpected crushadmin logins or newly-created admin accounts; anomalous Authorization headers preceding admin access; egress from the file server to remote-management infrastructure.",
18189
+ "was_this_required": false,
18190
+ "framework_requiring_it": null,
18191
+ "adequacy": "Necessary to catch the account takeover; the MFT class is a high-value ransomware target."
18192
+ },
18193
+ "response": {
18194
+ "what_would_have_worked": "Audit for unauthorized admin sessions/accounts; rotate credentials; review transferred-file access logs for data exfiltration given the MFT data-extortion pattern.",
18195
+ "was_this_required": false,
18196
+ "framework_requiring_it": null,
18197
+ "adequacy": "Necessary; the extortion risk is the stored/transited data, not just server control."
18198
+ }
18199
+ },
18200
+ "framework_coverage": {
18201
+ "NIST-800-53-SI-2": {
18202
+ "covered": true,
18203
+ "adequate": false,
18204
+ "gap": "Unauthenticated admin takeover on an internet-facing managed-file-transfer server — a proven ransomware/data-extortion vector. The 30-day patch SLA is exploitation acceptance; the exposure window opened within days of public details."
18205
+ },
18206
+ "ISO-27001-2022-A.8.8": {
18207
+ "covered": true,
18208
+ "adequate": false,
18209
+ "gap": "Appropriate timescales undefined; the standard 30-day interpretation is unsafe for an unauthenticated preauth flaw on an internet-facing device/server with public exploitation."
18210
+ },
18211
+ "NIS2-Art21-network-security": {
18212
+ "covered": true,
18213
+ "adequate": false,
18214
+ "gap": "Treats this class as essential-function infrastructure but lacks a CISA-KEV-style compressed remediation SLA."
18215
+ },
18216
+ "DORA-Art-9": {
18217
+ "covered": true,
18218
+ "adequate": false,
18219
+ "gap": "ICT incident management presumes vendor-patch cadence; the exposure window opened inside the financial-entity SLA."
18220
+ },
18221
+ "UK-CAF-B4": {
18222
+ "covered": true,
18223
+ "adequate": false,
18224
+ "gap": "Silent on the reality that a patched device can still carry attacker persistence seeded before the patch; cleanup/rebuild verification is required."
18225
+ },
18226
+ "AU-ISM-1546": {
18227
+ "covered": true,
18228
+ "adequate": false,
18229
+ "gap": "Essential 8 ML3 (48h) is closer to reality than NIST SI-2 but still misses the mass-scanning window for this internet-facing class."
18230
+ }
18231
+ },
18232
+ "compliance_exposure_score": {
18233
+ "percent_audit_passing_orgs_still_exposed": 68,
18234
+ "basis": "MFT servers are internet-facing by function and hold high-value data; audited orgs routinely run them without a compressed-SLA procedure or the structural DMZ-proxy mitigation, and the MOVEit precedent shows the class is a primary extortion target.",
18235
+ "theater_pattern": "patch_management"
18236
+ },
18237
+ "ai_discovered_zeroday": false,
18238
+ "ai_discovery_source": "vendor_research",
18239
+ "ai_assist_factor": "none"
17960
18240
  }
17961
18241
  }
@@ -158,8 +158,14 @@ function temporalStalenessFindings(loaded, opts = {}) {
158
158
  }
159
159
 
160
160
  // CISA KEV due-date passed without remediation status — surfaces
161
- // operationally-stale entries the operator should re-verify.
162
- if (e.cisa_kev === true && typeof e.cisa_kev_due_date === "string") {
161
+ // operationally-stale CURATED entries the operator should re-verify.
162
+ // Auto-imported drafts are excluded: a KEV due-date passing with wall-clock
163
+ // time on the un-curated bulk-import backlog is expected (and grows the
164
+ // count purely by calendar drift, which would mechanically breach the
165
+ // budget gate on a no-op release). The finding is actionable only once the
166
+ // entry is curated, so it is scoped to non-draft entries.
167
+ const isDraft = e._auto_imported === true || e._draft === true;
168
+ if (!isDraft && e.cisa_kev === true && typeof e.cisa_kev_due_date === "string") {
163
169
  const sinceDue = daysSince(e.cisa_kev_due_date, now);
164
170
  if (sinceDue !== null && sinceDue > 0) {
165
171
  out.push({ class: "temporal-staleness", catalog: "cve-catalog", id,
@@ -119,7 +119,7 @@ const KEBAB_RE = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
119
119
  const JSON_FILENAME_RE = /^[A-Za-z0-9._-]+\.json$/;
120
120
 
121
121
  function parseArgs(argv) {
122
- const opts = { skill: null, quiet: false };
122
+ const opts = { skill: null, quiet: false, strict: false };
123
123
  for (let i = 2; i < argv.length; i++) {
124
124
  const a = argv[i];
125
125
  if (a === '--skill') {
@@ -128,6 +128,11 @@ function parseArgs(argv) {
128
128
  opts.skill = a.slice('--skill='.length);
129
129
  } else if (a === '--quiet' || a === '-q') {
130
130
  opts.quiet = true;
131
+ } else if (a === '--strict') {
132
+ // Promote warnings (header-only sections, unresolved draft refs,
133
+ // playbook air-gap gaps) to release-blocking failures. Used by the
134
+ // predeploy gate so a warned regression cannot scroll past.
135
+ opts.strict = true;
131
136
  } else if (a === '--help' || a === '-h') {
132
137
  printHelp();
133
138
  process.exit(0);
@@ -856,7 +861,13 @@ function main() {
856
861
  console.log(
857
862
  `\n${passed}/${total} skills passed${warnSummary}${failed ? `, ${failed} failed` : ''}${orphanSummary}${airGapSummary}.`,
858
863
  );
859
- process.exit(failed === 0 && orphans.length === 0 ? 0 : 1);
864
+ // --strict treats any warning (per-skill or playbook air-gap) as a
865
+ // release-blocking failure so a warned regression cannot ship silently.
866
+ const strictFail = opts.strict && (warned > 0 || (airGapWarnings && airGapWarnings.length > 0));
867
+ if (strictFail) {
868
+ console.log(`[lint-skills] --strict: ${warned + (airGapWarnings ? airGapWarnings.length : 0)} warning(s) treated as failures.`);
869
+ }
870
+ process.exit(failed === 0 && orphans.length === 0 && !strictFail ? 0 : 1);
860
871
  }
861
872
 
862
873
  // Export the minimal frontmatter parser for downstream consumers
@@ -2912,8 +2912,6 @@ function buildEvidenceBundle(format, playbook, analyze, validate, agentSignals,
2912
2912
  rwep_adjusted: analyze.rwep?.adjusted || 0,
2913
2913
  rwep_threshold_escalate: analyze.rwep?.threshold?.escalate || null,
2914
2914
  blast_radius_score: analyze.blast_radius_score || 0,
2915
- feeds_into: null, // populated by close()
2916
- jurisdiction_clocks_active: null, // populated by close()
2917
2915
  remediation_recommended: validate.selected_remediation?.id || null,
2918
2916
  }
2919
2917
  };
@@ -272,6 +272,21 @@ function additionalChecks(key, entry, ctx) {
272
272
  }
273
273
  }
274
274
 
275
+ // V5 — KEV status must carry its date (AGENTS.md Hard Rule #1: a KEV flag
276
+ // without a date is an incomplete threat-intel claim; RWEP scoring and the
277
+ // jurisdiction-clock SLAs key off the KEV listing date). cisa_kev=true with a
278
+ // null/missing/invalid cisa_kev_date is flagged; promoted to a hard error
279
+ // under --strict (predeploy). 0 violations in the shipped catalog today.
280
+ if (entry.cisa_kev === true) {
281
+ const d = entry.cisa_kev_date;
282
+ const dateOk = typeof d === 'string' && isUsableDate(d).ok;
283
+ if (!dateOk) {
284
+ warnings.push(
285
+ `${key}: cisa_kev=true but cisa_kev_date is ${JSON.stringify(d)} (KEV status must carry a valid listing date — Hard Rule #1)`,
286
+ );
287
+ }
288
+ }
289
+
275
290
  // V4 — Impossible-date guard.
276
291
  for (const f of DATE_FIELDS) {
277
292
  const v = entry[f];
@@ -352,18 +367,26 @@ function main() {
352
367
  }
353
368
  }
354
369
 
355
- // Guard the hand-maintained framework-control-gaps _meta.entry_count against
356
- // silent drift (it declared 184 while the file held 192 — 8 entries were
357
- // added without bumping the counter, and nothing caught it). Assert the
358
- // declared count equals the actual non-_meta entry count.
359
- if (frameworks && frameworks._meta && typeof frameworks._meta.entry_count === 'number') {
360
- const actualGapCount = Object.keys(frameworks).filter((k) => !k.startsWith('_')).length;
361
- if (frameworks._meta.entry_count !== actualGapCount) {
362
- process.stderr.write(
363
- `[validate-cve-catalog] FAIL: framework-control-gaps _meta.entry_count (${frameworks._meta.entry_count}) ` +
364
- `!= actual entry count (${actualGapCount}). Update _meta.entry_count to ${actualGapCount}.\n`,
365
- );
366
- process.exit(1);
370
+ // Guard hand-maintained _meta.entry_count fields against silent drift. The
371
+ // framework-control-gaps counter once declared 184 while the file held 192
372
+ // and nothing caught it; the zeroday-lessons counter drifted to 68 while the
373
+ // file held 422 because only framework-control-gaps was gated. This now
374
+ // checks EVERY loaded catalog that declares a numeric _meta.entry_count, so a
375
+ // new catalog with the field is covered automatically.
376
+ const ENTRY_COUNT_CATALOGS = [
377
+ { name: 'framework-control-gaps', catalog: frameworks },
378
+ { name: 'zeroday-lessons', catalog: lessons },
379
+ ];
380
+ for (const { name, catalog: cat } of ENTRY_COUNT_CATALOGS) {
381
+ if (cat && cat._meta && typeof cat._meta.entry_count === 'number') {
382
+ const actual = Object.keys(cat).filter((k) => !k.startsWith('_')).length;
383
+ if (cat._meta.entry_count !== actual) {
384
+ process.stderr.write(
385
+ `[validate-cve-catalog] FAIL: ${name} _meta.entry_count (${cat._meta.entry_count}) ` +
386
+ `!= actual entry count (${actual}). Update _meta.entry_count to ${actual}.\n`,
387
+ );
388
+ process.exit(1);
389
+ }
367
390
  }
368
391
  }
369
392