From abd5fc181f4892a8e3de048028eb09c5a05ba466 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Thu, 12 Jun 2025 16:45:05 +0200 Subject: [PATCH] fix(export): add name sanitization (#8012) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Adrián Jesús Peña Rodríguez --- api/CHANGELOG.md | 7 +++++++ api/pyproject.toml | 2 +- api/src/backend/api/specs/v1.yaml | 2 +- api/src/backend/api/v1/views.py | 2 +- api/src/backend/tasks/jobs/export.py | 8 ++++++-- api/src/backend/tasks/tests/test_export.py | 19 +++++++++++++++++++ 6 files changed, 35 insertions(+), 5 deletions(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 885d856202..6ca3c69223 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to the **Prowler API** are documented in this file. +## [v1.8.5] (Prowler v5.7.5) + +### Fixed +- Normalize provider UID to ensure safe and unique export directory paths [(#8007)](https://github.com/prowler-cloud/prowler/pull/8007). + +--- + ## [v1.8.4] (Prowler v5.7.4) ### Removed diff --git a/api/pyproject.toml b/api/pyproject.toml index d519c2510c..08b9a1660f 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -35,7 +35,7 @@ name = "prowler-api" package-mode = false # Needed for the SDK compatibility requires-python = ">=3.11,<3.13" -version = "1.8.4" +version = "1.8.5" [project.scripts] celery = "src.backend.config.settings.celery" diff --git a/api/src/backend/api/specs/v1.yaml b/api/src/backend/api/specs/v1.yaml index d2f071f627..4f1ad1016d 100644 --- a/api/src/backend/api/specs/v1.yaml +++ b/api/src/backend/api/specs/v1.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: Prowler API - version: 1.8.4 + version: 1.8.5 description: |- Prowler API specification. diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 78fcdff87b..d4d70c6477 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -260,7 +260,7 @@ class SchemaView(SpectacularAPIView): def get(self, request, *args, **kwargs): spectacular_settings.TITLE = "Prowler API" - spectacular_settings.VERSION = "1.8.4" + spectacular_settings.VERSION = "1.8.5" spectacular_settings.DESCRIPTION = ( "Prowler API specification.\n\nThis file is auto-generated." ) diff --git a/api/src/backend/tasks/jobs/export.py b/api/src/backend/tasks/jobs/export.py index 2bda9d6def..3525da2425 100644 --- a/api/src/backend/tasks/jobs/export.py +++ b/api/src/backend/tasks/jobs/export.py @@ -1,4 +1,5 @@ import os +import re import zipfile import boto3 @@ -238,15 +239,18 @@ def _generate_output_directory( '/tmp/tenant-1234/aws/scan-5678/prowler-output-2023-02-15T12:34:56', '/tmp/tenant-1234/aws/scan-5678/compliance/prowler-output-2023-02-15T12:34:56' """ + # Sanitize the prowler provider name to ensure it is a valid directory name + prowler_provider_sanitized = re.sub(r"[^\w\-]", "-", prowler_provider) + path = ( f"{output_directory}/{tenant_id}/{scan_id}/prowler-output-" - f"{prowler_provider}-{output_file_timestamp}" + f"{prowler_provider_sanitized}-{output_file_timestamp}" ) os.makedirs("/".join(path.split("/")[:-1]), exist_ok=True) compliance_path = ( f"{output_directory}/{tenant_id}/{scan_id}/compliance/prowler-output-" - f"{prowler_provider}-{output_file_timestamp}" + f"{prowler_provider_sanitized}-{output_file_timestamp}" ) os.makedirs("/".join(compliance_path.split("/")[:-1]), exist_ok=True) diff --git a/api/src/backend/tasks/tests/test_export.py b/api/src/backend/tasks/tests/test_export.py index 6811fe7449..f113d22f17 100644 --- a/api/src/backend/tasks/tests/test_export.py +++ b/api/src/backend/tasks/tests/test_export.py @@ -145,3 +145,22 @@ class TestOutputs: assert path.endswith(f"{provider}-{output_file_timestamp}") assert compliance.endswith(f"{provider}-{output_file_timestamp}") + + def test_generate_output_directory_invalid_character(self, tmpdir): + from prowler.config.config import output_file_timestamp + + base_tmp = Path(str(tmpdir.mkdir("generate_output"))) + base_dir = str(base_tmp) + tenant_id = "t1" + scan_id = "s1" + provider = "aws/test@check" + + path, compliance = _generate_output_directory( + base_dir, provider, tenant_id, scan_id + ) + + assert os.path.isdir(os.path.dirname(path)) + assert os.path.isdir(os.path.dirname(compliance)) + + assert path.endswith(f"aws-test-check-{output_file_timestamp}") + assert compliance.endswith(f"aws-test-check-{output_file_timestamp}")