regscale-cli 6.20.7.0__py3-none-any.whl → 6.20.9.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.
- regscale/_version.py +1 -1
- regscale/core/app/api.py +8 -1
- regscale/core/app/application.py +130 -20
- regscale/core/utils/date.py +16 -16
- regscale/integrations/commercial/aqua/aqua.py +1 -1
- regscale/integrations/commercial/aws/cli.py +1 -1
- regscale/integrations/commercial/defender.py +1 -1
- regscale/integrations/commercial/ecr.py +1 -1
- regscale/integrations/commercial/ibm.py +1 -1
- regscale/integrations/commercial/nexpose.py +1 -1
- regscale/integrations/commercial/prisma.py +1 -1
- regscale/integrations/commercial/qualys/__init__.py +150 -77
- regscale/integrations/commercial/qualys/containers.py +2 -1
- regscale/integrations/commercial/qualys/scanner.py +5 -3
- regscale/integrations/commercial/snyk.py +14 -4
- regscale/integrations/commercial/synqly/ticketing.py +23 -11
- regscale/integrations/commercial/veracode.py +15 -4
- regscale/integrations/commercial/xray.py +1 -1
- regscale/integrations/public/cisa.py +7 -1
- regscale/integrations/public/nist_catalog.py +8 -2
- regscale/integrations/scanner_integration.py +18 -36
- regscale/models/integration_models/cisa_kev_data.json +51 -6
- regscale/models/integration_models/flat_file_importer/__init__.py +34 -19
- regscale/models/integration_models/send_reminders.py +8 -2
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/regscale_models/control_implementation.py +40 -0
- regscale/models/regscale_models/issue.py +7 -4
- regscale/models/regscale_models/parameter.py +3 -2
- regscale/models/regscale_models/ports_protocol.py +15 -5
- regscale/models/regscale_models/vulnerability.py +1 -1
- regscale/utils/graphql_client.py +3 -6
- regscale/utils/threading/threadhandler.py +12 -2
- {regscale_cli-6.20.7.0.dist-info → regscale_cli-6.20.9.0.dist-info}/METADATA +13 -13
- {regscale_cli-6.20.7.0.dist-info → regscale_cli-6.20.9.0.dist-info}/RECORD +41 -40
- tests/regscale/core/test_app.py +402 -16
- tests/regscale/core/test_version_regscale.py +62 -0
- tests/regscale/test_init.py +2 -0
- {regscale_cli-6.20.7.0.dist-info → regscale_cli-6.20.9.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.20.7.0.dist-info → regscale_cli-6.20.9.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.20.7.0.dist-info → regscale_cli-6.20.9.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.20.7.0.dist-info → regscale_cli-6.20.9.0.dist-info}/top_level.txt +0 -0
|
@@ -52,13 +52,6 @@ def sync_freshdesk(regscale_id: int, regscale_module: str, name: str, subject: s
|
|
|
52
52
|
@ticketing.command(name="sync_jira")
|
|
53
53
|
@regscale_id()
|
|
54
54
|
@regscale_module()
|
|
55
|
-
@click.option(
|
|
56
|
-
"--issue_type",
|
|
57
|
-
type=click.STRING,
|
|
58
|
-
help="jira issue type",
|
|
59
|
-
required=True,
|
|
60
|
-
prompt="jira issue type",
|
|
61
|
-
)
|
|
62
55
|
@click.option(
|
|
63
56
|
"--project",
|
|
64
57
|
type=click.STRING,
|
|
@@ -66,6 +59,12 @@ def sync_freshdesk(regscale_id: int, regscale_module: str, name: str, subject: s
|
|
|
66
59
|
required=True,
|
|
67
60
|
prompt="jira project",
|
|
68
61
|
)
|
|
62
|
+
@click.option(
|
|
63
|
+
"--default_issue_type",
|
|
64
|
+
type=click.STRING,
|
|
65
|
+
help="Default Issue Type for the integration. If provided, the issue_type field becomes optional in ticket creation requests.",
|
|
66
|
+
required=False,
|
|
67
|
+
)
|
|
69
68
|
@click.option(
|
|
70
69
|
"--default_project",
|
|
71
70
|
type=click.STRING,
|
|
@@ -80,7 +79,12 @@ def sync_freshdesk(regscale_id: int, regscale_module: str, name: str, subject: s
|
|
|
80
79
|
default=True,
|
|
81
80
|
)
|
|
82
81
|
def sync_jira(
|
|
83
|
-
regscale_id: int,
|
|
82
|
+
regscale_id: int,
|
|
83
|
+
regscale_module: str,
|
|
84
|
+
project: str,
|
|
85
|
+
default_issue_type: str,
|
|
86
|
+
default_project: str,
|
|
87
|
+
sync_attachments: bool,
|
|
84
88
|
) -> None:
|
|
85
89
|
"""Sync Ticketing data between Jira and RegScale."""
|
|
86
90
|
from regscale.models.integration_models.synqly_models.connectors import Ticketing
|
|
@@ -89,8 +93,8 @@ def sync_jira(
|
|
|
89
93
|
ticketing_jira.run_sync(
|
|
90
94
|
regscale_id=regscale_id,
|
|
91
95
|
regscale_module=regscale_module,
|
|
92
|
-
issue_type=issue_type,
|
|
93
96
|
project=project,
|
|
97
|
+
default_issue_type=default_issue_type,
|
|
94
98
|
default_project=default_project,
|
|
95
99
|
sync_attachments=sync_attachments,
|
|
96
100
|
)
|
|
@@ -157,12 +161,20 @@ def sync_servicenow(regscale_id: int, regscale_module: str, issue_type: str, def
|
|
|
157
161
|
required=True,
|
|
158
162
|
prompt="servicenow_sir issue type",
|
|
159
163
|
)
|
|
160
|
-
|
|
164
|
+
@click.option(
|
|
165
|
+
"--default_project",
|
|
166
|
+
type=click.STRING,
|
|
167
|
+
help="Default Project for the integration. This maps to the custom table for tickets. This table should be derived from Security Incident table. Defaults to the security incident table if not specified.",
|
|
168
|
+
required=False,
|
|
169
|
+
)
|
|
170
|
+
def sync_servicenow_sir(regscale_id: int, regscale_module: str, issue_type: str, default_project: str) -> None:
|
|
161
171
|
"""Sync Ticketing data between Servicenow Sir and RegScale."""
|
|
162
172
|
from regscale.models.integration_models.synqly_models.connectors import Ticketing
|
|
163
173
|
|
|
164
174
|
ticketing_servicenow_sir = Ticketing("servicenow_sir")
|
|
165
|
-
ticketing_servicenow_sir.run_sync(
|
|
175
|
+
ticketing_servicenow_sir.run_sync(
|
|
176
|
+
regscale_id=regscale_id, regscale_module=regscale_module, issue_type=issue_type, default_project=default_project
|
|
177
|
+
)
|
|
166
178
|
|
|
167
179
|
|
|
168
180
|
@ticketing.command(name="sync_torq")
|
|
@@ -28,10 +28,12 @@ FlatFileImporter.show_mapping(
|
|
|
28
28
|
message="File path to the folder containing Veracode .xlsx files to process to RegScale.",
|
|
29
29
|
prompt="File path for Veracode files",
|
|
30
30
|
import_name="veracode",
|
|
31
|
+
support_component=True,
|
|
31
32
|
)
|
|
32
33
|
def import_veracode(
|
|
33
34
|
folder_path: PathLike[str],
|
|
34
35
|
regscale_ssp_id: int,
|
|
36
|
+
component_id: int,
|
|
35
37
|
scan_date: datetime,
|
|
36
38
|
mappings_path: Path,
|
|
37
39
|
disable_mapping: bool,
|
|
@@ -43,9 +45,15 @@ def import_veracode(
|
|
|
43
45
|
"""
|
|
44
46
|
Import scans, vulnerabilities and assets to RegScale from Veracode export files
|
|
45
47
|
"""
|
|
48
|
+
if not regscale_ssp_id and not component_id:
|
|
49
|
+
raise click.UsageError(
|
|
50
|
+
"You must provide either a --regscale_ssp_id or a --component_id to import Veracode scans."
|
|
51
|
+
)
|
|
52
|
+
|
|
46
53
|
import_veracode_data(
|
|
47
54
|
folder_path=folder_path,
|
|
48
|
-
|
|
55
|
+
object_id=component_id if component_id else regscale_ssp_id,
|
|
56
|
+
is_component=bool(component_id),
|
|
49
57
|
scan_date=scan_date,
|
|
50
58
|
mappings_path=mappings_path,
|
|
51
59
|
disable_mapping=disable_mapping,
|
|
@@ -58,7 +66,7 @@ def import_veracode(
|
|
|
58
66
|
|
|
59
67
|
def import_veracode_data(
|
|
60
68
|
folder_path: PathLike[str],
|
|
61
|
-
|
|
69
|
+
object_id: int,
|
|
62
70
|
scan_date: datetime,
|
|
63
71
|
mappings_path: Path,
|
|
64
72
|
s3_bucket: str,
|
|
@@ -66,11 +74,13 @@ def import_veracode_data(
|
|
|
66
74
|
aws_profile: str,
|
|
67
75
|
disable_mapping: Optional[bool] = False,
|
|
68
76
|
upload_file: Optional[bool] = True,
|
|
77
|
+
is_component: Optional[bool] = False,
|
|
69
78
|
) -> None:
|
|
70
79
|
"""Import scans, vulnerabilities and assets to RegScale from Veracode export files"
|
|
71
80
|
|
|
72
81
|
:param os.PathLike[str] folder_path: Path to the folder containing Veracode files
|
|
73
|
-
:param int
|
|
82
|
+
:param int object_id: RegScale SSP ID or Component ID
|
|
83
|
+
:param bool is_component: Whether object_id is a component or not
|
|
74
84
|
:param datetime scan_date: Scan date
|
|
75
85
|
:param os.PathLike[str] mappings_path: Path to the header mapping file
|
|
76
86
|
:param str s3_bucket: S3 bucket to download the files from
|
|
@@ -85,7 +95,7 @@ def import_veracode_data(
|
|
|
85
95
|
import_name="Veracode",
|
|
86
96
|
file_types=[".xml", ".xlsx", ".json"],
|
|
87
97
|
folder_path=folder_path,
|
|
88
|
-
|
|
98
|
+
object_id=object_id,
|
|
89
99
|
scan_date=scan_date,
|
|
90
100
|
mappings_path=mappings_path,
|
|
91
101
|
disable_mapping=disable_mapping,
|
|
@@ -93,4 +103,5 @@ def import_veracode_data(
|
|
|
93
103
|
s3_prefix=s3_prefix,
|
|
94
104
|
aws_profile=aws_profile,
|
|
95
105
|
upload_file=upload_file,
|
|
106
|
+
is_component=is_component,
|
|
96
107
|
)
|
|
@@ -171,7 +171,13 @@ def parse_html(page_url: str, app: Application) -> list:
|
|
|
171
171
|
control["items"] = len(articles)
|
|
172
172
|
control["page"] += 1
|
|
173
173
|
# check if max threads <= 20 to prevent IP ban from CISA
|
|
174
|
-
|
|
174
|
+
max_threads_config = app.config.get("maxThreads", 100)
|
|
175
|
+
if not isinstance(max_threads_config, int):
|
|
176
|
+
try:
|
|
177
|
+
max_threads_config = int(max_threads_config)
|
|
178
|
+
except (ValueError, TypeError):
|
|
179
|
+
max_threads_config = 100
|
|
180
|
+
max_threads = min(max_threads_config, 20)
|
|
175
181
|
with ThreadPoolExecutor(max_workers=max_threads) as executor:
|
|
176
182
|
futures = []
|
|
177
183
|
for link in control["links"]:
|
|
@@ -67,8 +67,14 @@ def sort_controls_by_id(catalog_id: int) -> None:
|
|
|
67
67
|
api = Api()
|
|
68
68
|
config = app.config
|
|
69
69
|
# update api limits depending on maxThreads
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
max_threads = config.get("maxThreads", 100)
|
|
71
|
+
if not isinstance(max_threads, int):
|
|
72
|
+
try:
|
|
73
|
+
max_threads = int(max_threads)
|
|
74
|
+
except (ValueError, TypeError):
|
|
75
|
+
max_threads = 100
|
|
76
|
+
api.pool_connections = max(api.pool_connections, max_threads)
|
|
77
|
+
api.pool_maxsize = max(api.pool_maxsize, max_threads)
|
|
72
78
|
security_control_count: int = 0
|
|
73
79
|
|
|
74
80
|
# get all controls by catalog
|
|
@@ -638,6 +638,9 @@ class ScannerIntegration(ABC):
|
|
|
638
638
|
self.is_component: bool = is_component
|
|
639
639
|
if self.is_component:
|
|
640
640
|
self.component = regscale_models.Component.get_object(self.plan_id)
|
|
641
|
+
self.parent_module: str = regscale_models.Component.get_module_string()
|
|
642
|
+
else:
|
|
643
|
+
self.parent_module: str = regscale_models.SecurityPlan.get_module_string()
|
|
641
644
|
self.components: ThreadSafeList[Any] = ThreadSafeList()
|
|
642
645
|
self.asset_map_by_identifier: ThreadSafeDict[str, regscale_models.Asset] = ThreadSafeDict()
|
|
643
646
|
self.software_to_create: ThreadSafeList[regscale_models.SoftwareInventory] = ThreadSafeList()
|
|
@@ -655,16 +658,17 @@ class ScannerIntegration(ABC):
|
|
|
655
658
|
self.implementation_option_map: ThreadSafeDict[str, int] = ThreadSafeDict()
|
|
656
659
|
self.control_implementation_map: ThreadSafeDict[int, regscale_models.ControlImplementation] = ThreadSafeDict()
|
|
657
660
|
|
|
658
|
-
self.control_implementation_id_map = regscale_models.ControlImplementation.
|
|
659
|
-
plan_id=
|
|
661
|
+
self.control_implementation_id_map = regscale_models.ControlImplementation.get_control_label_map_by_parent(
|
|
662
|
+
parent_id=self.plan_id, parent_module=self.parent_module
|
|
660
663
|
)
|
|
661
664
|
self.control_map = {v: k for k, v in self.control_implementation_id_map.items()}
|
|
662
665
|
self.existing_issue_ids_by_implementation_map = regscale_models.Issue.get_open_issues_ids_by_implementation_id(
|
|
663
|
-
plan_id=plan_id
|
|
666
|
+
plan_id=self.plan_id, is_component=self.is_component
|
|
664
667
|
) # GraphQL Call
|
|
665
|
-
self.control_id_to_implementation_map = regscale_models.ControlImplementation.
|
|
666
|
-
plan_id=
|
|
668
|
+
self.control_id_to_implementation_map = regscale_models.ControlImplementation.get_control_id_map_by_parent(
|
|
669
|
+
parent_id=self.plan_id, parent_module=self.parent_module
|
|
667
670
|
)
|
|
671
|
+
|
|
668
672
|
self.cci_to_control_map: ThreadSafeDict[str, set[int]] = ThreadSafeDict()
|
|
669
673
|
self._no_ccis: bool = False
|
|
670
674
|
self.cci_to_control_map_lock: threading.Lock = threading.Lock()
|
|
@@ -800,11 +804,7 @@ class ScannerIntegration(ABC):
|
|
|
800
804
|
getattr(x, self.asset_identifier_field): x
|
|
801
805
|
for x in regscale_models.Asset.get_all_by_parent(
|
|
802
806
|
parent_id=self.plan_id,
|
|
803
|
-
parent_module=
|
|
804
|
-
regscale_models.Component.get_module_string()
|
|
805
|
-
if self.is_component
|
|
806
|
-
else regscale_models.SecurityPlan.get_module_string()
|
|
807
|
-
),
|
|
807
|
+
parent_module=self.parent_module,
|
|
808
808
|
)
|
|
809
809
|
}
|
|
810
810
|
|
|
@@ -817,7 +817,7 @@ class ScannerIntegration(ABC):
|
|
|
817
817
|
"""
|
|
818
818
|
all_issues = regscale_models.Issue.get_all_by_parent(
|
|
819
819
|
parent_id=self.plan_id,
|
|
820
|
-
parent_module=
|
|
820
|
+
parent_module=self.parent_module,
|
|
821
821
|
)
|
|
822
822
|
return {issue.integrationFindingId: issue for issue in all_issues}
|
|
823
823
|
|
|
@@ -1094,11 +1094,7 @@ class ScannerIntegration(ABC):
|
|
|
1094
1094
|
otherTrackingNumber=asset.other_tracking_number or asset.identifier,
|
|
1095
1095
|
assetOwnerId=asset.asset_owner_id or "Unknown",
|
|
1096
1096
|
parentId=component.id if component else self.plan_id,
|
|
1097
|
-
parentModule=
|
|
1098
|
-
regscale_models.Component.get_module_string()
|
|
1099
|
-
if component or self.is_component
|
|
1100
|
-
else regscale_models.SecurityPlan.get_module_string()
|
|
1101
|
-
),
|
|
1097
|
+
parentModule=self.parent_module,
|
|
1102
1098
|
assetType=asset.asset_type,
|
|
1103
1099
|
dateLastUpdated=asset.date_last_updated or get_current_datetime(),
|
|
1104
1100
|
status=asset.status,
|
|
@@ -1324,9 +1320,7 @@ class ScannerIntegration(ABC):
|
|
|
1324
1320
|
|
|
1325
1321
|
:rtype: None
|
|
1326
1322
|
"""
|
|
1327
|
-
regscale_models.Asset.get_all_by_parent(
|
|
1328
|
-
parent_id=self.plan_id, parent_module=regscale_models.SecurityPlan.get_module_string()
|
|
1329
|
-
)
|
|
1323
|
+
regscale_models.Asset.get_all_by_parent(parent_id=self.plan_id, parent_module=self.parent_module)
|
|
1330
1324
|
|
|
1331
1325
|
def _create_process_function(self, loading_assets: TaskID) -> Callable[[IntegrationAsset], bool]:
|
|
1332
1326
|
"""
|
|
@@ -1600,11 +1594,7 @@ class ScannerIntegration(ABC):
|
|
|
1600
1594
|
|
|
1601
1595
|
# Update all fields
|
|
1602
1596
|
issue.parentId = self.plan_id
|
|
1603
|
-
issue.parentModule =
|
|
1604
|
-
regscale_models.Component.get_module_string()
|
|
1605
|
-
if self.is_component
|
|
1606
|
-
else regscale_models.SecurityPlan.get_module_string()
|
|
1607
|
-
)
|
|
1597
|
+
issue.parentModule = self.parent_module
|
|
1608
1598
|
issue.vulnerabilityId = finding.vulnerability_id
|
|
1609
1599
|
issue.title = issue_title
|
|
1610
1600
|
issue.dateCreated = finding.date_created
|
|
@@ -2159,7 +2149,7 @@ class ScannerIntegration(ABC):
|
|
|
2159
2149
|
# Get all existing POAM IDs and find the maximum
|
|
2160
2150
|
issues: List[regscale_models.Issue] = regscale_models.Issue.get_all_by_parent(
|
|
2161
2151
|
parent_id=self.plan_id,
|
|
2162
|
-
parent_module=
|
|
2152
|
+
parent_module=self.parent_module,
|
|
2163
2153
|
)
|
|
2164
2154
|
self._max_poam_id = max(
|
|
2165
2155
|
(
|
|
@@ -2184,11 +2174,7 @@ class ScannerIntegration(ABC):
|
|
|
2184
2174
|
"""
|
|
2185
2175
|
scan_history = regscale_models.ScanHistory(
|
|
2186
2176
|
parentId=self.plan_id,
|
|
2187
|
-
parentModule=
|
|
2188
|
-
regscale_models.Component.get_module_string()
|
|
2189
|
-
if self.is_component
|
|
2190
|
-
else regscale_models.SecurityPlan.get_module_string()
|
|
2191
|
-
),
|
|
2177
|
+
parentModule=self.parent_module,
|
|
2192
2178
|
scanningTool=self.title,
|
|
2193
2179
|
scanDate=self.scan_date if self.scan_date else get_current_datetime(),
|
|
2194
2180
|
createdById=self.assessor_id,
|
|
@@ -2309,11 +2295,7 @@ class ScannerIntegration(ABC):
|
|
|
2309
2295
|
description=finding.description,
|
|
2310
2296
|
dateLastUpdated=finding.date_last_updated,
|
|
2311
2297
|
parentId=self.plan_id,
|
|
2312
|
-
parentModule=
|
|
2313
|
-
regscale_models.Component.get_module_string()
|
|
2314
|
-
if self.is_component
|
|
2315
|
-
else regscale_models.SecurityPlan.get_module_string()
|
|
2316
|
-
),
|
|
2298
|
+
parentModule=self.parent_module,
|
|
2317
2299
|
dns=asset.fqdn or "unknown",
|
|
2318
2300
|
status=regscale_models.VulnerabilityStatus.Open,
|
|
2319
2301
|
ipAddress=finding.ip_address or asset.ipAddress or "",
|
|
@@ -2424,7 +2406,7 @@ class ScannerIntegration(ABC):
|
|
|
2424
2406
|
|
|
2425
2407
|
# Get all vulnerabilities for this security plan
|
|
2426
2408
|
all_vulnerabilities: list[regscale_models.Vulnerability] = regscale_models.Vulnerability.get_all_by_parent(
|
|
2427
|
-
parent_id=self.plan_id, parent_module=
|
|
2409
|
+
parent_id=self.plan_id, parent_module=self.parent_module
|
|
2428
2410
|
)
|
|
2429
2411
|
|
|
2430
2412
|
# Pre-filter vulnerabilities that are not in current set
|
|
@@ -1,9 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"title": "CISA Catalog of Known Exploited Vulnerabilities",
|
|
3
|
-
"catalogVersion": "2025.07.
|
|
4
|
-
"dateReleased": "2025-07-
|
|
5
|
-
"count":
|
|
3
|
+
"catalogVersion": "2025.07.28",
|
|
4
|
+
"dateReleased": "2025-07-28T14:00:14.6746Z",
|
|
5
|
+
"count": 1391,
|
|
6
6
|
"vulnerabilities": [
|
|
7
|
+
{
|
|
8
|
+
"cveID": "CVE-2023-2533",
|
|
9
|
+
"vendorProject": "PaperCut",
|
|
10
|
+
"product": "NG\/MF",
|
|
11
|
+
"vulnerabilityName": "PaperCut NG\/MF Cross-Site Request Forgery (CSRF) Vulnerability",
|
|
12
|
+
"dateAdded": "2025-07-28",
|
|
13
|
+
"shortDescription": "PaperCut NG\/MF contains a cross-site request forgery (CSRF) vulnerability, which, under specific conditions, could potentially enable an attacker to alter security settings or execute arbitrary code. ",
|
|
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-08-18",
|
|
16
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
17
|
+
"notes": "https:\/\/www.papercut.com\/kb\/Main\/SecurityBulletinJune2023 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2023-2533",
|
|
18
|
+
"cwes": [
|
|
19
|
+
"CWE-352"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"cveID": "CVE-2025-20337",
|
|
24
|
+
"vendorProject": "Cisco",
|
|
25
|
+
"product": "Identity Services Engine",
|
|
26
|
+
"vulnerabilityName": "Cisco Identity Services Engine Injection Vulnerability",
|
|
27
|
+
"dateAdded": "2025-07-28",
|
|
28
|
+
"shortDescription": "Cisco Identity Services Engine contains an injection vulnerability in a specific API of Cisco ISE and Cisco ISE-PIC due to insufficient validation of user-supplied input allowing an attacker to exploit this vulnerability by submitting a crafted API request. Successful exploitation could allow an attacker to perform remote code execution and obtaining root privileges on an affected device.",
|
|
29
|
+
"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.",
|
|
30
|
+
"dueDate": "2025-08-18",
|
|
31
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
32
|
+
"notes": "https:\/\/sec.cloudapps.cisco.com\/security\/center\/content\/CiscoSecurityAdvisory\/cisco-sa-ise-unauth-rce-ZAd2GnJ6 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-20337",
|
|
33
|
+
"cwes": [
|
|
34
|
+
"CWE-74"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"cveID": "CVE-2025-20281",
|
|
39
|
+
"vendorProject": "Cisco",
|
|
40
|
+
"product": "Identity Services Engine",
|
|
41
|
+
"vulnerabilityName": "Cisco Identity Services Engine Injection Vulnerability",
|
|
42
|
+
"dateAdded": "2025-07-28",
|
|
43
|
+
"shortDescription": "Cisco Identity Services Engine contains an injection vulnerability in a specific API of Cisco ISE and Cisco ISE-PIC due to insufficient validation of user-supplied input allowing an attacker to exploit this vulnerability by submitting a crafted API request. Successful exploitation could allow an attacker to perform remote code execution and obtaining root privileges on an affected device.",
|
|
44
|
+
"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.",
|
|
45
|
+
"dueDate": "2025-08-18",
|
|
46
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
47
|
+
"notes": "https:\/\/sec.cloudapps.cisco.com\/security\/center\/content\/CiscoSecurityAdvisory\/cisco-sa-ise-unauth-rce-ZAd2GnJ6 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-20281",
|
|
48
|
+
"cwes": [
|
|
49
|
+
"CWE-74"
|
|
50
|
+
]
|
|
51
|
+
},
|
|
7
52
|
{
|
|
8
53
|
"cveID": "CVE-2025-2775",
|
|
9
54
|
"vendorProject": "SysAid",
|
|
@@ -73,7 +118,7 @@
|
|
|
73
118
|
"shortDescription": "Microsoft SharePoint contains a code injection vulnerability that could allow an authorized attacker to execute code over a network. This vulnerability could be chained with CVE-2025-49706. The update for CVE-2025-53770 includes more robust protections than the update for CVE-2025-49704.",
|
|
74
119
|
"requiredAction": "CISA recommends disconnecting public-facing versions of SharePoint Server that have reached their end-of-life (EOL) or end-of-service (EOS). For example, SharePoint Server 2013 and earlier versions are end-of-life and should be discontinued if still in use. For supported versions, please follow the mitigations according to CISA and vendor instructions. Adhere to the applicable BOD 22-01 guidance for cloud services or discontinue use of the product if mitigations are not available.",
|
|
75
120
|
"dueDate": "2025-07-23",
|
|
76
|
-
"knownRansomwareCampaignUse": "
|
|
121
|
+
"knownRansomwareCampaignUse": "Known",
|
|
77
122
|
"notes": "CISA Mitigation Instructions: https:\/\/www.cisa.gov\/news-events\/alerts\/2025\/07\/20\/microsoft-releases-guidance-exploitation-sharepoint-vulnerability-cve-2025-53770; https:\/\/www.microsoft.com\/en-us\/security\/blog\/2025\/07\/22\/disrupting-active-exploitation-of-on-premises-sharepoint-vulnerabilities\/ ; https:\/\/msrc.microsoft.com\/update-guide\/vulnerability\/CVE-2025-49704 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-49704",
|
|
78
123
|
"cwes": [
|
|
79
124
|
"CWE-94"
|
|
@@ -88,8 +133,8 @@
|
|
|
88
133
|
"shortDescription": "Microsoft SharePoint contains an improper authentication vulnerability that allows an authorized attacker to perform spoofing over a network. Successfully exploitation could allow an attacker to view sensitive information and make some changes to disclosed information. This vulnerability could be chained with CVE-2025-49704. The update for CVE-2025-53771 includes more robust protections than the update for CVE-2025-49706.",
|
|
89
134
|
"requiredAction": "CISA recommends disconnecting public-facing versions of SharePoint Server that have reached their end-of-life (EOL) or end-of-service (EOS). For example, SharePoint Server 2013 and earlier versions are end-of-life and should be discontinued if still in use. For supported versions, please follow the mitigations according to CISA and vendor instructions. Adhere to the applicable BOD 22-01 guidance for cloud services or discontinue use of the product if mitigations are not available.",
|
|
90
135
|
"dueDate": "2025-07-23",
|
|
91
|
-
"knownRansomwareCampaignUse": "
|
|
92
|
-
"notes": "CISA Mitigation Instructions: https:\/\/www.cisa.gov\/news-events\/alerts\/2025\/07\/20\/microsoft-releases-guidance-exploitation-sharepoint-vulnerability-cve-2025-53770; https:\/\/www.microsoft.com\/en-us\/security\/blog\/2025\/07\/22\/disrupting-active-exploitation-of-on-premises-sharepoint-vulnerabilities\/ ; https:\/\/msrc.microsoft.com\/update-guide\/vulnerability\/CVE-2025-49706 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-49706",
|
|
136
|
+
"knownRansomwareCampaignUse": "Known",
|
|
137
|
+
"notes": "CISA Mitigation Instructions: https:\/\/www.cisa.gov\/news-events\/alerts\/2025\/07\/20\/microsoft-releases-guidance-exploitation-sharepoint-vulnerability-cve-2025-53770 ; https:\/\/www.microsoft.com\/en-us\/security\/blog\/2025\/07\/22\/disrupting-active-exploitation-of-on-premises-sharepoint-vulnerabilities\/ ; https:\/\/msrc.microsoft.com\/update-guide\/vulnerability\/CVE-2025-49706 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-49706",
|
|
93
138
|
"cwes": [
|
|
94
139
|
"CWE-287"
|
|
95
140
|
]
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
"""Container Scan Abstract"""
|
|
2
2
|
|
|
3
3
|
import ast
|
|
4
|
-
import csv
|
|
5
4
|
import json
|
|
6
5
|
import logging
|
|
7
6
|
import re
|
|
8
7
|
import shutil
|
|
9
8
|
from abc import ABC, abstractmethod
|
|
10
9
|
from collections import namedtuple
|
|
11
|
-
from datetime import datetime
|
|
10
|
+
from datetime import datetime
|
|
12
11
|
from os import PathLike
|
|
13
12
|
from typing import TYPE_CHECKING, Any, Callable, Generator, Iterator, List, Optional, Sequence, TextIO, Tuple, Union
|
|
14
13
|
|
|
@@ -18,7 +17,6 @@ if TYPE_CHECKING:
|
|
|
18
17
|
from pathlib import Path
|
|
19
18
|
|
|
20
19
|
import click
|
|
21
|
-
import requests
|
|
22
20
|
import xmltodict
|
|
23
21
|
from openpyxl.reader.excel import load_workbook
|
|
24
22
|
|
|
@@ -32,11 +30,10 @@ from regscale.core.app.utils.app_utils import (
|
|
|
32
30
|
get_current_datetime,
|
|
33
31
|
)
|
|
34
32
|
from regscale.core.app.utils.parser_utils import safe_datetime_str
|
|
35
|
-
from regscale.core.app.utils.report_utils import ReportGenerator
|
|
36
33
|
from regscale.integrations.scanner_integration import ScannerIntegration
|
|
37
34
|
from regscale.models import IssueStatus, Metadata, regscale_models
|
|
38
35
|
from regscale.models.app_models.mapping import Mapping
|
|
39
|
-
from regscale.models.regscale_models import Asset, File,
|
|
36
|
+
from regscale.models.regscale_models import Asset, File, Vulnerability
|
|
40
37
|
|
|
41
38
|
logger = logging.getLogger(__name__)
|
|
42
39
|
|
|
@@ -74,6 +71,7 @@ class FlatFileIntegration(ScannerIntegration):
|
|
|
74
71
|
"Low": regscale_models.IssueSeverity.Low,
|
|
75
72
|
}
|
|
76
73
|
super().__init__(plan_id=plan_id, **kwargs)
|
|
74
|
+
self.is_component = kwargs.get("is_component", False)
|
|
77
75
|
|
|
78
76
|
def set_asset_identifier_field(self, asset_identifier_field: str) -> None:
|
|
79
77
|
"""
|
|
@@ -130,10 +128,16 @@ class FlatFileImporter(ABC):
|
|
|
130
128
|
"Medium": regscale_models.IssueSeverity.Moderate,
|
|
131
129
|
"Low": regscale_models.IssueSeverity.Low,
|
|
132
130
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
kwargs["
|
|
131
|
+
|
|
132
|
+
# Set the parent_id, parent_module, and plan_id if they are not provided
|
|
133
|
+
if "parent_id" not in kwargs and "object_id" in kwargs:
|
|
134
|
+
kwargs["parent_id"] = kwargs["object_id"]
|
|
135
|
+
kwargs["plan_id"] = kwargs["object_id"]
|
|
136
|
+
if kwargs.get("is_component", False):
|
|
137
|
+
kwargs["parent_module"] = regscale_models.Component.get_module_string()
|
|
138
|
+
else:
|
|
139
|
+
kwargs["parent_module"] = regscale_models.SecurityPlan.get_module_string()
|
|
140
|
+
|
|
137
141
|
if "app" not in kwargs:
|
|
138
142
|
kwargs["app"] = Application()
|
|
139
143
|
# empty generator
|
|
@@ -156,7 +160,8 @@ class FlatFileImporter(ABC):
|
|
|
156
160
|
"mapping",
|
|
157
161
|
"ignore_validation",
|
|
158
162
|
"header_line_number",
|
|
159
|
-
"
|
|
163
|
+
"is_component",
|
|
164
|
+
"object_id",
|
|
160
165
|
"plan_id",
|
|
161
166
|
"disable_mapping",
|
|
162
167
|
"mappings_path",
|
|
@@ -188,7 +193,8 @@ class FlatFileImporter(ABC):
|
|
|
188
193
|
}
|
|
189
194
|
self.create_epoch = str(int(creation_date(self.attributes.file_path)))
|
|
190
195
|
flat_int = FlatFileIntegration(
|
|
191
|
-
plan_id=self.attributes.plan_id or self.attributes.
|
|
196
|
+
plan_id=self.attributes.plan_id or self.attributes.object_id or self.attributes.parent_id,
|
|
197
|
+
is_component=self.attributes.is_component,
|
|
192
198
|
asset_identifier_field=self.asset_identifier_field,
|
|
193
199
|
finding_severity_map=self.finding_severity_map,
|
|
194
200
|
)
|
|
@@ -206,13 +212,15 @@ class FlatFileImporter(ABC):
|
|
|
206
212
|
elif isinstance(self.data["vulns"], list):
|
|
207
213
|
flat_int.num_findings_to_process = len(self.data["vulns"])
|
|
208
214
|
flat_int.sync_assets(
|
|
209
|
-
plan_id=self.attributes.
|
|
215
|
+
plan_id=self.attributes.plan_id,
|
|
216
|
+
is_component=self.attributes.is_component,
|
|
210
217
|
integration_assets=self.integration_assets,
|
|
211
218
|
title=self.attributes.name,
|
|
212
219
|
asset_count=flat_int.num_assets_to_process,
|
|
213
220
|
)
|
|
214
221
|
flat_int.sync_findings(
|
|
215
|
-
plan_id=self.attributes.
|
|
222
|
+
plan_id=self.attributes.plan_id,
|
|
223
|
+
is_component=self.attributes.is_component,
|
|
216
224
|
integration_findings=self.integration_findings,
|
|
217
225
|
title=self.attributes.name,
|
|
218
226
|
finding_count=flat_int.num_findings_to_process,
|
|
@@ -319,7 +327,7 @@ class FlatFileImporter(ABC):
|
|
|
319
327
|
asset_type=asset.assetType,
|
|
320
328
|
asset_owner_id=asset.assetOwnerId,
|
|
321
329
|
parent_id=self.attributes.parent_id,
|
|
322
|
-
parent_module=
|
|
330
|
+
parent_module=self.attributes.parent_module,
|
|
323
331
|
asset_category=asset.assetCategory,
|
|
324
332
|
date_last_updated=asset.dateLastUpdated,
|
|
325
333
|
status=asset.status,
|
|
@@ -651,7 +659,7 @@ class FlatFileImporter(ABC):
|
|
|
651
659
|
import_name: str,
|
|
652
660
|
file_types: Union[str, list[str]],
|
|
653
661
|
folder_path: PathLike[str],
|
|
654
|
-
|
|
662
|
+
object_id: int,
|
|
655
663
|
scan_date: datetime,
|
|
656
664
|
mappings_path: Union[PathLike[str], Path],
|
|
657
665
|
disable_mapping: bool,
|
|
@@ -668,7 +676,7 @@ class FlatFileImporter(ABC):
|
|
|
668
676
|
:param str import_name: The name of the import type
|
|
669
677
|
:param Union[str, list[str]] file_types: The file types to glob and import, e.g. ".csv" or [".csv", ".xlsx"]
|
|
670
678
|
:param PathLike[str] folder_path: The folder path to import from
|
|
671
|
-
:param int
|
|
679
|
+
:param int object_id: The RegScale SSP ID
|
|
672
680
|
:param datetime scan_date: The date of the scan
|
|
673
681
|
:param Union[PathLike[str], Path] mappings_path: The path to the mappings file
|
|
674
682
|
:param bool disable_mapping: Whether to disable custom mappings
|
|
@@ -685,9 +693,16 @@ class FlatFileImporter(ABC):
|
|
|
685
693
|
if s3_bucket:
|
|
686
694
|
download_from_s3(s3_bucket, s3_prefix, folder_path, aws_profile)
|
|
687
695
|
app = Application()
|
|
688
|
-
|
|
689
|
-
|
|
696
|
+
|
|
697
|
+
# Validate the parent_id is a valid RegScale object
|
|
698
|
+
is_component = kwargs.get("is_component", False)
|
|
699
|
+
if is_component and not validate_regscale_object(object_id, "components"):
|
|
700
|
+
app.logger.warning("Component #%i is not a valid RegScale Component.", object_id)
|
|
701
|
+
return
|
|
702
|
+
elif not is_component and not validate_regscale_object(object_id, "securityplans"):
|
|
703
|
+
app.logger.warning("SSP #%i is not a valid RegScale Security Plan.", object_id)
|
|
690
704
|
return
|
|
705
|
+
|
|
691
706
|
if not scan_date or not FlatFileImporter.check_date_format(scan_date):
|
|
692
707
|
scan_date = datetime.now()
|
|
693
708
|
if isinstance(file_types, str):
|
|
@@ -705,7 +720,7 @@ class FlatFileImporter(ABC):
|
|
|
705
720
|
import_type(
|
|
706
721
|
name=import_name,
|
|
707
722
|
file_path=str(file),
|
|
708
|
-
|
|
723
|
+
object_id=object_id,
|
|
709
724
|
scan_date=scan_date,
|
|
710
725
|
mappings_path=mappings_path,
|
|
711
726
|
disable_mapping=disable_mapping,
|
|
@@ -554,8 +554,14 @@ class SendReminders:
|
|
|
554
554
|
)
|
|
555
555
|
|
|
556
556
|
# update api pool limits to max_thread count from init.yaml
|
|
557
|
-
|
|
558
|
-
|
|
557
|
+
max_threads = config.get("maxThreads", 100)
|
|
558
|
+
if not isinstance(max_threads, int):
|
|
559
|
+
try:
|
|
560
|
+
max_threads = int(max_threads)
|
|
561
|
+
except (ValueError, TypeError):
|
|
562
|
+
max_threads = 100
|
|
563
|
+
api.pool_connections = max_threads
|
|
564
|
+
api.pool_maxsize = max_threads
|
|
559
565
|
|
|
560
566
|
# get assigned threads
|
|
561
567
|
for i in range(len(threads)):
|