regscale-cli 6.16.1.0__py3-none-any.whl → 6.16.3.0__py3-none-any.whl

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.

Potentially problematic release.


This version of regscale-cli might be problematic. Click here for more details.

Files changed (46) hide show
  1. regscale/__init__.py +1 -1
  2. regscale/core/app/internal/login.py +1 -1
  3. regscale/core/app/internal/poam_editor.py +1 -1
  4. regscale/core/app/utils/api_handler.py +4 -11
  5. regscale/integrations/commercial/__init__.py +2 -2
  6. regscale/integrations/commercial/ad.py +1 -1
  7. regscale/integrations/commercial/crowdstrike.py +0 -1
  8. regscale/integrations/commercial/grype/__init__.py +3 -0
  9. regscale/integrations/commercial/grype/commands.py +72 -0
  10. regscale/integrations/commercial/grype/scanner.py +390 -0
  11. regscale/integrations/commercial/import_all/import_all_cmd.py +2 -2
  12. regscale/integrations/commercial/opentext/__init__.py +6 -0
  13. regscale/integrations/commercial/opentext/commands.py +77 -0
  14. regscale/integrations/commercial/opentext/scanner.py +449 -85
  15. regscale/integrations/commercial/qualys.py +50 -61
  16. regscale/integrations/commercial/servicenow.py +1 -0
  17. regscale/integrations/commercial/snyk.py +2 -2
  18. regscale/integrations/commercial/synqly/ticketing.py +29 -0
  19. regscale/integrations/commercial/trivy/__init__.py +5 -0
  20. regscale/integrations/commercial/trivy/commands.py +74 -0
  21. regscale/integrations/commercial/trivy/scanner.py +276 -0
  22. regscale/integrations/commercial/veracode.py +1 -1
  23. regscale/integrations/commercial/wizv2/utils.py +1 -1
  24. regscale/integrations/jsonl_scanner_integration.py +869 -0
  25. regscale/integrations/public/fedramp/fedramp_common.py +4 -4
  26. regscale/integrations/public/fedramp/inventory_items.py +3 -3
  27. regscale/integrations/scanner_integration.py +225 -59
  28. regscale/models/integration_models/cisa_kev_data.json +65 -7
  29. regscale/models/integration_models/{flat_file_importer.py → flat_file_importer/__init__.py} +29 -8
  30. regscale/models/integration_models/snyk.py +141 -15
  31. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  32. regscale/models/integration_models/tenable_models/integration.py +42 -7
  33. regscale/models/integration_models/veracode.py +91 -48
  34. regscale/models/regscale_models/regscale_model.py +1 -1
  35. regscale/models/regscale_models/user.py +3 -4
  36. regscale/models/regscale_models/vulnerability.py +21 -0
  37. regscale/utils/version.py +3 -5
  38. {regscale_cli-6.16.1.0.dist-info → regscale_cli-6.16.3.0.dist-info}/METADATA +3 -3
  39. {regscale_cli-6.16.1.0.dist-info → regscale_cli-6.16.3.0.dist-info}/RECORD +43 -38
  40. regscale/integrations/commercial/grype.py +0 -165
  41. regscale/integrations/commercial/opentext/click.py +0 -99
  42. regscale/integrations/commercial/trivy.py +0 -162
  43. {regscale_cli-6.16.1.0.dist-info → regscale_cli-6.16.3.0.dist-info}/LICENSE +0 -0
  44. {regscale_cli-6.16.1.0.dist-info → regscale_cli-6.16.3.0.dist-info}/WHEEL +0 -0
  45. {regscale_cli-6.16.1.0.dist-info → regscale_cli-6.16.3.0.dist-info}/entry_points.txt +0 -0
  46. {regscale_cli-6.16.1.0.dist-info → regscale_cli-6.16.3.0.dist-info}/top_level.txt +0 -0
@@ -1878,11 +1878,11 @@ def check_control_list_length(ssp_obj: SSP, mapping: dict) -> Optional[list]:
1878
1878
  return missing_controls
1879
1879
 
1880
1880
 
1881
- def log_controls_info(ssp_obj: dict, current_imps: List[dict]) -> None:
1881
+ def log_controls_info(ssp_obj: SSP, current_imps: List[dict]) -> None:
1882
1882
  """
1883
1883
  Log controls info
1884
1884
 
1885
- :param dict ssp_obj: SSP object
1885
+ :param SSP ssp_obj: SSP object
1886
1886
  :param List[dict] current_imps: List of current implementations
1887
1887
  :return None:
1888
1888
  :rtype None:
@@ -2305,8 +2305,8 @@ def fetch_existing_stakeholders(api: Api, config: dict, regscale_ssp: dict) -> l
2305
2305
  if response.ok:
2306
2306
  logger.info(
2307
2307
  f"Found {len(response.json())} existing stakeholders",
2308
- record_type="stackholders",
2309
- model_layer="stackholders",
2308
+ record_type="stakeholders",
2309
+ model_layer="stakeholders",
2310
2310
  )
2311
2311
  return response.json()
2312
2312
  return []
@@ -59,7 +59,7 @@ def get_dict_value(outer_key: str, inner_key: str, source_dict: Dict) -> Optiona
59
59
  outer_dict = source_dict.get(outer_key, None)
60
60
  if outer_dict is not None and isinstance(outer_dict, dict):
61
61
  val = outer_dict.get(inner_key, None)
62
- logger.info(f"{val}")
62
+ logger.debug(f"{val=}")
63
63
  return val
64
64
  return None
65
65
 
@@ -205,8 +205,8 @@ def parse_inventory_items(trv: FedrampTraversal, components_dict: Dict):
205
205
 
206
206
  for imp_component in implemented_components:
207
207
  if not isinstance(components_dict, dict):
208
- logger.info(components_dict)
209
- logger.info("components do not exist yet")
208
+ logger.debug(components_dict)
209
+ logger.info("Components do not exist yet.")
210
210
  continue
211
211
  comp = components_dict.get(imp_component.get("component_uuid"))
212
212
  comp_id = comp.get("id") if comp else None
@@ -9,12 +9,12 @@ import enum
9
9
  import hashlib
10
10
  import json
11
11
  import logging
12
- import re
13
12
  import threading
14
13
  import time
15
14
  from abc import ABC, abstractmethod
16
15
  from collections import defaultdict
17
- from typing import Any, Dict, Generic, Iterator, List, Optional, Set, TypeVar, Union
16
+ from concurrent.futures import ThreadPoolExecutor
17
+ from typing import Any, Dict, Generic, Iterator, List, Optional, Set, TypeVar, Union, Callable
18
18
 
19
19
  from rich.progress import Progress, TaskID
20
20
 
@@ -269,6 +269,10 @@ class IntegrationAsset:
269
269
  other_cloud_identifier: Optional[str] = None
270
270
  patch_level: Optional[str] = None
271
271
  cpe: Optional[str] = None
272
+ is_latest_scan: Optional[bool] = None
273
+ is_authenticated_scan: Optional[bool] = None
274
+ system_administrator_id: Optional[str] = None
275
+ scanning_tool: Optional[str] = None
272
276
 
273
277
  source_data: Optional[Dict[str, Any]] = None
274
278
  url: Optional[str] = None
@@ -345,6 +349,15 @@ class IntegrationFinding:
345
349
  :param Optional[str] remediation: The remediation of the finding, defaults to None.
346
350
  :param Optional[str] source_rule_id: The source rule ID of the finding, defaults to None.
347
351
  :param Optional[str] poam_id: The POAM ID of the finding, defaults to None.
352
+ :param Optional[str] cvss_v3_vector: The CVSS v3 vector of the finding, defaults to None.
353
+ :param Optional[str] cvss_v2_vector: The CVSS v2 vector of the finding, defaults to None.
354
+ :param Optional[str] affected_os: The affected OS of the finding, defaults to None.
355
+ :param Optional[str] image_digest: The image digest of the finding, defaults to None.
356
+ :param Optional[str] affected_packages: The affected packages of the finding, defaults to None.
357
+ :param Optional[str] installed_versions: The installed versions of the finding, defaults to None.
358
+ :param Optional[str] fixed_versions: The fixed versions of the finding, defaults to None.
359
+ :param Optional[str] fix_status: The fix status of the finding, defaults to None.
360
+ :param Optional[str] build_version: The build version of the finding, defaults to None.
348
361
  """
349
362
 
350
363
  control_labels: List[str]
@@ -364,9 +377,20 @@ class IntegrationFinding:
364
377
  cvss_v2_score: Optional[float] = None
365
378
  ip_address: Optional[str] = None
366
379
  plugin_id: Optional[str] = None
380
+ plugin_text: Optional[str] = None
367
381
  dns: Optional[str] = None
368
382
  severity_int: int = 0
369
383
  security_check: Optional[str] = None
384
+ cvss_v3_vector: Optional[str] = None
385
+ cvss_v2_vector: Optional[str] = None
386
+ affected_os: Optional[str] = None
387
+ package_path: Optional[str] = None
388
+ image_digest: Optional[str] = None
389
+ affected_packages: Optional[str] = None
390
+ installed_versions: Optional[str] = None
391
+ fixed_versions: Optional[str] = None
392
+ fix_status: Optional[str] = None
393
+ build_version: Optional[str] = None
370
394
 
371
395
  # Issues
372
396
  issue_title: str = ""
@@ -391,6 +415,7 @@ class IntegrationFinding:
391
415
  risk_adjustment: str = "No"
392
416
  operational_requirements: Optional[str] = None
393
417
  deviation_rationale: Optional[str] = None
418
+ is_cwe: bool = False
394
419
 
395
420
  poam_comments: Optional[str] = None
396
421
  vulnerability_id: Optional[int] = None
@@ -1048,6 +1073,10 @@ class ScannerIntegration(ABC):
1048
1073
  softwareVersion=asset.software_version,
1049
1074
  softwareName=asset.software_name,
1050
1075
  softwareVendor=asset.software_vendor,
1076
+ bLatestScan=asset.is_latest_scan,
1077
+ bAuthenticatedScan=asset.is_authenticated_scan,
1078
+ systemAdministratorId=asset.system_administrator_id,
1079
+ scanningTool=asset.scanning_tool,
1051
1080
  )
1052
1081
  if self.asset_identifier_field:
1053
1082
  setattr(new_asset, self.asset_identifier_field, asset.identifier)
@@ -1211,34 +1240,126 @@ class ScannerIntegration(ABC):
1211
1240
 
1212
1241
  def _process_assets(self, assets: Iterator[IntegrationAsset], loading_assets: TaskID) -> int:
1213
1242
  """
1214
- Processes the assets using single or multi-threaded approach based on THREAD_MAX_WORKERS.
1243
+ Process assets using single or multi-threaded approach based on THREAD_MAX_WORKERS.
1215
1244
 
1216
- :param Iterator[IntegrationAsset] assets: The assets to process
1217
- :param TaskID loading_assets: The task ID for the progress bar
1218
- :return: The number of assets processed
1245
+ :param Iterator[IntegrationAsset] assets: Assets to process
1246
+ :param TaskID loading_assets: Task ID for the progress bar
1247
+ :return: Number of assets processed
1219
1248
  :rtype: int
1220
1249
  """
1221
- assets_processed = 0
1222
- # prime cache
1250
+ self._prime_asset_cache()
1251
+ process_func = self._create_process_function(loading_assets)
1252
+ max_workers = get_thread_workers_max()
1253
+
1254
+ if max_workers == 1:
1255
+ return self._process_single_threaded(assets, process_func)
1256
+ return self._process_multi_threaded(assets, process_func, max_workers)
1257
+
1258
+ def _prime_asset_cache(self) -> None:
1259
+ """
1260
+ Prime the asset cache by fetching assets for the given plan.
1261
+
1262
+ :rtype: None
1263
+ """
1223
1264
  regscale_models.Asset.get_all_by_parent(
1224
1265
  parent_id=self.plan_id, parent_module=regscale_models.SecurityPlan.get_module_string()
1225
1266
  )
1226
1267
 
1227
- process_func = lambda my_asset: self._process_single_asset(my_asset, loading_assets) # noqa: E731
1268
+ def _create_process_function(self, loading_assets: TaskID) -> Callable[[IntegrationAsset], bool]:
1269
+ """
1270
+ Create a function to process a single asset.
1271
+
1272
+ :param TaskID loading_assets: Task ID for the progress bar
1273
+ :return: Function that processes an asset and returns success status
1274
+ :rtype: Callable[[IntegrationAsset], bool]
1275
+ """
1276
+ return lambda asset: self._process_single_asset(asset, loading_assets)
1277
+
1278
+ def _process_single_threaded(
1279
+ self, assets: Iterator[IntegrationAsset], process_func: Callable[[IntegrationAsset], bool]
1280
+ ) -> int:
1281
+ """
1282
+ Process assets sequentially in a single thread.
1283
+
1284
+ :param Iterator[IntegrationAsset] assets: Assets to process
1285
+ :param Callable[[IntegrationAsset], bool] process_func: Function to process each asset
1286
+ :return: Number of assets processed
1287
+ :rtype: int
1288
+ """
1289
+ assets_processed = 0
1290
+ for asset in assets:
1291
+ if process_func(asset):
1292
+ assets_processed = self._update_processed_count(assets_processed)
1293
+ return assets_processed
1294
+
1295
+ def _process_multi_threaded(
1296
+ self, assets: Iterator[IntegrationAsset], process_func: Callable[[IntegrationAsset], bool], max_workers: int
1297
+ ) -> int:
1298
+ """
1299
+ Process assets in batches using multiple threads.
1300
+
1301
+ :param Iterator[IntegrationAsset] assets: Assets to process
1302
+ :param Callable[[IntegrationAsset], bool] process_func: Function to process each asset
1303
+ :param int max_workers: Maximum number of worker threads
1304
+ :return: Number of assets processed
1305
+ :rtype: int
1306
+ """
1307
+ batch_size = max_workers * 2
1308
+ assets_processed = 0
1309
+
1310
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
1311
+ batch = []
1312
+ futures = []
1228
1313
 
1229
- if get_thread_workers_max() == 1:
1230
1314
  for asset in assets:
1231
- if process_func(asset):
1232
- assets_processed = self._update_processed_count(assets_processed)
1233
- else:
1234
- with concurrent.futures.ThreadPoolExecutor(max_workers=get_thread_workers_max()) as executor:
1235
- future_to_asset = {executor.submit(process_func, asset): asset for asset in assets}
1236
- for future in concurrent.futures.as_completed(future_to_asset):
1237
- if future.result():
1238
- assets_processed = self._update_processed_count(assets_processed)
1315
+ batch.append(asset)
1316
+ if len(batch) >= batch_size:
1317
+ assets_processed += self._submit_and_process_batch(executor, process_func, batch, futures)
1318
+ batch = []
1319
+ futures = []
1320
+
1321
+ if batch: # Process any remaining items
1322
+ assets_processed += self._submit_and_process_batch(executor, process_func, batch, futures)
1323
+
1324
+ return assets_processed
1325
+
1326
+ def _submit_and_process_batch(
1327
+ self,
1328
+ executor: ThreadPoolExecutor,
1329
+ process_func: Callable[[IntegrationAsset], bool],
1330
+ batch: List[IntegrationAsset],
1331
+ futures: List,
1332
+ ) -> int:
1333
+ """
1334
+ Submit a batch of assets for processing and count successful completions.
1335
+
1336
+ :param ThreadPoolExecutor executor: Thread pool executor for parallel processing
1337
+ :param Callable[[IntegrationAsset], bool] process_func: Function to process each asset
1338
+ :param List[IntegrationAsset] batch: Batch of assets to process
1339
+ :param List futures: List to store future objects
1340
+ :return: Number of assets processed in this batch
1341
+ :rtype: int
1342
+ """
1343
+ assets_processed = 0
1344
+ for asset in batch:
1345
+ futures.append(executor.submit(process_func, asset))
1346
+
1347
+ for future in concurrent.futures.as_completed(futures):
1348
+ if future.result():
1349
+ assets_processed = self._update_processed_count(assets_processed)
1239
1350
 
1240
1351
  return assets_processed
1241
1352
 
1353
+ def _update_processed_count(self, current_count: int) -> int:
1354
+ """
1355
+ Increment the processed count.
1356
+
1357
+ :param int current_count: Current number of processed items
1358
+ :return: Updated count
1359
+ :rtype: int
1360
+ """
1361
+ return current_count + 1
1362
+
1242
1363
  def _process_single_asset(self, asset: IntegrationAsset, loading_assets: TaskID) -> bool:
1243
1364
  """
1244
1365
  Processes a single asset and handles any exceptions.
@@ -1430,7 +1551,7 @@ class ScannerIntegration(ABC):
1430
1551
  issue.issueOwnerId = self.assessor_id
1431
1552
  issue.securityPlanId = self.plan_id
1432
1553
  issue.identification = "Vulnerability Assessment"
1433
- issue.dateFirstDetected = finding.date_created
1554
+ issue.dateFirstDetected = finding.first_seen
1434
1555
  issue.dueDate = finding.due_date
1435
1556
  issue.description = description
1436
1557
  issue.sourceReport = finding.source_report or self.title
@@ -1476,15 +1597,34 @@ class ScannerIntegration(ABC):
1476
1597
  bulk_update=True, defaults={"otherIdentifier": self._get_other_identifier(finding, is_poam)}
1477
1598
  )
1478
1599
 
1600
+ self._handle_property_creation_for_issue(issue, finding)
1601
+ return issue
1602
+
1603
+ def _handle_property_creation_for_issue(self, issue: regscale_models.Issue, finding: IntegrationFinding) -> None:
1604
+ """
1605
+ Handles property creation for an issue based on the finding data
1606
+
1607
+ :param regscale_models.Issue issue: The issue to handle properties for
1608
+ :param IntegrationFinding finding: The finding data
1609
+ :rtype: None
1610
+ """
1479
1611
  if poc := finding.point_of_contact:
1480
- _ = regscale_models.Property(
1612
+ regscale_models.Property(
1481
1613
  key="POC",
1482
1614
  value=poc,
1483
1615
  parentId=issue.id,
1484
1616
  parentModule="issues",
1485
- ).create_or_update(bulk_create=True, bulk_update=True)
1617
+ ).create_or_update()
1618
+ logger.debug("Added POC property %s to issue %s", poc, issue.id)
1486
1619
 
1487
- return issue
1620
+ if finding.is_cwe:
1621
+ regscale_models.Property(
1622
+ key="CWE",
1623
+ value=finding.plugin_id,
1624
+ parentId=issue.id,
1625
+ parentModule="issues",
1626
+ ).create_or_update()
1627
+ logger.debug("Added CWE property %s to issue %s", finding.plugin_id, issue.id)
1488
1628
 
1489
1629
  @staticmethod
1490
1630
  def get_consolidated_asset_identifier(
@@ -1608,15 +1748,16 @@ class ScannerIntegration(ABC):
1608
1748
  :param IntegrationFinding finding: The finding data that has failed
1609
1749
  :rtype: None
1610
1750
  """
1611
- logger.debug("Creating issue for failing finding %s", finding.external_id)
1612
- found_issue = self.create_or_update_issue_from_finding(
1613
- title=issue_title,
1614
- finding=finding,
1615
- )
1616
- # Update the control implementation status to NOT_IMPLEMENTED since we have a failing finding
1617
- if found_issue.controlImplementationIds:
1618
- for control_id in found_issue.controlImplementationIds:
1619
- self.update_control_implementation_status_after_close(control_id)
1751
+ if ScannerVariables.vulnerabilityCreation.lower() != "noissue":
1752
+ logger.debug("Creating issue for failing finding %s", finding.external_id)
1753
+ found_issue = self.create_or_update_issue_from_finding(
1754
+ title=issue_title,
1755
+ finding=finding,
1756
+ )
1757
+ # Update the control implementation status to NOT_IMPLEMENTED since we have a failing finding
1758
+ if found_issue.controlImplementationIds:
1759
+ for control_id in found_issue.controlImplementationIds:
1760
+ self.update_control_implementation_status_after_close(control_id)
1620
1761
 
1621
1762
  def handle_failing_checklist(
1622
1763
  self,
@@ -1844,9 +1985,8 @@ class ScannerIntegration(ABC):
1844
1985
  scan_history = self.create_scan_history()
1845
1986
  current_vulnerabilities: Dict[int, Set[int]] = defaultdict(set)
1846
1987
  processed_findings_count = 0
1847
- findings_to_process = self.num_findings_to_process
1848
1988
  loading_findings = self.finding_progress.add_task(
1849
- f"[#f8b737]Processing {f'{findings_to_process} ' if findings_to_process else ''}finding(s) from {self.title}",
1989
+ f"[#f8b737]Processing {f'{self.num_findings_to_process} ' if self.num_findings_to_process else ''}finding(s) from {self.title}",
1850
1990
  total=self.num_findings_to_process if self.num_findings_to_process else None,
1851
1991
  )
1852
1992
 
@@ -1865,13 +2005,11 @@ class ScannerIntegration(ABC):
1865
2005
  self.process_finding(finding_to_process, scan_history, current_vulnerabilities)
1866
2006
  with count_lock:
1867
2007
  processed_findings_count += 1
1868
- if findings_to_process and self.finding_progress.tasks[loading_findings].total != float(
1869
- findings_to_process
1870
- ):
2008
+ if self.num_findings_to_process:
1871
2009
  self.finding_progress.update(
1872
2010
  loading_findings,
1873
- total=findings_to_process,
1874
- description=f"[#f8b737]Processing {findings_to_process} findings from {self.title}.",
2011
+ total=self.num_findings_to_process,
2012
+ description=f"[#f8b737]Processing {self.num_findings_to_process} findings from {self.title}.",
1875
2013
  )
1876
2014
  self.finding_progress.advance(loading_findings, 1)
1877
2015
  except Exception as exc:
@@ -1885,13 +2023,27 @@ class ScannerIntegration(ABC):
1885
2023
  for finding in findings:
1886
2024
  process_finding_with_progress(finding)
1887
2025
  else:
2026
+ # Process findings in batches to control memory usage
2027
+ batch_size = get_thread_workers_max() * 2 # Set batch size based on thread count
1888
2028
  with concurrent.futures.ThreadPoolExecutor(max_workers=get_thread_workers_max()) as executor:
1889
- list(executor.map(process_finding_with_progress, findings))
2029
+ batch = []
2030
+ for finding in findings:
2031
+ batch.append(finding)
2032
+ if len(batch) >= batch_size:
2033
+ # Process this batch
2034
+ list(executor.map(process_finding_with_progress, batch))
2035
+ # Clear the batch
2036
+ batch = []
2037
+
2038
+ # Process any remaining items
2039
+ if batch:
2040
+ list(executor.map(process_finding_with_progress, batch))
1890
2041
 
1891
2042
  # Close outdated issues
1892
2043
  self._results["scan_history"] = scan_history.save()
1893
2044
  self.update_result_counts("issues", regscale_models.Issue.bulk_save(progress_context=self.finding_progress))
1894
2045
  self.close_outdated_issues(current_vulnerabilities)
2046
+ self._perform_batch_operations(self.finding_progress)
1895
2047
 
1896
2048
  return processed_findings_count
1897
2049
 
@@ -2068,6 +2220,9 @@ class ScannerIntegration(ABC):
2068
2220
  finding.vpr_score if hasattr(finding, "vprScore") else None
2069
2221
  ), # If this is the VPR score, otherwise use a different field
2070
2222
  cvsSv3BaseScore=finding.cvss_v3_base_score or finding.cvss_v3_score or finding.cvss_score,
2223
+ cvsSv2BaseScore=finding.cvss_v2_score,
2224
+ cvsSv3BaseVector=finding.cvss_v3_vector,
2225
+ cvsSv2BaseVector=finding.cvss_v2_vector,
2071
2226
  scanId=scan_history.id,
2072
2227
  severity=self.issue_to_vulnerability_map.get(finding.severity, regscale_models.VulnerabilitySeverity.Low),
2073
2228
  description=finding.description,
@@ -2082,27 +2237,35 @@ class ScannerIntegration(ABC):
2082
2237
  plugInName=finding.cve or finding.plugin_name, # Use CVE if available, otherwise use plugin name
2083
2238
  plugInId=finding.plugin_id,
2084
2239
  exploitAvailable=None, # Set this if you have information about exploit availability
2085
- plugInText=finding.observations, # or finding.evidence, whichever is more appropriate
2240
+ plugInText=finding.plugin_text
2241
+ or finding.observations, # or finding.evidence, whichever is more appropriate
2086
2242
  port=finding.port if hasattr(finding, "port") else None,
2087
2243
  protocol=finding.protocol if hasattr(finding, "protocol") else None,
2088
2244
  operatingSystem=asset.operating_system if hasattr(asset, "operating_system") else None,
2245
+ fixedVersions=finding.fixed_versions,
2246
+ buildVersion=finding.build_version,
2247
+ fixStatus=finding.fix_status,
2248
+ installedVersions=finding.installed_versions,
2249
+ affectedOS=finding.affected_os,
2250
+ packagePath=finding.package_path,
2251
+ imageDigest=finding.image_digest,
2252
+ affectedPackages=finding.affected_packages,
2089
2253
  )
2090
2254
 
2091
2255
  vulnerability = vulnerability.create_or_update()
2092
- if re.match(r"^\d+\.\d+(\.\d+){0,2}$", self.regscale_version) or self.regscale_version >= "5.64.0":
2093
- regscale_models.VulnerabilityMapping(
2094
- vulnerabilityId=vulnerability.id,
2095
- assetId=asset.id,
2096
- scanId=scan_history.id,
2097
- securityPlansId=self.plan_id,
2098
- createdById=self.assessor_id,
2099
- tenantsId=self.tenant_id,
2100
- isPublic=True,
2101
- dateCreated=get_current_datetime(),
2102
- firstSeen=finding.first_seen,
2103
- lastSeen=finding.last_seen,
2104
- status=finding.status,
2105
- ).create_unique()
2256
+ regscale_models.VulnerabilityMapping(
2257
+ vulnerabilityId=vulnerability.id,
2258
+ assetId=asset.id,
2259
+ scanId=scan_history.id,
2260
+ securityPlansId=self.plan_id,
2261
+ createdById=self.assessor_id,
2262
+ tenantsId=self.tenant_id,
2263
+ isPublic=True,
2264
+ dateCreated=get_current_datetime(),
2265
+ firstSeen=finding.first_seen,
2266
+ lastSeen=finding.last_seen,
2267
+ status=finding.status,
2268
+ ).create_unique()
2106
2269
  return vulnerability
2107
2270
 
2108
2271
  def handle_vulnerability(
@@ -2131,11 +2294,12 @@ class ScannerIntegration(ABC):
2131
2294
  vulnerability = self.create_vulnerability_from_finding(finding, asset, scan_history)
2132
2295
  finding.vulnerability_id = vulnerability.id
2133
2296
 
2134
- # Handle associated issue
2135
- self.create_or_update_issue_from_finding(
2136
- title=finding.title,
2137
- finding=finding,
2138
- )
2297
+ if ScannerVariables.vulnerabilityCreation.lower() != "noissue":
2298
+ # Handle associated issue
2299
+ self.create_or_update_issue_from_finding(
2300
+ title=finding.title,
2301
+ finding=finding,
2302
+ )
2139
2303
 
2140
2304
  return vulnerability.id
2141
2305
 
@@ -2492,6 +2656,8 @@ class ScannerIntegration(ABC):
2492
2656
  created_count = instance._results.get("assets", {}).get("created_count", 0)
2493
2657
  updated_count = instance._results.get("assets", {}).get("updated_count", 0)
2494
2658
  dedupe_count = assets_processed - (created_count + updated_count)
2659
+ # Ensure dedupe_count is always a positive value
2660
+ dedupe_count = dedupe_count if dedupe_count >= 0 else dedupe_count * -1
2495
2661
  logger.info(
2496
2662
  "%d assets processed and %d asset(s) deduped. %d asset(s) created & %d asset(s) updated in RegScale.",
2497
2663
  assets_processed,
@@ -1,9 +1,67 @@
1
1
  {
2
2
  "title": "CISA Catalog of Known Exploited Vulnerabilities",
3
- "catalogVersion": "2025.03.19",
4
- "dateReleased": "2025-03-19T18:00:10.5417Z",
5
- "count": 1307,
3
+ "catalogVersion": "2025.03.27",
4
+ "dateReleased": "2025-03-27T17:55:47.8204Z",
5
+ "count": 1311,
6
6
  "vulnerabilities": [
7
+ {
8
+ "cveID": "CVE-2025-2783",
9
+ "vendorProject": "Google",
10
+ "product": "Chromium Mojo",
11
+ "vulnerabilityName": "Google Chromium Mojo Sandbox Escape Vulnerability",
12
+ "dateAdded": "2025-03-27",
13
+ "shortDescription": "Google Chromium Mojo on Windows contains a sandbox escape vulnerability caused by a logic error, which results from an incorrect handle being provided in unspecified circumstances. This vulnerability could affect multiple web browsers that utilize Chromium, including, but not limited to, Google Chrome, Microsoft Edge, and Opera.",
14
+ "requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
15
+ "dueDate": "2025-04-17",
16
+ "knownRansomwareCampaignUse": "Unknown",
17
+ "notes": "https:\/\/chromereleases.googleblog.com\/2025\/03\/stable-channel-update-for-desktop_25.html ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-2783",
18
+ "cwes": []
19
+ },
20
+ {
21
+ "cveID": "CVE-2019-9875",
22
+ "vendorProject": "Sitecore",
23
+ "product": "CMS and Experience Platform (XP)",
24
+ "vulnerabilityName": "Sitecore CMS and Experience Platform (XP) Deserialization Vulnerability",
25
+ "dateAdded": "2025-03-26",
26
+ "shortDescription": "Sitecore CMS and Experience Platform (XP) contain a deserialization vulnerability in the Sitecore.Security.AntiCSRF module that allows an authenticated attacker to execute arbitrary code by sending a serialized .NET object in the HTTP POST parameter __CSRFTOKEN.",
27
+ "requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
28
+ "dueDate": "2025-04-16",
29
+ "knownRansomwareCampaignUse": "Unknown",
30
+ "notes": "https:\/\/support.sitecore.com\/kb?id=kb_article_view&sysparm_article=KB0038556 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2019-9875",
31
+ "cwes": [
32
+ "CWE-502"
33
+ ]
34
+ },
35
+ {
36
+ "cveID": "CVE-2019-9874",
37
+ "vendorProject": "Sitecore",
38
+ "product": "CMS and Experience Platform (XP)",
39
+ "vulnerabilityName": "Sitecore CMS and Experience Platform (XP) Deserialization Vulnerability",
40
+ "dateAdded": "2025-03-26",
41
+ "shortDescription": "Sitecore CMS and Experience Platform (XP) contain a deserialization vulnerability in the Sitecore.Security.AntiCSRF module that allows an unauthenticated attacker to execute arbitrary code by sending a serialized .NET object in the HTTP POST parameter __CSRFTOKEN.",
42
+ "requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
43
+ "dueDate": "2025-04-16",
44
+ "knownRansomwareCampaignUse": "Unknown",
45
+ "notes": "https:\/\/support.sitecore.com\/kb?id=kb_article_view&sysparm_article=KB0334035 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2019-9874",
46
+ "cwes": [
47
+ "CWE-502"
48
+ ]
49
+ },
50
+ {
51
+ "cveID": "CVE-2025-30154",
52
+ "vendorProject": "reviewdog",
53
+ "product": "action-setup GitHub Action",
54
+ "vulnerabilityName": "reviewdog\/action-setup GitHub Action Embedded Malicious Code Vulnerability",
55
+ "dateAdded": "2025-03-24",
56
+ "shortDescription": "reviewdog action-setup GitHub Action contains an embedded malicious code vulnerability that dumps exposed secrets to Github Actions Workflow Logs.",
57
+ "requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
58
+ "dueDate": "2025-04-14",
59
+ "knownRansomwareCampaignUse": "Unknown",
60
+ "notes": "This vulnerability affects a common open-source project, third-party library, or a protocol used by different products. For more information, please see: CISA Mitigation Instructions: https:\/\/www.cisa.gov\/news-events\/alerts\/2025\/03\/18\/supply-chain-compromise-third-party-tj-actionschanged-files-cve-2025-30066-and-reviewdogaction ; Additional References: https:\/\/github.com\/reviewdog\/reviewdog\/security\/advisories\/GHSA-qmg3-hpqr-gqvc ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-30154",
61
+ "cwes": [
62
+ "CWE-506"
63
+ ]
64
+ },
7
65
  {
8
66
  "cveID": "CVE-2017-12637",
9
67
  "vendorProject": "SAP",
@@ -55,11 +113,11 @@
55
113
  "product": "changed-files GitHub Action",
56
114
  "vulnerabilityName": "tj-actions\/changed-files GitHub Action Embedded Malicious Code Vulnerability",
57
115
  "dateAdded": "2025-03-18",
58
- "shortDescription": "The tj-actions\/changed-files GitHub Action contains an embedded malicious code vulnerability that allows a remote attacker to discover secrets by reading actions logs. These secrets may include, but are not limited to, valid AWS access keys, GitHub personal access tokens (PATs), npm tokens, and private RSA keys.",
116
+ "shortDescription": "tj-actions\/changed-files GitHub Action contains an embedded malicious code vulnerability that allows a remote attacker to discover secrets by reading Github Actions Workflow Logs. These secrets may include, but are not limited to, valid AWS access keys, GitHub personal access tokens (PATs), npm tokens, and private RSA keys.",
59
117
  "requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
60
118
  "dueDate": "2025-04-08",
61
119
  "knownRansomwareCampaignUse": "Unknown",
62
- "notes": "https:\/\/github.com\/tj-actions\/changed-files\/blob\/45fb12d7a8bedb4da42342e52fe054c6c2c3fd73\/README.md?plain=1#L20-L28 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-30066",
120
+ "notes": "This vulnerability affects a common open-source project, third-party library, or a protocol used by different products. For more information, please see: CISA Mitigation Instructions: https:\/\/www.cisa.gov\/news-events\/alerts\/2025\/03\/18\/supply-chain-compromise-third-party-tj-actionschanged-files-cve-2025-30066-and-reviewdogaction ; Additional References: https:\/\/github.com\/tj-actions\/changed-files\/blob\/45fb12d7a8bedb4da42342e52fe054c6c2c3fd73\/README.md?plain=1#L20-L28 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-30066",
63
121
  "cwes": [
64
122
  "CWE-506"
65
123
  ]
@@ -2949,7 +3007,7 @@
2949
3007
  {
2950
3008
  "cveID": "CVE-2024-4761",
2951
3009
  "vendorProject": "Google",
2952
- "product": "Chromium Visuals",
3010
+ "product": "Chromium V8",
2953
3011
  "vulnerabilityName": "Google Chromium V8 Out-of-Bounds Memory Write Vulnerability",
2954
3012
  "dateAdded": "2024-05-16",
2955
3013
  "shortDescription": "Google Chromium V8 Engine contains an unspecified out-of-bounds memory write vulnerability via a crafted HTML page. This vulnerability could affect multiple web browsers that utilize Chromium, including, but not limited to, Google Chrome, Microsoft Edge, and Opera. ",
@@ -14604,7 +14662,7 @@
14604
14662
  "cveID": "CVE-2020-6572",
14605
14663
  "vendorProject": "Google",
14606
14664
  "product": "Chrome Media",
14607
- "vulnerabilityName": "Google Chrome Media Prior to 81.0.4044.92 Use-After-Free Vulnerability",
14665
+ "vulnerabilityName": "Google Chrome Media Use-After-Free Vulnerability",
14608
14666
  "dateAdded": "2022-01-10",
14609
14667
  "shortDescription": "Google Chrome Media contains a use-after-free vulnerability that allows a remote attacker to execute code via a crafted HTML page.",
14610
14668
  "requiredAction": "Apply updates per vendor instructions.",