From 52f98f1704461fc7f4fcaddf2592d3accd996fc6 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Thu, 12 Feb 2026 13:04:35 +0100 Subject: [PATCH 01/12] chore(ci): update org members list in PR labeler (#10053) --- .github/workflows/labeler.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index ac78619549..1f44080229 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -51,18 +51,16 @@ jobs: "amitsharm" "andoniaf" "cesararroba" - "Chan9390" "danibarranqueroo" "HugoPBrito" "jfagoagas" "josema-xyz" "lydiavilchez" "mmuller88" - "MrCloudSec" + # "MrCloudSec" "pedrooot" "prowler-bot" "puchy22" - "rakan-pro" "RosaRivasProwler" "StylusFrost" "toniblyx" From f55983a77d3fade524232ddddfb332e70db71774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Thu, 12 Feb 2026 13:10:59 +0100 Subject: [PATCH 02/12] feat(compliance): add csa ccm 4.0 for the aws provider (#10018) --- api/CHANGELOG.md | 1 + api/src/backend/tasks/jobs/export.py | 2 + dashboard/compliance/csa_ccm_4_0_aws.py | 31 + prowler/CHANGELOG.md | 1 + prowler/__main__.py | 13 + prowler/compliance/aws/csa_ccm_4.0_aws.json | 7604 +++++++++++++++++ prowler/lib/check/compliance_models.py | 13 + prowler/lib/outputs/compliance/compliance.py | 10 + .../lib/outputs/compliance/csa/__init__.py | 0 prowler/lib/outputs/compliance/csa/csa.py | 101 + prowler/lib/outputs/compliance/csa/csa_aws.py | 96 + prowler/lib/outputs/compliance/csa/models.py | 30 + ui/CHANGELOG.md | 1 + .../compliance/[compliancetitle]/page.tsx | 12 +- .../compliance-custom-details/csa-details.tsx | 93 + .../icons/compliance/IconCompliance.tsx | 2 + ui/components/icons/compliance/csa.svg | 1 + ui/lib/compliance/compliance-mapper.ts | 14 + ui/lib/compliance/csa.tsx | 143 + ui/types/compliance.ts | 13 + 20 files changed, 8176 insertions(+), 5 deletions(-) create mode 100644 dashboard/compliance/csa_ccm_4_0_aws.py create mode 100644 prowler/compliance/aws/csa_ccm_4.0_aws.json create mode 100644 prowler/lib/outputs/compliance/csa/__init__.py create mode 100644 prowler/lib/outputs/compliance/csa/csa.py create mode 100644 prowler/lib/outputs/compliance/csa/csa_aws.py create mode 100644 prowler/lib/outputs/compliance/csa/models.py create mode 100644 ui/components/compliance/compliance-custom-details/csa-details.tsx create mode 100644 ui/components/icons/compliance/csa.svg create mode 100644 ui/lib/compliance/csa.tsx diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 6f0cc8b484..1b57de2998 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the **Prowler API** are documented in this file. - Attack Paths: Queries definition now has short description and attribution [(#9983)](https://github.com/prowler-cloud/prowler/pull/9983) - Attack Paths: Internet node is created while scan [(#9992)](https://github.com/prowler-cloud/prowler/pull/9992) +- Support CSA CCM for the AWS provider [(#10018)](https://github.com/prowler-cloud/prowler/pull/10018) --- diff --git a/api/src/backend/tasks/jobs/export.py b/api/src/backend/tasks/jobs/export.py index 883d7d0dbe..c652095fba 100644 --- a/api/src/backend/tasks/jobs/export.py +++ b/api/src/backend/tasks/jobs/export.py @@ -35,6 +35,7 @@ from prowler.lib.outputs.compliance.cis.cis_github import GithubCIS from prowler.lib.outputs.compliance.cis.cis_kubernetes import KubernetesCIS from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS from prowler.lib.outputs.compliance.cis.cis_oraclecloud import OracleCloudCIS +from prowler.lib.outputs.compliance.csa.csa_aws import AWSCSA from prowler.lib.outputs.compliance.ens.ens_aws import AWSENS from prowler.lib.outputs.compliance.ens.ens_azure import AzureENS from prowler.lib.outputs.compliance.ens.ens_gcp import GCPENS @@ -90,6 +91,7 @@ COMPLIANCE_CLASS_MAP = { (lambda name: name == "prowler_threatscore_aws", ProwlerThreatScoreAWS), (lambda name: name == "ccc_aws", CCC_AWS), (lambda name: name.startswith("c5_"), AWSC5), + (lambda name: name.startswith("csa_"), AWSCSA), ], "azure": [ (lambda name: name.startswith("cis_"), AzureCIS), diff --git a/dashboard/compliance/csa_ccm_4_0_aws.py b/dashboard/compliance/csa_ccm_4_0_aws.py new file mode 100644 index 0000000000..346576729d --- /dev/null +++ b/dashboard/compliance/csa_ccm_4_0_aws.py @@ -0,0 +1,31 @@ +import warnings + +from dashboard.common_methods import get_section_containers_kisa_ismsp + +warnings.filterwarnings("ignore") + + +def get_table(data): + data["REQUIREMENTS_ID"] = ( + data["REQUIREMENTS_ID"] + " - " + data["REQUIREMENTS_DESCRIPTION"] + ) + + data["REQUIREMENTS_ID"] = data["REQUIREMENTS_ID"].apply( + lambda x: x[:150] + "..." if len(str(x)) > 150 else x + ) + + aux = data[ + [ + "REQUIREMENTS_ID", + "REQUIREMENTS_ATTRIBUTES_SECTION", + "CHECKID", + "STATUS", + "REGION", + "ACCOUNTID", + "RESOURCEID", + ] + ].copy() + + return get_section_containers_kisa_ismsp( + aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID" + ) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index ee032f4392..a28b648618 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - `defender_safe_attachments_policy_enabled` check for M365 provider [(#9833)](https://github.com/prowler-cloud/prowler/pull/9833) - `defender_safelinks_policy_enabled` check for M365 provider [(#9832)](https://github.com/prowler-cloud/prowler/pull/9832) - AI Skills: Added a skill for creating new Attack Paths queries in openCypher, compatible with Neo4j and Neptune [(#9975)](https://github.com/prowler-cloud/prowler/pull/9975) +- CSA CCM 4.0 for the AWS provider [(#10018)](https://github.com/prowler-cloud/prowler/pull/10018) ### 🔄 Changed diff --git a/prowler/__main__.py b/prowler/__main__.py index fd7869193b..a9344ec433 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -65,6 +65,7 @@ from prowler.lib.outputs.compliance.cis.cis_kubernetes import KubernetesCIS from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS from prowler.lib.outputs.compliance.cis.cis_oraclecloud import OracleCloudCIS from prowler.lib.outputs.compliance.compliance import display_compliance_table +from prowler.lib.outputs.compliance.csa.csa_aws import AWSCSA from prowler.lib.outputs.compliance.ens.ens_aws import AWSENS from prowler.lib.outputs.compliance.ens.ens_azure import AzureENS from prowler.lib.outputs.compliance.ens.ens_gcp import GCPENS @@ -626,6 +627,18 @@ def prowler(): ) generated_outputs["compliance"].append(c5) c5.batch_write_data_to_file() + elif compliance_name == "csa_ccm_4.0_aws": + filename = ( + f"{output_options.output_directory}/compliance/" + f"{output_options.output_filename}_{compliance_name}.csv" + ) + csa_ccm_4_0_aws = AWSCSA( + findings=finding_outputs, + compliance=bulk_compliance_frameworks[compliance_name], + file_path=filename, + ) + generated_outputs["compliance"].append(csa_ccm_4_0_aws) + csa_ccm_4_0_aws.batch_write_data_to_file() else: filename = ( f"{output_options.output_directory}/compliance/" diff --git a/prowler/compliance/aws/csa_ccm_4.0_aws.json b/prowler/compliance/aws/csa_ccm_4.0_aws.json new file mode 100644 index 0000000000..6d0a019c2b --- /dev/null +++ b/prowler/compliance/aws/csa_ccm_4.0_aws.json @@ -0,0 +1,7604 @@ +{ + "Framework": "CSA-CCM", + "Name": "CSA Cloud Controls Matrix (CCM) v4.0.13", + "Version": "4.0", + "Provider": "AWS", + "Description": "The Cloud Security Alliance (CSA) Cloud Controls Matrix (CCM) is a cybersecurity control framework for cloud computing, composed of 197 control objectives structured in 17 domains covering all key aspects of cloud technology. The CCM can be used as a tool for the systematic assessment of a cloud implementation, and provides guidance on which security controls should be implemented by which actor within the cloud supply chain.", + "Requirements": [ + { + "Id": "A&A-02", + "Description": "Conduct independent audit and assurance assessments according to relevant standards at least annually.", + "Name": "Independent Assessments", + "Attributes": [ + { + "Section": "Audit & Assurance", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC4.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "AAC-02" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.5.2", + "5.2.6" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "AS1.1", + "AS2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.2.1", + "27002: 18.2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.35", + "27001: A.5.36" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CA-2", + "CA-2(1)", + "CA-2(2)", + "CA-7", + "CA-7(1)" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.IM-01" + ] + } + ] + } + ], + "Checks": [ + "securityhub_enabled" + ] + }, + { + "Id": "A&A-04", + "Description": "Verify compliance with all relevant standards, regulations, legal/contractual, and statutory requirements applicable to the audit.", + "Name": "Requirements Compliance", + "Attributes": [ + { + "Section": "Audit & Assurance", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC3.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-01", + "GRM-03" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "7.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "AS1.1", + "AS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 9.3.2", + "27001: A.18.2.2", + "27002: 18.2.2", + "27001: A.18.2.3", + "27002: 18.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 9.3.2", + "27001: A.5.31", + "27001: A.5.32", + "27001: A.5.33", + "27001: A.5.34", + "27001: A.5.36" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CA-1" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-3", + "DE.DP-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.IM-01" + ] + } + ] + } + ], + "Checks": [ + "securityhub_enabled", + "config_recorder_all_regions_enabled" + ] + }, + { + "Id": "AIS-04", + "Description": "Define and implement a SDLC process for application design, development, deployment, and operation in accordance with security requirements defined by the organization.", + "Name": "Secure Application Design and Development", + "Attributes": [ + { + "Section": "Application & Interface Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.8", + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "AIS-01", + "AIS-03" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.3.4", + "5.3.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SD1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.14.1.1", + "27002: 14.1.1", + "27017: 14.1.1", + "27001: A.14.1.2", + "27002: 14.1.2", + "27017: 14.1.2", + "27001: A.14.2.1", + "27002: 14.2.1", + "27017: 14.2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.8", + "27001: A.8.25", + "27001: A.8.26", + "27001: A.8.28" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PL-2", + "PL-8", + "PL-8(1)", + "SA-3", + "SA-3(1)", + "SA-4", + "SA-4(2)", + "SA-4(3)", + "SA-4(8)", + "SA-4(9)", + "SA-5", + "SA-8", + "SA-8(1)-(7)", + "SA-8(9)-(13)", + "SA-8(15)-(20)", + "SA-8(22)", + "SA-8(24)-(28)", + "SA-8(30)-(33)", + "SA-17", + "SA-17(1)-(9)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-6", + "PR.DS-7", + "PR.IP-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "PR.IR-01", + "PR.PS-01", + "PR.PS-02", + "PR.PS-06" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.3" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.2.1", + "6.2.3", + "6.5.2" + ] + } + ] + } + ], + "Checks": [ + "codebuild_project_source_repo_url_no_sensitive_credentials", + "codebuild_project_no_secrets_in_variables" + ] + }, + { + "Id": "AIS-05", + "Description": "Implement a testing strategy, including criteria for acceptance of new information systems, upgrades and new versions, which provides application security assurance and maintains compliance while enabling organizational speed of delivery goals. Automate when applicable and possible.", + "Name": "Automated Application Security Testing", + "Attributes": [ + { + "Section": "Application & Interface Security", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.8", + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "AIS-01", + "AIS-03" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.12", + "16.13" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SD2.3", + "SD2.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.14.2.8", + "27001: A.14.2.9", + "27001: A.12.1.2", + "27002: 12.1.2", + "27001: A.14.1.1", + "27002: 14.1.1", + "27001: A.14.2.2", + "27002: 14.2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.25", + "27001: A.8.29", + "27001: A.8.32", + "27002: 8.25 (e)", + "27002: 8.32 (d)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SA-11", + "SA-11(1)-(9)", + "SI-6", + "SI-6(2)", + "SI-6(3)", + "SI-10", + "SI-10(1)-(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-2", + "PR.PT-3", + "PR.IP-12", + "DE.CM-8" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "ID.RA-01", + "PR.PS-01", + "PR.PS-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "A.3.2.2", + "A.3.2.2.1", + "6.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.2.4", + "6.4.1", + "6.4.2", + "6.5.1" + ] + } + ] + } + ], + "Checks": [ + "inspector2_is_enabled", + "ecr_repositories_scan_vulnerabilities_in_latest_image", + "ecr_registry_scan_images_on_push_enabled" + ] + }, + { + "Id": "AIS-07", + "Description": "Define and implement a process to remediate application security vulnerabilities, automating remediation when possible.", + "Name": "Application Vulnerability Remediation", + "Attributes": [ + { + "Section": "Application & Interface Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.1", + "CC7.4", + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "TVM-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.2", + "16.6" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.16.1.5", + "27002: 16.1.5", + "27017: 16.1.5", + "27001: A.12.6.1", + "27002: 12.6.1", + "27017: 12.6.1", + "27018: 12.6.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.26", + "27001: A.8.8", + "27002: 5.26 (j)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SI-2", + "SI-2(2)-(6)", + "SA-11", + "SA-11(2)", + "SA-15", + "SA-15(1)-(3)", + "SA-15(5)-(8)", + "SA-15(10)-(12)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-2", + "PR.IP-12", + "DE.CM-8", + "RS.AN-5", + "RS.MI-3", + "PR.DS-6" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "ID.RA-01", + "ID.RA-06", + "ID.RA-08", + "PR.PS-02", + "PR.PS-06" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.2", + "6.5", + "6.5.1-10" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.3.1", + "11.3.1", + "11.3.1.1" + ] + } + ] + } + ], + "Checks": [ + "inspector2_is_enabled", + "inspector2_active_findings_exist" + ] + }, + { + "Id": "BCR-08", + "Description": "Periodically backup data stored in the cloud. Ensure the confidentiality, integrity and availability of the backup, and verify data restoration from backup for resiliency.", + "Name": "Backup", + "Attributes": [ + { + "Section": "Business Continuity Management and Operational Resilience", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "A1.2", + "A1.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "BCR-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "11.1", + "11.2", + "11.3", + "11.4", + "11.5" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.8", + "5.2.9" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.3", + "27017: 12.3", + "27018: 12.3.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.13", + "27001: A.5.23", + "27001: A.5.30", + "27002: 8.13", + "27002: 5.23 2nd (i)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-4", + "CP-4(4)", + "CP-6", + "CP-6(1)-(3)", + "CP-9", + "CP-9(1)", + "CP-9(2)", + "CP-10", + "CP-10(2)", + "CP-10(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-4", + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01", + "PR.DS-11", + "RC.RP-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "9.5.1", + "12.10.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.10.1", + "10.3.3" + ] + } + ] + } + ], + "Checks": [ + "backup_plans_exist", + "backup_vaults_exist", + "backup_vaults_encrypted", + "backup_recovery_point_encrypted", + "dynamodb_tables_pitr_enabled", + "dynamodb_table_protected_by_backup_plan", + "ec2_ebs_volume_snapshots_exists", + "ec2_ebs_volume_protected_by_backup_plan", + "efs_have_backup_enabled", + "rds_instance_backup_enabled", + "rds_instance_protected_by_backup_plan", + "rds_cluster_protected_by_backup_plan", + "redshift_cluster_automated_snapshot", + "s3_bucket_object_versioning", + "documentdb_cluster_backup_enabled", + "neptune_cluster_backup_enabled", + "elasticache_redis_cluster_backup_enabled", + "fsx_file_system_copy_tags_to_backups_enabled", + "lightsail_instance_automated_snapshots", + "dlm_ebs_snapshot_lifecycle_policy_exists" + ] + }, + { + "Id": "BCR-09", + "Description": "Establish, document, approve, communicate, apply, evaluate and maintain a disaster response plan to recover from natural and man-made disasters. Update the plan at least annually or upon significant changes.", + "Name": "Disaster Response Plan", + "Attributes": [ + { + "Section": "Business Continuity Management and Operational Resilience", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "A1.2", + "CC3.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.8", + "5.2.9", + "1.6.1", + "1.6.2", + "1.6.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "BC1.4", + "BC2.1", + "BC2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.29", + "27001: A.5.30", + "27002: 5.29", + "27002: 5.30" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-2(1)", + "CP-2(2)", + "CP-2(3)", + "CP-2(5)", + "CP-2(6)", + "CP-2(7)", + "CP-2(8)", + "PE-13", + "PE-13(1)", + "PE-13(2)", + "PE-13(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-9", + "PR.IP-10", + "RC.IM-1", + "RC.IM-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.IM-04" + ] + } + ] + } + ], + "Checks": [ + "drs_job_exist", + "ssmincidents_enabled_with_plans" + ] + }, + { + "Id": "BCR-11", + "Description": "Supplement business-critical equipment with redundant equipment independently located at a reasonable minimum distance in accordance with applicable industry standards.", + "Name": "Equipment Redundancy", + "Attributes": [ + { + "Section": "Business Continuity Management and Operational Resilience", + "CCMLite": "No", + "IaaS": "CSP-Owned", + "PaaS": "CSP-Owned", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "A1.2", + "CC3.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "BCR-06" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.8" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "BC1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.20", + "27001: A.7.11", + "27001: A.8.14", + "27002: 5.20 (t)", + "27002: 8.14 (c)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-2", + "CP-2(2)", + "CP-4(3)", + "CP-6", + "CP-6(1)", + "CP-7", + "CP-8", + "CP-8(1)-(3)", + "CP-9", + "CP-9(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.BE-4", + "ID.BE-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.OC-04", + "GV.OC-05", + "PR.IR-03" + ] + } + ] + } + ], + "Checks": [ + "rds_instance_multi_az", + "rds_cluster_multi_az", + "elbv2_is_in_multiple_az", + "elb_is_in_multiple_az", + "autoscaling_group_multiple_az", + "autoscaling_group_multiple_instance_types", + "ec2_ebs_volume_protected_by_backup_plan", + "elasticache_redis_cluster_multi_az_enabled", + "elasticache_redis_cluster_automatic_failover_enabled", + "opensearch_service_domains_fault_tolerant_data_nodes", + "opensearch_service_domains_fault_tolerant_master_nodes", + "dynamodb_accelerator_cluster_multi_az", + "documentdb_cluster_multi_az_enabled", + "neptune_cluster_multi_az", + "efs_multi_az_enabled", + "vpc_vpn_connection_tunnels_up", + "directconnect_connection_redundancy", + "directconnect_virtual_interface_redundancy", + "networkfirewall_multi_az", + "vpc_endpoint_multi_az_enabled", + "awslambda_function_vpc_multi_az", + "redshift_cluster_multi_az_enabled" + ] + }, + { + "Id": "CCC-04", + "Description": "Restrict the unauthorized addition, removal, update, and management of organization assets.", + "Name": "Unauthorized Change Protection", + "Attributes": [ + { + "Section": "Change Control and Configuration Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "CCC-04" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.1", + "1.3.4", + "5.3.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY2.4", + "SM2.6" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.1.4", + "27002: 12.1.4", + "27001: A.12.4.2", + "27002: 12.4.2", + "27001: A.14.2.2", + "27017: 14.2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.3", + "27001: A.8.4", + "27001: A.8.15", + "27001: A.8.31", + "27001: A.8.32" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CA-7", + "CA-7(4)", + "CM-3", + "CM-3(1)", + "CM-3(5)", + "CM-3(7)", + "CM-3(8)", + "CM-5", + "CM-5(1)", + "CM-5(4)", + "CM-5(5)", + "CM-6", + "CM-6(1)", + "CM-6(2)", + "CM-7", + "CM-7(1)", + "CM-7(4)", + "CM-7(5)", + "CM-7(9)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.AM-1", + "ID.AM-2", + "ID.AM-4", + "PR.MA-1", + "PR.MA-2", + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-01", + "ID.AM-02", + "ID.AM-04", + "ID.AM-08", + "PR.PS-02", + "PR.PS-03", + "PR.PS-05", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.4.5.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.5.1", + "6.5.2" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_multi_region_enabled", + "cloudtrail_log_file_validation_enabled", + "s3_bucket_object_lock", + "cloudwatch_log_metric_filter_aws_organizations_changes", + "servicecatalog_portfolio_shared_within_organization_only" + ] + }, + { + "Id": "CCC-07", + "Description": "Implement detection measures with proactive notification in case of changes deviating from the established baseline.", + "Name": "Detection of Baseline Deviation", + "Attributes": [ + { + "Section": "Change Control and Configuration Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-01" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.5.1", + "1.5.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY2.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.14.2.2", + "27001: A.14.2.4", + "27001: A.12.4.1", + "27002: 12.4.1 (g)", + "27001: A.5.1.1", + "27017: 5.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.9", + "27001: A.8.15", + "27002: 8.9" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-6", + "CM-6(2)", + "SI-2", + "SI-2(2)-(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.MA-1", + "PR.IP-1", + "DE.DP-4", + "PR.IP-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-01", + "DE.CM-09", + "DE.AE-06" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.4.5.3", + "6.4.5.4", + "11.5", + "11.5.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "11.5.2", + "11.6.1" + ] + } + ] + } + ], + "Checks": [ + "config_recorder_all_regions_enabled", + "guardduty_is_enabled", + "securityhub_enabled", + "cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled", + "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", + "cloudwatch_changes_to_network_acls_alarm_configured", + "cloudwatch_changes_to_network_gateways_alarm_configured", + "cloudwatch_changes_to_network_route_tables_alarm_configured", + "cloudwatch_log_metric_filter_authentication_failures", + "cloudwatch_log_metric_filter_aws_organizations_changes", + "cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk" + ] + }, + { + "Id": "CEK-03", + "Description": "Provide cryptographic protection to data at-rest and in-transit, using cryptographic libraries certified to approved standards.", + "Name": "Data Encryption", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-03", + "EKM-04" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.6", + "3.1", + "3.11", + "11.3", + "16.11" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1.1", + "27001: A.18.1.2", + "27001: A.18.1.3", + "27001: A.18.1.4", + "27001: A.18.1.5", + "27001: A.10.1", + "27002: 10.1", + "27001: A.13.2.1", + "27002: 13.2.1", + "27001: A.18", + "27002: 18", + "27001: A.14.1.2", + "27002: 14.1.2", + "27001: A.14.1.3", + "27002 14.1.3 c)", + "27001 - A.10.1.1", + "27017 - 10.1.1", + "27001 - A.10.1.2", + "27017 - 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.14", + "27001: A.8.24", + "27002: 8.24 Other Information (a)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-19", + "AC-19(5)", + "SC-8", + "SC-8(1)", + "SC-8(3)", + "SC-8(4)", + "SC-12", + "SC-12(2)", + "SC-12(3)", + "SC-28", + "SC-28(1)-(3)", + "SI-4", + "SI-4(10)", + "SI-7", + "SI-7(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-1", + "PR.DS-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01", + "PR.DS-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "Requirement 3", + "2.2.3", + "2.3", + "3.4", + "3.5.3", + "4.1", + "8.2.1", + "PCI Glossary - Strong Cryptography" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "2.2.7", + "3.5.1", + "4.2.1", + "4.2.1.2", + "4.2.2" + ] + } + ] + } + ], + "Checks": [ + "ec2_ebs_volume_encryption", + "ec2_ebs_default_encryption", + "ec2_ebs_snapshots_encrypted", + "s3_bucket_default_encryption", + "s3_bucket_kms_encryption", + "s3_bucket_secure_transport_policy", + "rds_instance_storage_encrypted", + "rds_cluster_storage_encrypted", + "rds_instance_transport_encrypted", + "rds_snapshots_encrypted", + "efs_encryption_at_rest_enabled", + "dynamodb_tables_kms_cmk_encryption_enabled", + "dynamodb_accelerator_cluster_encryption_enabled", + "dynamodb_accelerator_cluster_in_transit_encryption_enabled", + "kinesis_stream_encrypted_at_rest", + "firehose_stream_encrypted_at_rest", + "sns_topics_kms_encryption_at_rest_enabled", + "sqs_queues_server_side_encryption_enabled", + "cloudtrail_kms_encryption_enabled", + "cloudwatch_log_group_kms_encryption_enabled", + "opensearch_service_domains_encryption_at_rest_enabled", + "opensearch_service_domains_node_to_node_encryption_enabled", + "opensearch_service_domains_https_communications_enforced", + "redshift_cluster_encrypted_at_rest", + "redshift_cluster_in_transit_encryption_enabled", + "documentdb_cluster_storage_encrypted", + "neptune_cluster_storage_encrypted", + "neptune_cluster_snapshot_encrypted", + "elasticache_redis_cluster_rest_encryption_enabled", + "elasticache_redis_cluster_in_transit_encryption_enabled", + "kafka_cluster_in_transit_encryption_enabled", + "kafka_cluster_encryption_at_rest_uses_cmk", + "kafka_connector_in_transit_encryption_enabled", + "dms_endpoint_ssl_enabled", + "dms_endpoint_redis_in_transit_encryption_enabled", + "elb_ssl_listeners", + "elbv2_ssl_listeners", + "elbv2_insecure_ssl_ciphers", + "elbv2_nlb_tls_termination_enabled", + "cloudfront_distributions_https_enabled", + "cloudfront_distributions_origin_traffic_encrypted", + "cloudfront_distributions_custom_ssl_certificate", + "transfer_server_in_transit_encryption_enabled", + "sagemaker_notebook_instance_encryption_enabled", + "sagemaker_training_jobs_volume_and_output_encryption_enabled", + "workspaces_volume_encryption_enabled", + "storagegateway_fileshare_encryption_enabled", + "backup_vaults_encrypted", + "backup_recovery_point_encrypted", + "athena_workgroup_encryption", + "glue_data_catalogs_connection_passwords_encryption_enabled", + "glue_data_catalogs_metadata_encryption_enabled", + "glue_etl_jobs_amazon_s3_encryption_enabled", + "glue_etl_jobs_cloudwatch_logs_encryption_enabled", + "glue_etl_jobs_job_bookmark_encryption_enabled", + "glue_development_endpoints_s3_encryption_enabled", + "glue_development_endpoints_cloudwatch_logs_encryption_enabled", + "glue_development_endpoints_job_bookmark_encryption_enabled", + "glue_ml_transform_encrypted_at_rest", + "bedrock_model_invocation_logs_encryption_enabled", + "codebuild_project_s3_logs_encrypted", + "codebuild_report_group_export_encrypted" + ] + }, + { + "Id": "CEK-04", + "Description": "Use encryption algorithms that are appropriate for data protection, considering the classification of data, associated risks, and usability of the encryption technology.", + "Name": "Encryption Algorithm", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-04" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.11" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1.2", + "27001: 6.1.3", + "27001: A.8.2", + "27002: 8.2", + "27001: A.8.3", + "27001: A.10.1.1", + "27002: 10.1.1 (b)", + "27001: A.10.1.2", + "27002: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1.2", + "27001: 6.1.3", + "27001: A.8.24", + "27001: A.5.12", + "27001: A.5.13", + "27002: 8.24 General (b)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-12", + "SC-12(2)", + "SC-12(3)", + "SC-28", + "SC-28(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-1", + "PR.DS-2", + "ID.AM-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01", + "PR.DS-02", + "ID.AM-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "A2", + "Requirement 3", + "2.3", + "2.2.3", + "3.4", + "3.5.3", + "4.1", + "8.2.1", + "PCI Glossary - Strong Cryptography" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "2.2.7", + "3.5.1", + "4.2.1", + "4.2.1.2", + "4.2.2" + ] + } + ] + } + ], + "Checks": [ + "acm_certificates_with_secure_key_algorithms", + "elb_insecure_ssl_ciphers", + "elbv2_insecure_ssl_ciphers", + "cloudfront_distributions_using_deprecated_ssl_protocols" + ] + }, + { + "Id": "CEK-08", + "Description": "CSPs must provide the capability for CSCs to manage their own data encryption keys.", + "Name": "CSC Key Management Capability", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2", + "SC2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1", + "27017: 10.1", + "27001: A.10.1.1", + "27017: 10.1.1", + "27001: A.10.1.2", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.23", + "27001: A.8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-9", + "CP-9(8)", + "SA-9", + "SA-9(6)", + "SC-12", + "SC-12(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.SC-3", + "ID.AM-6", + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.SC-05" + ] + } + ] + } + ], + "Checks": [ + "kms_cmk_are_used", + "s3_bucket_kms_encryption", + "dynamodb_tables_kms_cmk_encryption_enabled", + "kms_key_not_publicly_accessible", + "kms_cmk_not_multi_region" + ] + }, + { + "Id": "CEK-10", + "Description": "Generate Cryptographic keys using industry accepted cryptographic libraries specifying the algorithm strength and the random number generator used.", + "Name": "Key Generation", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-04" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.11" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2", + "TS2.3", + "SY1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1.1", + "27002: 10.1.1 (e)", + "27017: 10.1.1", + "27001: A.10.1.2", + "27002: 10.1.2", + "27002: 10.1.2 (a)", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.24", + "27002: 8.24 (d), Key management (a)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-12", + "SC-12(2)", + "SC-12(3)", + "SC-13" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.2.3", + "3.6.1", + "PCI Glossary - Cryptographic Key Generation" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.6.1", + "3.6.1.1", + "3.7.1" + ] + } + ] + } + ], + "Checks": [ + "kms_cmk_are_used" + ] + }, + { + "Id": "CEK-12", + "Description": "Rotate cryptographic keys in accordance with the calculated cryptoperiod, which includes provisions for considering the risk of information disclosure and legal and regulatory requirements.", + "Name": "Key Rotation", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1.1", + "27017: 10.1.1", + "27001: A.10.1.2", + "27002: 10.1.2 e)", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.31", + "27001: A.8.24", + "27002: 5.31 Cryptography", + "27002: 8.24 Key management (e,m)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-12", + "SC-12(2)", + "SC-12(3)", + "SC-13" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "ID.GV-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-05", + "GV.OC-03" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.7.4", + "3.7.5" + ] + } + ] + } + ], + "Checks": [ + "kms_cmk_rotation_enabled", + "iam_rotate_access_key_90_days", + "secretsmanager_automatic_rotation_enabled", + "secretsmanager_secret_rotated_periodically" + ] + }, + { + "Id": "CEK-14", + "Description": "Define, implement and evaluate processes, procedures and technical measures to destroy keys stored outside a secure environment and revoke keys stored in Hardware Security Modules (HSMs) when they are no longer needed, which include provisions for legal and regulatory requirements.", + "Name": "Key Destruction", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1.1", + "27017: 10.1.1", + "27017: 10.1.2", + "27001: A.10.1.2", + "27002: 10.1.2 (j)", + "27001: A.18.1.3", + "27002: 18.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.31", + "27001: A.8.24", + "27002: 5.31 Cryptography", + "27002: 8.24 Key management (j,m)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-12", + "SC-12(2)", + "SC-12(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.IP-6", + "ID.GV-3", + "PR.DS-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-05", + "ID.AM-08", + "GV.OC-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.6.4", + "3.6.5" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.7.4", + "3.7.5" + ] + } + ] + } + ], + "Checks": [ + "kms_cmk_not_deleted_unintentionally" + ] + }, + { + "Id": "DCS-06", + "Description": "Catalogue and track all relevant physical and logical assets located at all of the CSP's sites within a secured system.", + "Name": "Assets Cataloguing and Tracking", + "Attributes": [ + { + "Section": "Datacenter Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "DCS - 01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "1.1", + "2.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.3.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SM2.6" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.8.1.1", + "27002: 8.1.1", + "27017: 8.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.9" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-8", + "CM-8(1)", + "CM-8(2)", + "CM-8(4)", + "CM-8(7)", + "CM-8(8)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.AM-1", + "ID.AM-2", + "ID.AM-4", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-01", + "ID.AM-02", + "ID.AM-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.4", + "9.7.1", + "9.9.1", + "9.9.1.a", + "9.9.1.b", + "9.9.1.c", + "12.3.3", + "12.3.4" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.6.1.1", + "6.3.2", + "9.4.2", + "9.4.3", + "12.5.1" + ] + } + ] + } + ], + "Checks": [ + "config_recorder_all_regions_enabled", + "resourceexplorer2_indexes_found" + ] + }, + { + "Id": "DSP-02", + "Description": "Apply industry accepted methods for the secure disposal of data from storage media such that data is not recoverable by any forensic means.", + "Name": "Secure Disposal", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2", + "CC6.3", + "CC6.4", + "CC6.5", + "CC6.7", + "P4.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "DSI-07" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.5" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.3.3", + "7.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.1", + "IM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.8.3.2", + "27002: 8.3.2", + "27001: A.11.2.7", + "27002: 11.2.7" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.7.10", + "27001: A.7.14", + "27001: A.8.10", + "27002: 7.10 (Secure reuse or disposal)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PM-22", + "SI-12", + "SI-12(3)", + "SI-18", + "SI-18(1)", + "SI-18(4)", + "SI-18(5)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-6" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.SC-10", + "PR.PS-02", + "PR.PS-03", + "ID.AM-08" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.1", + "9.8", + "9.8.1", + "9.8.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.2.1", + "3.7.5", + "9.4.7" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_lifecycle_enabled", + "dlm_ebs_snapshot_lifecycle_policy_exists", + "ecr_repositories_lifecycle_policy_enabled" + ] + }, + { + "Id": "DSP-03", + "Description": "Create and maintain a data inventory, at least for any sensitive data and personal data.", + "Name": "Data Inventory", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.3.1", + "1.3.2", + "1.3.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.1", + "IM2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.8.1.1", + "27002: 8.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.9", + "27001: A.8.12" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-12", + "CM-12(1)", + "PM-5", + "PM-5(1)", + "SI-12", + "SI-12(1)", + "SI-19", + "SI-19(1)", + "SI-19(2)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.AM-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-07" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.2.1", + "9.4.5" + ] + } + ] + } + ], + "Checks": [ + "macie_is_enabled", + "macie_automated_sensitive_data_discovery_enabled", + "config_recorder_all_regions_enabled" + ] + }, + { + "Id": "DSP-04", + "Description": "Classify data according to its type and sensitivity level.", + "Name": "Data Classification", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "C1.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "DSI-01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.7" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.3.1", + "1.3.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.8.2.1", + "27002: 8.2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.12" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-16", + "AC-16(9)", + "PM-22", + "PM-23", + "PT-2", + "PT-2(1)", + "SI-18", + "SI-18(2)", + "SI-19", + "SI-19(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.AM-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-05", + "ID.AM-07" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "9.6.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "9.4.2", + "9.4.3" + ] + } + ] + } + ], + "Checks": [ + "macie_is_enabled", + "macie_automated_sensitive_data_discovery_enabled" + ] + }, + { + "Id": "DSP-07", + "Description": "Develop systems, products, and business practices based upon a principle of security by design and industry best practices.", + "Name": "Data Protection by Design and Default", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "PI1.2", + "PI1.3" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.3.1", + "5.3.2", + "5.3.3", + "5.3.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SD2.2", + "IM1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.14.1.1", + "27002:14.1.1", + "27001: A.14.2.5", + "27002:14.2.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.27", + "27001: A.8.28", + "27001: A.8.29", + "27002: 5.8 (Information security requirements a-i)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PM-17", + "PM-24", + "PM-25", + "PT-2", + "PT-2(2)", + "SA-3", + "SA-4", + "SA-5", + "SA-8", + "SA-8(9)", + "SA-8(13)", + "SA-8(18)", + "SA-8(20)", + "SA-8(22)", + "SA-8(23)", + "SA-8(33)", + "SA-15", + "SA-15(12)", + "SC-3", + "SC-3(3)", + "SC-7", + "SC-7(24)", + "SC-8", + "SC-8(1)-(4)", + "SC-28", + "SC-28(1)", + "SI-12", + "SI-12(1)-(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-2", + "PR.PT-3", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "PR.PS-06" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.2.1" + ] + } + ] + } + ], + "Checks": [ + "ec2_ebs_default_encryption", + "s3_account_level_public_access_blocks", + "s3_bucket_level_public_access_block", + "ec2_ebs_snapshot_account_block_public_access", + "rds_instance_no_public_access", + "rds_snapshots_public_access" + ] + }, + { + "Id": "DSP-10", + "Description": "Define, implement and evaluate processes, procedures and technical measures that ensure any transfer of personal or sensitive data is protected from unauthorized access and only processed within scope as permitted by the respective laws and regulations.", + "Name": "Sensitive Data Transfer", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-02", + "EKM-03" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.1", + "3.12", + "3.13" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.2", + "9.5.1", + "9.5.2", + "9.5.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.4", + "IM2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.13.2.1", + "27002: 13.2.1", + "27001: A.8.3.3", + "27002: 8.3.3", + "27001: A.13.2.3", + "27002: 13.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.14", + "27001: A.7.10" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-4", + "AC-4(23)-(25)", + "CA-3", + "CA-3(6)", + "CA-6", + "CA-6(1)", + "CA-6(2)", + "SC-4", + "SC-4(2)", + "SC-7", + "SC-7(10)", + "SC-7(24)", + "SC-8", + "SC-8(1)-(5)", + "SC-16", + "SC-16(1)-(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-2", + "PR.DS-5", + "PR.PT-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-02", + "PR.IR-01", + "ID.AM-03", + "GV.OC-03", + "ID.AM-07" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "4.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "4.1.1", + "4.2.1", + "4.2.2" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_secure_transport_policy", + "opensearch_service_domains_https_communications_enforced", + "redshift_cluster_in_transit_encryption_enabled", + "rds_instance_transport_encrypted", + "transfer_server_in_transit_encryption_enabled", + "kafka_cluster_mutual_tls_authentication_enabled" + ] + }, + { + "Id": "DSP-16", + "Description": "Data retention, archiving and deletion is managed in accordance with business requirements, applicable laws and regulations.", + "Name": "Data Retention and Deletion", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "C1.1", + "C1.2", + "CC3.1", + "P4.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-02", + "BCR-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.4", + "3.5" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.3.1", + "7.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.1", + "IM2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.33", + "27001: A.8.10", + "27002: 5.33 (b)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SI-12", + "SI-12(1)-(3)", + "SI-18", + "SI-18(1)", + "SI-18(4)", + "SI-18(5)", + "SI-19", + "SI-19(2)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-3", + "PR.IP-6", + "ID.GV-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "GV.OC-03", + "GV.SC-10", + "PR.DS-11" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.2.1" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_lifecycle_enabled", + "cloudwatch_log_group_retention_policy_specific_days_enabled", + "kinesis_stream_data_retention_period", + "ecr_repositories_lifecycle_policy_enabled" + ] + }, + { + "Id": "DSP-17", + "Description": "Define and implement, processes, procedures and technical measures to protect sensitive data throughout it's lifecycle.", + "Name": "Sensitive Data Protection", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "CSP-Owned", + "PaaS": "CSP-Owned", + "SaaS": "CSC-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC2.1", + "CC6.1", + "CC6.3", + "CC6.7", + "CC8.1", + "C1.1", + "P2.0", + "P3.0", + "P4.0", + "P5.0", + "P6.0" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.1", + "3.1", + "3.14" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.3.3", + "9.1.1", + "9.2.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.1", + "IM2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1.3", + "27002: 18.1.3", + "27001:A.18.1.4", + "27002:18.1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.11", + "27001: A.8.12" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PL-2", + "PM-22", + "PM-24", + "PT-7", + "PT-7(1)", + "PT-7(2)", + "PT-8", + "SC-8", + "SC-8(1)-(5)", + "SC-28", + "SC-28(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-1", + "PR.DS-2", + "PR.DS-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01", + "PR.DS-02", + "PR.DS-10" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.0 (including all subsections)", + "4.0 (including all subsections)" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.1.1", + "4.1.1" + ] + } + ] + } + ], + "Checks": [ + "s3_account_level_public_access_blocks", + "s3_bucket_public_access", + "s3_bucket_policy_public_write_access", + "ec2_ebs_public_snapshot", + "rds_snapshots_public_access", + "rds_instance_no_public_access", + "ec2_ebs_volume_encryption", + "s3_bucket_default_encryption", + "rds_instance_storage_encrypted", + "secretsmanager_not_publicly_accessible", + "macie_is_enabled" + ] + }, + { + "Id": "GRC-05", + "Description": "Develop and implement an Information Security Program, which includes programs for all the relevant domains of the CCM.", + "Name": "Information Security Program", + "Attributes": [ + { + "Section": "Governance, Risk and Compliance", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-04" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "14.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SG2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 4.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 4.3" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PM-1", + "PM-3", + "PM-14", + "PL-2", + "PM-18", + "PM-31" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "12.4.1", + "A.3.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.4.1", + "A3.1.1" + ] + } + ] + } + ], + "Checks": [ + "securityhub_enabled", + "guardduty_is_enabled" + ] + }, + { + "Id": "IAM-02", + "Description": "Establish, document, approve, communicate, implement, apply, evaluate and maintain strong password policies and procedures. Review and update the policies and procedures at least annually.", + "Name": "Strong Password Policy and Procedures", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-02", + "IAM-12", + "GRM-06", + "GRM-09" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.1.1", + "1.5.1", + "4.1.2", + "4.1.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.1", + "SA1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 5.1", + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: 9.1", + "27001: 9.3", + "27001: A.5", + "27002: 5", + "27001: A.9.4.3", + "27002: 9.4.3", + "27017: 9.4.3", + "27018: 9.4.3", + "27001: A.9.2.4", + "27002: 9.2.4", + "27017: 9.2.4", + "27001: A.7.2.2", + "27002: 7.2.2", + "27001: A.9.2.6", + "27002: 9.2.6", + "27001: A.9.2.3", + "27002: 9.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 5.1", + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: 9.1", + "27001: 9.3", + "27001: A.5.1", + "27001: A.5.4", + "27001: A.5.17", + "27001: A.6.3", + "27001: A.8.5", + "27001: A.5.37" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(3)", + "AC-2(11)", + "AC-3", + "AC-3(3)", + "AC-12", + "AC-12(1)", + "IA-2", + "IA-2(10)", + "IA-5", + "IA-5(1)", + "IA-5(18)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-1", + "PR.AC-1", + "PR.AC-7" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.PO-01", + "GV.PO-02", + "ID.IM-03", + "PR.AA-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.4", + "12.1", + "12.1.1", + "12.11" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "8.1.1", + "8.3.8" + ] + } + ] + } + ], + "Checks": [ + "iam_password_policy_minimum_length_14", + "iam_password_policy_lowercase", + "iam_password_policy_uppercase", + "iam_password_policy_number", + "iam_password_policy_symbol", + "iam_password_policy_reuse_24", + "iam_password_policy_expires_passwords_within_90_days_or_less", + "cognito_user_pool_password_policy_minimum_length_14", + "cognito_user_pool_password_policy_lowercase", + "cognito_user_pool_password_policy_uppercase", + "cognito_user_pool_password_policy_number", + "cognito_user_pool_password_policy_symbol" + ] + }, + { + "Id": "IAM-03", + "Description": "Manage, store, and review the information of system identities, and level of access.", + "Name": "Identity Inventory", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-04", + "IAM-08", + "IAM-10" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.1", + "5.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.3", + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 9.2 (c)", + "27001: A.8.1.1", + "27002: 8.1.1", + "27001: A.9.4.1", + "27002: 9.4.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 9.2 (c)", + "27001: A.5.15", + "27001: A.5.16", + "27001: A.5.18", + "27001: A.7.4", + "27001: A.8.15", + "27001: A.8.2", + "27001: A.8.3" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-10", + "AU-10(1)", + "AU-10(2)", + "AU-16", + "AU-16(1)", + "IA-4", + "IA-4(8)", + "IA-4(9)", + "IA-5", + "IA-5(5)", + "IA-8", + "IA-8(4)", + "PM-5(1)", + "SA-8", + "SA-8(22)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-6", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-02", + "PR.AA-04", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.4.a" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.5", + "7.2.5.1" + ] + } + ] + } + ], + "Checks": [ + "iam_user_accesskey_unused", + "iam_user_console_access_unused", + "iam_user_two_active_access_key" + ] + }, + { + "Id": "IAM-04", + "Description": "Employ the separation of duties principle when implementing information system access.", + "Name": "Separation of Duties", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC1.3", + "CC5.1", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-05" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "6.8" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.2.2", + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.6.1.2", + "27002: 6.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.15", + "27001: A.5.18", + "27001: A.5.3", + "27001: A.8.2" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(3)", + "AC-2(11)", + "AC-6", + "AC-6(1)-(10)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.4", + "6.4.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.5.3", + "6.5.4", + "7.2.1", + "7.2.2" + ] + } + ] + } + ], + "Checks": [ + "iam_policy_attached_only_to_group_or_roles", + "iam_securityaudit_role_created", + "iam_support_role_created" + ] + }, + { + "Id": "IAM-05", + "Description": "Employ the least privilege principle when implementing information system access.", + "Name": "Least Privilege", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-02", + "IAM-06", + "IVS-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "6.8" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.1.1", + "27002: 9.1.1", + "27001: A.9.1.2", + "27002: 9.1.2", + "27001: A.9.2.3", + "27002: 9.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.15", + "27001: A.8.2", + "27002: 5.15 (Other information 2nd (a))" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-6", + "AC-6(4)", + "IA-12", + "IA-12(2)", + "IA-12(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "7.1", + "7.1.1", + "7.1.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.1", + "7.2.2", + "7.2.5", + "7.2.6" + ] + } + ] + } + ], + "Checks": [ + "iam_aws_attached_policy_no_administrative_privileges", + "iam_customer_attached_policy_no_administrative_privileges", + "iam_inline_policy_no_administrative_privileges", + "iam_customer_unattached_policy_no_administrative_privileges", + "iam_policy_allows_privilege_escalation", + "iam_inline_policy_allows_privilege_escalation", + "iam_no_custom_policy_permissive_role_assumption", + "iam_role_administratoraccess_policy", + "iam_user_administrator_access_policy", + "iam_group_administrator_access_policy", + "iam_administrator_access_with_mfa" + ] + }, + { + "Id": "IAM-07", + "Description": "De-provision or respectively modify access of movers / leavers or system identity changes in a timely manner in order to effectively adopt and communicate identity and access management policies.", + "Name": "User Access Changes and Revocation", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC5.3", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.3", + "6.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.15", + "27001: A.5.18" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(1)", + "AC-2(2)", + "AC-2(6)", + "AC-2(8)", + "AC-3", + "AC-3(8)", + "AC-6", + "AC-6(7)", + "AU-10", + "AU-10(4)", + "AU-16", + "AU-16(1)", + "CM-7", + "CM-7(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-4", + "PR.IP-11" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.RR-04", + "GV.SC-10", + "PR.AA-01", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.1.2", + "8.1.3" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "8.2.5", + "8.2.6" + ] + } + ] + } + ], + "Checks": [ + "iam_user_accesskey_unused", + "iam_user_console_access_unused", + "iam_user_no_setup_initial_access_key" + ] + }, + { + "Id": "IAM-08", + "Description": "Review and revalidate user access for least privilege and separation of duties with a frequency that is commensurate with organizational risk tolerance.", + "Name": "User Access Review", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.2", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-10" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.5", + "27001: A.9.2.6", + "27001: A.9.4.1", + "27017: 9.4.1", + "27001: A.6.1.2", + "27001: A 9.2.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.3", + "27001: A.5.18", + "27001: A.8.3" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-6", + "AC-6(4)", + "AC-6(8)", + "IA-8", + "IA-8(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "12.5.5" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.5.1", + "7.2.5", + "7.2.4" + ] + } + ] + } + ], + "Checks": [ + "iam_user_accesskey_unused", + "iam_user_console_access_unused", + "iam_rotate_access_key_90_days", + "secretsmanager_secret_unused" + ] + }, + { + "Id": "IAM-09", + "Description": "Define, implement and evaluate processes, procedures and technical measures for the segregation of privileged access roles such that administrative access to data, encryption and key management capabilities and logging capabilities are distinct and separated.", + "Name": "Segregation of Privileged Access Roles", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC5.1", + "CC6.1", + "CC6.3" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.3", + "27002: 9.2.3", + "27017: 9.2.3", + "27018: 9.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.2", + "27001: A.8.18", + "27002: 8.2 (j)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-6", + "AC-3(7)", + "AC-6(4)", + "AC-6(8)", + "IA-5", + "IA-5(6)", + "IA-8", + "IA-8(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.3", + "3.5.2", + "7.1.2", + "7.1.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.6.1", + "3.7.6", + "6.5.3", + "6.5.4", + "7.2.1", + "7.2.2", + "10.3.1" + ] + } + ] + } + ], + "Checks": [ + "iam_policy_attached_only_to_group_or_roles", + "iam_role_administratoraccess_policy", + "iam_avoid_root_usage", + "iam_no_root_access_key" + ] + }, + { + "Id": "IAM-10", + "Description": "Define and implement an access process to ensure privileged access roles and rights are granted for a time limited period, and implement procedures to prevent the culmination of segregated privileged access.", + "Name": "Management of Privileged Access Roles", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2", + "CC6.3" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.1", + "6.5" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.3", + "27002: 9.2.3", + "27017: 9.2.3", + "27018: 9.2.3", + "27001: A.9.4.4", + "27002: 9.4.4", + "27017: 9.4.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.2", + "27001: A.8.18", + "27002: 8.2 (i)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(7)", + "AC-3", + "AC-3(4)", + "AC-3(11)", + "AC-3(13)", + "AC-3(14)", + "AC-6", + "AC-6(4)", + "AC-6(5)", + "AC-6(8)", + "AC-12", + "AC-12(3)", + "AC-17", + "AC-17(4)", + "IA-8", + "IA-8(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "7.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.1", + "7.2.2" + ] + } + ] + } + ], + "Checks": [ + "iam_avoid_root_usage", + "iam_no_root_access_key", + "iam_role_cross_account_readonlyaccess_policy", + "iam_role_cross_service_confused_deputy_prevention", + "iam_inline_policy_allows_privilege_escalation", + "iam_policy_allows_privilege_escalation" + ] + }, + { + "Id": "IAM-12", + "Description": "Define, implement and evaluate processes, procedures and technical measures to ensure the logging infrastructure is read-only for all with write access, including privileged access roles, and that the ability to disable it is controlled through a procedure that ensures the segregation of duties and break glass procedures.", + "Name": "Safeguard Logs Integrity", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.3" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.1", + "27002: 12.4.1", + "27017: 12.4.1", + "27018: 12.4.1", + "27001: A.12.4.2", + "27002: 12.4.2", + "27017: 12.4.2", + "27018: 12.4.2", + "27001: A.12.4.3", + "27002: 12.4.3", + "27017: 12.4.3", + "27018: 12.4.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.15", + "27001: A.8.18", + "27002: 8.15 Protection of Logs" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(11)", + "AC-2(12)", + "IA-8", + "IA-8(4)", + "SA-8", + "SA-8(22)", + "SC-34", + "SC-34(1)", + "SC-34(2)", + "SC-36", + "SI-4", + "SI-4(5)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.5" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.3.1", + "10.3.2", + "10.3.3", + "10.3.4" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_log_file_validation_enabled", + "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", + "cloudtrail_logs_s3_bucket_access_logging_enabled", + "cloudtrail_kms_encryption_enabled", + "cloudtrail_bucket_requires_mfa_delete" + ] + }, + { + "Id": "IAM-13", + "Description": "Define, implement and evaluate processes, procedures and technical measures that ensure users are identifiable through unique IDs or which can associate individuals to the usage of user IDs.", + "Name": "Uniquely Identifiable Users", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.1", + "27002: 9.2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.16" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-3", + "AC-3(14)", + "AC-24", + "AC-24(2)", + "AU-10", + "AU-10(1)", + "IA-2", + "IA-2(1)", + "IA-2(2)", + "IA-2(12)", + "IA-4", + "IA-4(1)", + "SA-8", + "SA-8(22)", + "SC-23", + "SC-23(3)", + "SC-40(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-6" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.1", + "8.2", + "8.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "8.2.1", + "8.2.2", + "8.2.4" + ] + } + ] + } + ], + "Checks": [ + "iam_user_mfa_enabled_console_access", + "iam_check_saml_providers_sts" + ] + }, + { + "Id": "IAM-14", + "Description": "Define, implement and evaluate processes, procedures and technical measures for authenticating access to systems, application and data assets, including multifactor authentication for at least privileged user and sensitive data access. Adopt digital certificates or alternatives which achieve an equivalent level of security for system identities.", + "Name": "Strong Authentication", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-02", + "IAM-05" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "6.3", + "6.5", + "12.5", + "12.7" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3", + "SA1.4", + "SA1.8" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.1.2", + "27002: 9.1.2", + "27017: 9.1.2", + "27001: A.9.2.4", + "27002: 9.2.4", + "27017: 9.2.4", + "27001: A.9.4.2", + "27002: 9.4.2", + "27017: 9.4.2", + "27018: 9.4.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.15", + "27001: A.5.17", + "27001: A.8.5", + "27001: A.8.24", + "27002: 8.5", + "27002: 8.24 other information (d)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-6", + "AC-6(5)", + "AC-7", + "AC-7(4)", + "AU-10", + "AU-10(2)", + "IA-2", + "IA-2(1)", + "IA-2(2)", + "IA-2(8)", + "IA-2(12)", + "IA-3", + "IA-3(1)", + "IA-5", + "IA-5(2)", + "IA-5(7)", + "IA-5(9)", + "IA-5(10)", + "IA-5(12)", + "IA-5(14)-(16)", + "IA-8", + "IA-8(1)", + "IA-8(6)", + "SC-23", + "SC-23(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-6", + "PR.AC-7" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-02", + "PR.AA-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.1.2", + "8.1.3", + "8.1.6", + "8.2", + "8.3", + "8.3.2", + "12.3.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.1", + "8.3.1", + "8.3.2", + "8.4.1", + "8.4.2", + "8.4.3" + ] + } + ] + } + ], + "Checks": [ + "iam_root_mfa_enabled", + "iam_root_hardware_mfa_enabled", + "iam_user_mfa_enabled_console_access", + "iam_user_hardware_mfa_enabled", + "cognito_user_pool_mfa_enabled" + ] + }, + { + "Id": "IAM-15", + "Description": "Define, implement and evaluate processes, procedures and technical measures for the secure management of passwords.", + "Name": "Passwords Management", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.4", + "27002: 9.2.4", + "27017: 9.2.4", + "27018: 9.2.4", + "27001: A.9.3.1", + "27002: 9.3.1", + "27017: 9.3.1", + "27018: 9.3.1", + "27001: A.9.4.3", + "27002: 9.4.3", + "27017: 9.4.3", + "27018: 9.4.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.17" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "IA-4", + "IA-4(8)", + "IA-5", + "IA-5(1)", + "IA-5(8)", + "IA-5(18)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.2", + "8.2.1-6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "2.2.2", + "2.3.1", + "8.3.5", + "8.3.6", + "8.3.7", + "8.3.8", + "8.3.9", + "8.3.10", + "8.3.10.1", + "8.6.2" + ] + } + ] + } + ], + "Checks": [ + "iam_password_policy_minimum_length_14", + "iam_password_policy_reuse_24", + "iam_password_policy_expires_passwords_within_90_days_or_less", + "cognito_user_pool_password_policy_minimum_length_14", + "cognito_user_pool_temporary_password_expiration" + ] + }, + { + "Id": "IAM-16", + "Description": "Define, implement and evaluate processes, procedures and technical measures to verify access to data and system functions is authorized.", + "Name": "Authorization Mechanisms", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3", + "SA1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.5", + "27002: 9.2.5", + "27017: 9.2.5", + "27018: 9.2.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.18" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-3", + "AC-3(5)", + "AC-4", + "AC-4(17)", + "AC-4(21)", + "AC-4(22)", + "AC-6", + "AC-6(8)", + "AC-6(9)", + "AC-12", + "AC-12(1)", + "AC-20", + "AC-20(1)", + "AU-10", + "AU-10(1)", + "AU-10(2)", + "IA-2", + "IA-2(1)", + "IA-2(2)", + "IA-2(12)", + "IA-3", + "IA-3(1)", + "IA-5(1)", + "IA-5(2)", + "IA-5(5)", + "IA-5(8)", + "IA-5(10)", + "IA-5(12)", + "IA-8", + "IA-8(1)", + "IA-8(2)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-4", + "PR.AC-6", + "PR.AC-7", + "PR.PT-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-02", + "PR.AA-03", + "PR.AA-04", + "PR.AA-05", + "PR.PS-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "5.3", + "7.1.4" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.4", + "7.2.3", + "7.2.5.1" + ] + } + ] + } + ], + "Checks": [ + "iam_aws_attached_policy_no_administrative_privileges", + "iam_customer_attached_policy_no_administrative_privileges", + "iam_inline_policy_no_administrative_privileges", + "apigateway_restapi_authorizers_enabled", + "apigatewayv2_api_authorizers_enabled", + "awslambda_function_not_publicly_accessible", + "awslambda_function_url_public", + "cognito_user_pool_waf_acl_attached" + ] + }, + { + "Id": "IPY-03", + "Description": "Implement cryptographically secure and standardized network protocols for the management, import and export of data.", + "Name": "Secure Interoperability and Portability Management", + "Attributes": [ + { + "Section": "Interoperability & Portability", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IPY-04" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY1.1", + "SY1.2", + "NC1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1", + "27001: A.15.1.1", + "27002: 15.1.1", + "27017: 15.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.19", + "27001: A.5.23", + "27001: A.5.31", + "27001: A.5.32", + "27001: A.5.33", + "27001: A.5.34" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PT-2", + "PT-2(2)", + "SA-4", + "SC-16", + "SC-16(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-02" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "1.2.1", + "1.2.5", + "1.2.6", + "2.2.4", + "2.2.5", + "2.2.7", + "4.2.1" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_secure_transport_policy" + ] + }, + { + "Id": "IVS-02", + "Description": "Plan and monitor the availability, quality, and adequate capacity of resources in order to deliver the required system performance as determined by the business.", + "Name": "Capacity and Resource Planning", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "No", + "IaaS": "CSP-Owned", + "PaaS": "CSP-Owned", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "A1.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-04" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 5.3", + "27001: 6.1", + "27001: 9.1", + "27001: A.12.1.3", + "27002: 12.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 5.3 (b)", + "27001: 6.1", + "27001: 9.1", + "27001: A.8.6", + "27001: A.8.14" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-2", + "CP-2(2)", + "SC-5", + "SC-5(2)", + "SC-4", + "SI-4" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-4", + "ID.BE-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.IR-04", + "GV.OC-04" + ] + } + ] + } + ], + "Checks": [ + "autoscaling_group_multiple_az", + "autoscaling_group_multiple_instance_types" + ] + }, + { + "Id": "IVS-03", + "Description": "Monitor, encrypt and restrict communications between environments to only authenticated and authorized connections, as justified by the business. Review these configurations at least annually, and support them by a documented justification of all allowed services, protocols, ports, and compensating controls.", + "Name": "Network Security", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-06" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.8", + "3.1", + "12.2", + "13.6", + "13.9" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.2", + "5.2.7" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "NC1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 7.5", + "27001: 9.1", + "27001: A.13.1.1", + "27002: 13.1.1", + "27001: A.13.1.2", + "27002: 13.1.2", + "27001: A.13.1.3", + "27002: 13.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 7.5", + "27001: 9.1", + "27001: A.5.15", + "27001: A.5.37", + "27001: A.8.5", + "27001: A.8.9", + "27001: A.8.16", + "27001: A.8.20", + "27001: A.8.21", + "27001: A.8.22", + "27001: A.8.24", + "27002: A.5.15 2nd c)", + "27002: 8.20", + "27002: 8.21", + "27002: 8.22", + "27002: 8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-1", + "SC-4", + "SC-7", + "SC-7(4)", + "SC-7(5)", + "SC-7(8)", + "SC-7(9)", + "SC-7(11)", + "SC-8", + "SC-8(1)", + "SC-11", + "SC-12", + "SC-16", + "SC-23", + "SC-29", + "SC-29(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-5", + "PR.AC-7", + "PR.PT-4", + "DE.CM-1", + "DE.CM-7", + "PR.DS-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.IR-01", + "PR.AA-03", + "PR.AA-05", + "DE.CM-01", + "PR.DS-02", + "ID.AM-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "1.1.6", + "1.2", + "1.2.3", + "2.2", + "4.1.1", + "10.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "1.2.5", + "1.2.6", + "1.2.7", + "1.4.2", + "2.2.4", + "2.2.5", + "2.2.7", + "4.2.1", + "10.1.1" + ] + } + ] + } + ], + "Checks": [ + "vpc_flow_logs_enabled", + "ec2_securitygroup_default_restrict_traffic", + "ec2_securitygroup_allow_ingress_from_internet_to_all_ports", + "ec2_securitygroup_allow_ingress_from_internet_to_any_port", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389", + "ec2_securitygroup_allow_ingress_from_internet_to_high_risk_tcp_ports", + "ec2_networkacl_allow_ingress_any_port", + "ec2_networkacl_allow_ingress_tcp_port_22", + "ec2_networkacl_allow_ingress_tcp_port_3389", + "ec2_securitygroup_allow_wide_open_public_ipv4", + "vpc_peering_routing_tables_with_least_privilege", + "vpc_subnet_no_public_ip_by_default" + ] + }, + { + "Id": "IVS-04", + "Description": "Harden host and guest OS, hypervisor or infrastructure control plane according to their respective best practices, and supported by technical controls, as part of a security baseline.", + "Name": "OS Hardening and Base Controls", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "CSP-Owned", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.8", + "CC7.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-07", + "IVS-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "4.1", + "4.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.3", + "5.2.5" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY1.1", + "SY1.3", + "SY1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 7.5", + "27001: 9.1", + "27001: A.14.2.2", + "27002: 14.2.2", + "27001: A.14.2.3", + "27001 A.14.2.4", + "27018: 12.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 7.5", + "27001: 9.1", + "27001: A.5.37", + "27001: A.8.5", + "27001: A.8.9", + "27001: A.8.16", + "27001: A.8.20", + "27001: A.8.22", + "27001: A.8.24", + "27002: 8.20", + "27002: 8.22", + "27002: 8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-6", + "CM-6(1)", + "SC-29", + "SC-29(1)", + "SC-2", + "SC-7", + "SC-7(12)", + "SC-30", + "SC-34", + "SC-35", + "SC-39", + "SC-44" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-1", + "PR.PT-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "2.2.1" + ] + } + ] + } + ], + "Checks": [ + "ec2_instance_imdsv2_enabled", + "ec2_instance_account_imdsv2_enabled", + "ec2_launch_template_imdsv2_required", + "ec2_instance_managed_by_ssm", + "ssm_managed_compliant_patching" + ] + }, + { + "Id": "IVS-06", + "Description": "Design, develop, deploy and configure applications and infrastructures such that CSP and CSC (tenant) user access and intra-tenant access is appropriately segmented and segregated, monitored and restricted from other tenants.", + "Name": "Segmentation and Segregation", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-09" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1", + "5.3.4", + "5.2.7" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SC2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 9.1", + "27001: A.13.1.3", + "27002: 13.1.3", + "27017: 13.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 9.1", + "27001: A.5.15", + "27001: A.5.20", + "27001: A.8.3", + "27001: A.8.9", + "27001: A.8.16", + "27001: A.8.22", + "27002: 5.15 (b)", + "27002: 8.3 (b)", + "27002: 8.16 (b)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-3", + "SC-7", + "SC-7(20)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4", + "PR.AC-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05", + "PR.IR-01", + "PR.PS-01", + "PR.PS-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.6", + "8.3.1", + "10.8", + "11.3", + "A3.2.1", + "A3.3.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "A1.1.1", + "A1.1.2", + "A1.1.3" + ] + } + ] + } + ], + "Checks": [ + "ec2_securitygroup_default_restrict_traffic", + "vpc_subnet_separate_private_public", + "vpc_peering_routing_tables_with_least_privilege", + "ec2_instance_public_ip", + "awslambda_function_inside_vpc", + "sagemaker_notebook_instance_vpc_settings_configured", + "sagemaker_models_vpc_settings_configured", + "sagemaker_training_jobs_vpc_settings_configured" + ] + }, + { + "Id": "IVS-07", + "Description": "Use secure and encrypted communication channels when migrating servers, services, applications, or data to cloud environments. Such channels must include only up-to-date and approved protocols.", + "Name": "Migration to Cloud Environments", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-10" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.4", + "IM1.4", + "NC1.4", + "SC2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.13.1.1", + "27002: 13.1.1", + "27017: 13.1.1", + "27018: 13.1.1", + "27001: A.13.1.2", + "27002: 13.1.2", + "27017: 13.1.2", + "27018: 13.1.2", + "27001: A.13.1.3", + "27002: 13.1.3", + "27017: 13.1.3", + "27018: 13.1.3", + "27001: A.13.2.1", + "27002: 13.2.1", + "27017: 13.2.1", + "27018: 13.2.1", + "27001: A.13.2.2", + "27002: 13.2.2", + "27017: 13.2.2", + "27018: 13.2.2", + "27001: A.13.2.3", + "27002: 13.2.3", + "27017: 13.2.3", + "27018: 13.2.3", + "27001: A.13.2.4", + "27002: 13.2.4", + "27017: 13.2.4", + "27018: 13.2.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.14", + "27001: A.8.20", + "27001: A.8.24", + "27002: 8.20 (e)", + "27002: 8.24 Guidance (b,f), other information (a)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-17", + "AC-20", + "SC-7", + "SC-7(28)", + "SC-8", + "SC-8(1)", + "SC-12", + "SC-23", + "SC-29", + "SI-7", + "SI-7(1)-(3)", + "SI-7(5)-(10)", + "SI-7(12)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-2", + "PR.PT-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-02" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "4.2.1" + ] + } + ] + } + ], + "Checks": [ + "dms_endpoint_ssl_enabled" + ] + }, + { + "Id": "IVS-09", + "Description": "Define, implement and evaluate processes, procedures and defense-in-depth techniques for protection, detection, and timely response to network-based attacks.", + "Name": "Network Defense", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.6", + "CC6.8", + "CC7.1", + "CC7.2", + "CC7.5" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-13" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "13.3", + "13.8" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.3", + "5.2.4", + "5.2.5", + "5.2.7", + "5.3.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "NC1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1", + "27001: 6.2", + "27001: A.14.1.2", + "27002: 14.1.2", + "27017: 14.1.2", + "27001: A.11.1.4", + "27002: 11.1.4", + "27017: 11.1.4", + "27018: 16.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1", + "27001: 6.2", + "27001: A.5.24", + "27001: A.5.26", + "27001: A.8.8", + "27001: A.8.16", + "27001: A.8.20", + "27001: A.8.21", + "27001: A.8.22", + "27001: A.8.26", + "27002: 8.8 (i)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PL-8", + "PL-8(1)", + "SC-5", + "SC-5(1)", + "SC-5(3)", + "SC-7", + "SC-7(13)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.AE-1", + "DE.DP-1", + "DE.CM-1", + "DE.CM-7", + "PR.AC-5", + "RS.MI-2", + "PR.DS-2", + "RS.RP-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-03", + "DE.CM-01", + "PR.IR-01", + "RS.MA-01", + "RS.MI-01", + "RS.MI-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.6", + "1.1", + "1.2", + "1.3", + "1.5", + "12.10.5" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "1.1.1", + "1.3.1", + "1.3.2", + "1.3.3", + "1.4.1", + "1.4.2", + "1.4.3", + "1.4.4", + "1.4.5", + "1.5.1", + "12.10.1" + ] + } + ] + } + ], + "Checks": [ + "networkfirewall_in_all_vpc", + "networkfirewall_logging_enabled", + "networkfirewall_policy_rule_group_associated", + "wafv2_webacl_with_rules", + "wafv2_webacl_logging_enabled", + "elbv2_waf_acl_attached", + "cloudfront_distributions_using_waf", + "guardduty_is_enabled", + "shield_advanced_protection_in_cloudfront_distributions", + "shield_advanced_protection_in_internet_facing_load_balancers" + ] + }, + { + "Id": "LOG-02", + "Description": "Define, implement and evaluate processes, procedures and technical measures to ensure the security and retention of audit logs.", + "Name": "Audit Logs Protection", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.1", + "8.9", + "8.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "3.1.3", + "5.1.2", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1.3", + "27002: 18.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.28", + "27001: A.5.33", + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-4", + "AU-11" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4", + "PR.IP-4", + "PR.IP-6", + "PR.PT-1", + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05", + "PR.DS-01", + "PR.DS-02", + "ID.AM-08", + "PR.DS-11", + "PR.PS-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.5", + "10.7" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.3.1", + "10.3.2", + "10.3.3", + "10.3.4", + "10.5.1" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_log_file_validation_enabled", + "cloudtrail_kms_encryption_enabled", + "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", + "cloudtrail_logs_s3_bucket_access_logging_enabled", + "cloudtrail_bucket_requires_mfa_delete", + "cloudwatch_log_group_kms_encryption_enabled", + "cloudwatch_log_group_not_publicly_accessible", + "s3_bucket_object_lock" + ] + }, + { + "Id": "LOG-03", + "Description": "Identify and monitor security-related events within applications and the underlying infrastructure. Define and implement a system to generate alerts to responsible stakeholders based on such events and corresponding metrics.", + "Name": "Security Monitoring and Alerting", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.8", + "CC7.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "SEF-03", + "SEF-05" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.5" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.4", + "5.2.7", + "1.6.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2", + "TM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.1", + "27002: 12.4.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.28", + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-5", + "AU-5(2)", + "AU-13" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.AE-1", + "DE.AE-2", + "DE.AE-3", + "DE.AE-5", + "DE.CM-1", + "DE.CM-2", + "DE.CM-3", + "DE.CM-4", + "DE.CM-5", + "DE.CM-6", + "DE.CM-7", + "DE.DP-1", + "DE.DP-4", + "DE.AE-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.AE-02", + "DE.AE-03", + "DE.AE-04", + "DE.AE-06", + "DE.AE-07", + "DE.AE-08", + "DE.CM-01", + "DE.CM-02", + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.2.1", + "10.2.2", + "10.4.1.1", + "10.4.2.1", + "10.4.3" + ] + } + ] + } + ], + "Checks": [ + "guardduty_is_enabled", + "securityhub_enabled", + "cloudwatch_alarm_actions_enabled", + "cloudwatch_alarm_actions_alarm_state_configured", + "cloudwatch_log_metric_filter_unauthorized_api_calls", + "cloudwatch_log_metric_filter_root_usage", + "cloudwatch_log_metric_filter_sign_in_without_mfa" + ] + }, + { + "Id": "LOG-04", + "Description": "Restrict audit logs access to authorized personnel and maintain records that provide unique access accountability.", + "Name": "Audit Logs Access and Accountability", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.14" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "3.1.1", + "4.1.2", + "4.1.3", + "4.2.1", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.2", + "27001: A.12.4.1", + "27002: 12.4.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.33", + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-9", + "AU-9(4)", + "AU-9(6)", + "AU-10" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05", + "PR.PS-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.1", + "10.2.1", + "10.2.3", + "10.5.1", + "10.5.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.2.1.3", + "10.3.1" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", + "cloudwatch_log_group_not_publicly_accessible" + ] + }, + { + "Id": "LOG-05", + "Description": "Monitor security audit logs to detect activity outside of typical or expected patterns. Establish and follow a defined process to review and take appropriate and timely actions on detected anomalies.", + "Name": "Audit Logs Monitoring and Response", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.8", + "8.11" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.1", + "1.6.2", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.3", + "27002: 12.4.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.15", + "27001: A.8.16" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-6", + "AU-6(1)", + "AU-6(5)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.AE-3", + "PR.PT-1", + "RS.AN-1", + "RS.CO-1.", + "DE.AE-1", + "DE.AE-5", + "DE.DP-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-03", + "PR.PS-04", + "DE.AE-02", + "DE.AE-03", + "DE.AE-06", + "DE.AE-07", + "DE.AE-08", + "DE.CM-01", + "DE.CM-02", + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.6", + "10.6.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.4.1.1", + "10.4.2.1" + ] + } + ] + } + ], + "Checks": [ + "cloudwatch_log_metric_filter_unauthorized_api_calls", + "cloudwatch_log_metric_filter_root_usage", + "cloudwatch_log_metric_filter_sign_in_without_mfa", + "cloudwatch_log_metric_filter_policy_changes", + "cloudwatch_log_metric_filter_security_group_changes", + "cloudwatch_changes_to_network_acls_alarm_configured", + "cloudwatch_changes_to_network_gateways_alarm_configured", + "cloudwatch_changes_to_network_route_tables_alarm_configured", + "cloudwatch_changes_to_vpcs_alarm_configured", + "cloudwatch_log_metric_filter_authentication_failures", + "cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk", + "cloudwatch_log_metric_filter_for_s3_bucket_policy_changes", + "cloudwatch_log_metric_filter_aws_organizations_changes", + "guardduty_no_high_severity_findings" + ] + }, + { + "Id": "LOG-07", + "Description": "Establish, document and implement which information meta/data system events should be logged. Review and update the scope at least annually or whenever there is a change in the threat environment.", + "Name": "Logging Scope", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 7.5.3", + "27001: A.12.4.1", + "27002: 12.4.1", + "27017: 12.4.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 7.5.3", + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-1", + "AU-14", + "AU-16" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.SC-3", + "ID.SC-4", + "PR.PT-1", + "ID.GV-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.3" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.2.1", + "10.2.2" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_multi_region_enabled", + "cloudtrail_multi_region_enabled_logging_management_events", + "cloudtrail_s3_dataevents_read_enabled", + "cloudtrail_s3_dataevents_write_enabled", + "vpc_flow_logs_enabled", + "awslambda_function_invoke_api_operations_cloudtrail_logging_enabled" + ] + }, + { + "Id": "LOG-08", + "Description": "Generate audit records containing relevant security information.", + "Name": "Log Records", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.1", + "27002: 12.4.1", + "27017: 12.4.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-3", + "AU-3(1)", + "AU-3(3)", + "AU-6", + "AU-6(8)", + "AU-12", + "AU-12(1)", + "AU-12(2)", + "AU-12(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.PT-1", + "DE.AE-3", + "DE.CM-1", + "DE.CM-2", + "DE.CM-3", + "DE.CM-6", + "DE.CM-7" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.CM-01", + "DE.CM-02", + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.3" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.2.2" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_multi_region_enabled", + "cloudtrail_cloudwatch_logging_enabled", + "vpc_flow_logs_enabled", + "s3_bucket_server_access_logging_enabled", + "elb_logging_enabled", + "elbv2_logging_enabled", + "cloudfront_distributions_logging_enabled", + "route53_public_hosted_zones_cloudwatch_logging_enabled", + "wafv2_webacl_logging_enabled", + "redshift_cluster_audit_logging", + "rds_cluster_integration_cloudwatch_logs", + "rds_instance_integration_cloudwatch_logs", + "opensearch_service_domains_audit_logging_enabled", + "eks_control_plane_logging_all_types_enabled", + "apigateway_restapi_logging_enabled", + "apigatewayv2_api_access_logging_enabled", + "networkfirewall_logging_enabled", + "mq_broker_logging_enabled", + "documentdb_cluster_cloudwatch_log_export", + "neptune_cluster_integration_cloudwatch_logs", + "codebuild_project_logging_enabled", + "glue_etl_jobs_logging_enabled", + "stepfunctions_statemachine_logging_enabled", + "datasync_task_logging_enabled", + "ec2_client_vpn_endpoint_connection_logging_enabled", + "elasticbeanstalk_environment_cloudwatch_logging_enabled" + ] + }, + { + "Id": "LOG-09", + "Description": "The information system protects audit records from unauthorized access, modification, and deletion.", + "Name": "Log Protection", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-04", + "IVS-01" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.4", + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.2", + "27002: 12.4.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-9", + "AU-9(2)", + "AU-9(3)", + "AU-9(4)", + "AU-12(3)", + "AU-12(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4", + "PR.IP-4", + "PR.IP-6", + "PR.PT-1", + "PR.DS-1", + "PR.DS-6" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05", + "PR.DS-01", + "PR.DS-02", + "PR.DS-11" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.5", + "10.5.1", + "10.5.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.3.1", + "10.3.2", + "10.3.3", + "10.3.4" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_log_file_validation_enabled", + "cloudtrail_kms_encryption_enabled", + "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", + "cloudwatch_log_group_kms_encryption_enabled", + "cloudwatch_log_group_not_publicly_accessible" + ] + }, + { + "Id": "LOG-10", + "Description": "Establish and maintain a monitoring and internal reporting capability over the operations of cryptographic, encryption and key management policies, processes, procedures, and controls.", + "Name": "Encryption Monitoring and Reporting", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC7.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-02", + "EKM-03" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1", + "5.1.1", + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1", + "27002: 10.1", + "27001: A.10.1.2", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-1", + "AU-9", + "AU-9(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-1", + "PR.PT-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.1.1", + "10.2.1", + "10.4.1" + ] + } + ] + } + ], + "Checks": [ + "kms_cmk_rotation_enabled", + "acm_certificates_expiration_check" + ] + }, + { + "Id": "LOG-11", + "Description": "Log and monitor key lifecycle management events to enable auditing and reporting on usage of cryptographic keys.", + "Name": "Transaction/Activity Logging", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC7.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-02" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1.2", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-9", + "AU-9(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.PT-1", + "DE.AE-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.CM-09" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_s3_dataevents_read_enabled", + "cloudtrail_s3_dataevents_write_enabled", + "cloudtrail_multi_region_enabled_logging_management_events" + ] + }, + { + "Id": "LOG-13", + "Description": "Define, implement and evaluate processes, procedures and technical measures for the reporting of anomalies and failures of the monitoring system and provide immediate notification to the accountable party.", + "Name": "Failures and Anomalies Reporting", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC2.3", + "CC7.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "SEF-03" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.1", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.16.1.1", + "27002: 16.1.1", + "27001: A.16.1.2", + "27017: 16.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.24", + "27001: A.6.8", + "27002: 6.8 (g)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-5", + "AU-5(2)", + "AU-6", + "AU-6(3)", + "AU-6(4)", + "AU-6(5)", + "AU-16" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.DP-3", + "DE.DP-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.AE-06" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.4.3", + "10.7.1", + "10.7.2", + "10.7.3" + ] + } + ] + } + ], + "Checks": [ + "guardduty_is_enabled", + "guardduty_no_high_severity_findings", + "cloudwatch_alarm_actions_enabled", + "cloudwatch_alarm_actions_alarm_state_configured" + ] + }, + { + "Id": "SEF-03", + "Description": "'Establish, document, approve, communicate, apply, evaluate and maintain a security incident response plan, which includes but is not limited to: relevant internal departments, impacted CSCs, and other business critical relationships (such as supply-chain) that may be impacted.'", + "Name": "Incident Response Plans", + "Attributes": [ + { + "Section": "Security Incident Management, E-Discovery, & Cloud Forensics", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2", + "CC7.3", + "CC7.4" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "BCR-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "17.2", + "17.4" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.2", + "1.6.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: A.16.1.5", + "27002: 16.1.5", + "27017: 16.1.5", + "27017: CLD.12.1.5", + "27018: 16.1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: A.5.26", + "27002: 5.26 (e,f)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "IR-1", + "IR-2", + "IR-2(1)-(3)", + "IR-3", + "IR-3(1)-(3)", + "IR-4", + "IR-4(1)-(15)", + "IR-5", + "IR-5(1)", + "IR-6", + "IR-6(1)-(3)", + "IR-7", + "IR-7(1)", + "IR-7(2)", + "IR-8", + "IR-8(1)", + "IR-9", + "IR-9(1)-(4)", + "PM-12" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "RS.CO-1", + "RS.CO-4", + "ID.AM-6", + "ID.GV-2", + "ID.SC-5", + "PR.IP-9", + "PR.IP10" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AT-01", + "PR.AT-02", + "RS.MA-01", + "GV.SC-08", + "ID.IM-02", + "ID.IM-04", + "RC.RP-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "12.1", + "12.10.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.10.1", + "12.10.5" + ] + } + ] + } + ], + "Checks": [ + "ssmincidents_enabled_with_plans" + ] + }, + { + "Id": "SEF-06", + "Description": "Define, implement and evaluate processes, procedures and technical measures supporting business processes to triage security-related events.", + "Name": "Event Triage Processes", + "Attributes": [ + { + "Section": "Security Incident Management, E-Discovery, & Cloud Forensics", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "SEF-02" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.16.1.4", + "27002: 16.1.4", + "27017: 16.1.4", + "27018: 16.1.4", + "27001: A.16.1.5", + "27002: 16.1.5", + "27017: 16.1.5", + "27018: 16.1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.25" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CA-7", + "CA-7(3)", + "CA-7(4)", + "CA-7(5)", + "CA-7(6)", + "IR-4", + "IR-4(1)", + "IR-4(3)", + "IR-4(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.AE-1", + "DE.AE-2", + "DE.AE-4", + "RS.RP-1", + "RS.AN-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "RS.MA-02", + "RS.MA-03", + "RS.AN-03", + "DE.AE-02", + "DE.AE-04", + "DE.AE-06", + "DE.AE-07", + "DE.AE-08", + "RS.MI-02", + "RC.RP-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "12.5.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.10.1" + ] + } + ] + } + ], + "Checks": [ + "guardduty_is_enabled", + "securityhub_enabled" + ] + }, + { + "Id": "SEF-08", + "Description": "Maintain points of contact for applicable regulation authorities, national and local law enforcement, and other legal jurisdictional authorities.", + "Name": "Points of Contact Maintenance", + "Attributes": [ + { + "Section": "Security Incident Management, E-Discovery, & Cloud Forensics", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC2.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "SEF-01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "17.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.2", + "1.6.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SM2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 4.2", + "27001: A.6.1.3", + "27002: 6.1.3", + "27017: 6.1.3", + "27018: 6.1.3", + "27001: A.16.1.1", + "27002: 16.1.1", + "27001: A.18.1.1", + "27002: 18.1.1", + "27017: 18.1.1", + "27018: 18.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.5", + "27001: A.5.24", + "27002: 5.24 Incident management procedure (d)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "IR-4", + "IR-4(8)", + "IR-6", + "IR-6(3)", + "IR-7", + "IR-7(2)", + "PM-21", + "PM-23", + "PM-26" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-2", + "RS.CO-3", + "RS.CO-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.RR-02", + "RS.CO-02", + "RS.CO-03" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.10.1" + ] + } + ] + } + ], + "Checks": [ + "account_maintain_current_contact_details", + "account_security_contact_information_is_registered", + "account_maintain_different_contact_details_to_security_billing_and_operations" + ] + }, + { + "Id": "TVM-02", + "Description": "Establish, document, approve, communicate, apply, evaluate and maintain policies and procedures to protect against malware on managed assets. Review and update the policies and procedures at least annually.", + "Name": "Malware Protection Policy and Procedures", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC5.3", + "CC6.8" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "TVM-01", + "GRM-06", + "GRM-09" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "9.7", + "10.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.1.1", + "1.5.1", + "5.2.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS1.2", + "TS1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 5.1", + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: 9.1", + "27001: 9.3", + "27001: A.5", + "27002: 5", + "27001: A.12.2.1", + "27001: A.6.2.1", + "27002: 6.2.1 (h)", + "27001: A.6.2.2", + "27002: 6.2.2 (j)", + "27001: A.7.2.2", + "27002: 7.2.2 (d)", + "27001: A.10.1.1", + "27002: 10.1.1 (g)", + "27001: A.13.2.1", + "27002: 13.2.1 (b)", + "27001: A.15.1.2", + "27017: 15.1.2", + "27001: A.12.2.1", + "27002: 12.2.1 (a),(d)", + "27017: CLD.9.5.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 5.1", + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: 9.1", + "27001: 9.3", + "27001: A.5.1", + "27001: A.5.4", + "27001: A.5.7", + "27001: A.5.37", + "27001: A.8.7", + "27002: 5.7 (b)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "RA-3", + "RA-3(3)", + "RA-5", + "RA-5(3)", + "RA-5(5)", + "SI-3", + "SI-3(4)", + "SI-3(10)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-1", + "DE.CM-4", + "DE.CM-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.PO-01", + "GV.PO-02", + "ID.IM-03", + "DE.CM-01", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "5.4", + "12.1", + "12.1.1", + "12.3.1", + "12.5.1", + "12.11" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.1.1", + "12.1.2", + "5.1.1", + "5.3.2.1" + ] + } + ] + } + ], + "Checks": [ + "guardduty_ec2_malware_protection_enabled" + ] + }, + { + "Id": "TVM-03", + "Description": "Define, implement and evaluate processes, procedures and technical measures to enable both scheduled and emergency responses to vulnerability identifications, based on the identified risk.", + "Name": "Vulnerability Remediation Schedule", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC5.3", + "CC7.1", + "CC7.4" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "TVM-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "7.2", + "7.7", + "17.9" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.5" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.1", + "TM2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.12.2.1", + "27001: A.12.6.1", + "27002: 12.6.1(c)(d)(j)", + "27018: 12.6.1(k)(i)" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.8.7", + "27001: A.8.8", + "27001: A.8.32", + "27002: 8.7", + "27002: 8.8", + "27002: 8.32" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PM-31", + "RA-3", + "RA-3(1)", + "RA-5", + "RA-5(2)-(4)", + "RA-5(6)", + "SI-3", + "SI-3(10)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "RS.AN-5", + "PR.IP-12" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.RA-01", + "ID.RA-06", + "ID.RA-08", + "PR.PS-02", + "PR.PS-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.1", + "6.1.a", + "6.1.b" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.1.1", + "6.3.1", + "6.3.2", + "6.3.3", + "12.10.1" + ] + } + ] + } + ], + "Checks": [ + "ssm_managed_compliant_patching", + "rds_instance_minor_version_upgrade_enabled", + "rds_cluster_minor_version_upgrade_enabled", + "redshift_cluster_automatic_upgrades", + "elasticbeanstalk_environment_managed_updates_enabled", + "dms_instance_minor_version_upgrade_enabled", + "elasticache_redis_cluster_auto_minor_version_upgrades", + "memorydb_cluster_auto_minor_version_upgrades", + "mq_broker_auto_minor_version_upgrades", + "opensearch_service_domains_updated_to_the_latest_service_software_version", + "kafka_cluster_uses_latest_version" + ] + }, + { + "Id": "TVM-04", + "Description": "Define, implement and evaluate processes, procedures and technical measures to update detection tools, threat signatures, and indicators of compromise on a weekly, or more frequent basis.", + "Name": "Detection Updates", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "No mapping" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "10.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS1.3", + "TS1.4", + "TM1.3", + "TM1.4", + "IM1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.5.1.1", + "27002: 5.1.1 (h)", + "27001: A.12.6.1", + "27002: 12.6.1 (b),(c)" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.5.1", + "27001: A.8.8", + "27001: A.8.15", + "27001: A.8.16", + "27002: 5.1", + "27002: 5.37", + "27002: 8.8", + "27002: 8.15 (d)", + "27002: 8.16 (d,e)", + "27002: 8.31 2nd (a)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-7", + "CM-7(4)", + "RA-3", + "RA-3(3)", + "RA-5(2)", + "SA-10", + "SA-10(5)", + "SA-11", + "SA-11(2)", + "SI-2", + "SI-2(4)", + "SI-3", + "SI-3(4)", + "SI-4", + "SI-4(9)", + "SI-4(24)", + "SI-8", + "SI-8(2)", + "SI-8(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.DP-5", + "PR.IP-12" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-02", + "ID.RA-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "5.2", + "5.2a", + "5.2b", + "5.2c" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "5.3.1" + ] + } + ] + } + ], + "Checks": [ + "guardduty_is_enabled", + "inspector2_is_enabled" + ] + }, + { + "Id": "TVM-05", + "Description": "Define, implement and evaluate processes, procedures and technical measures to identify updates for applications which use third party or open source libraries according to the organization's vulnerability management policy.", + "Name": "External Library Vulnerabilities", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC3.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "No mapping" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "2.6" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.1", + "SD2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.12.6.2", + "27002: 12.6.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1.3", + "27001: A 5.6", + "27001: A.8.19", + "27001: A.8.8", + "27001: A.8.28", + "27001: A.8.31", + "27002: 5.6 (c)", + "27001: 8.19", + "27001: 8.8", + "27001: 8.28", + "27001: 8.31" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "RA-5", + "RA-5(3)", + "SA-11", + "SA-11(2)", + "SA-11(5)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.DP-5", + "PR.IP-12" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.RA-01", + "ID.RA-03", + "PR.PS-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.1", + "6.2", + "6.3.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.3.1", + "6.3.2", + "6.3.3" + ] + } + ] + } + ], + "Checks": [ + "inspector2_is_enabled", + "ecr_repositories_scan_vulnerabilities_in_latest_image", + "ecr_registry_scan_images_on_push_enabled" + ] + }, + { + "Id": "TVM-07", + "Description": "Define, implement and evaluate processes, procedures and technical measures for the detection of vulnerabilities on organizationally managed assets at least monthly.", + "Name": "Vulnerability Identification", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "TVM-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "7.1", + "7.5", + "7.6" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.5", + "5.2.6" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.6", + "27001: A.12.6.1", + "27002: 12.6.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.8", + "27002: 8.8" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "RA-5", + "RA-5(4)", + "RA-5(5)", + "SA-11", + "SA-11(5)", + "SA-15(5)", + "SC-7", + "SC-7(10)", + "SI-3(8)", + "SI-3(10)", + "SI-7", + "SI-7(9)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.RA-1", + "DE.CM-8", + "PR.IP-12" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.RA-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.1", + "11.2", + "11.2.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.3.1", + "6.3.2", + "6.3.3", + "11.3.2", + "11.3.2.1" + ] + } + ] + } + ], + "Checks": [ + "inspector2_is_enabled", + "inspector2_active_findings_exist", + "guardduty_is_enabled", + "ecr_repositories_scan_vulnerabilities_in_latest_image" + ] + }, + { + "Id": "UEM-08", + "Description": "Protect information from unauthorized disclosure on managed endpoint devices with storage encryption.", + "Name": "Storage Encryption", + "Attributes": [ + { + "Section": "Universal Endpoint Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "MOS-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.6" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.2", + "3.1.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "PA1.2", + "PA1.3", + "PA1.5", + "PA2.2", + "PM1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.11.2.7", + "27002: 11.2.7", + "27001: A.18.1.1", + "27017: 18.1.1", + "27001: A.12.3.1", + "27017: 12.3.1", + "27018: A.11.4", + "27018: A.11.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.1", + "27002: 8.1 (h)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-19(5)", + "SC-28", + "SC-28(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.4", + "3.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.5.1", + "3.6" + ] + } + ] + } + ], + "Checks": [ + "ec2_ebs_volume_encryption", + "ec2_ebs_default_encryption", + "workspaces_volume_encryption_enabled" + ] + }, + { + "Id": "UEM-11", + "Description": "Configure managed endpoints with Data Loss Prevention (DLP) technologies and rules in accordance with a risk assessment.", + "Name": "Data Loss Prevention", + "Attributes": [ + { + "Section": "Universal Endpoint Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.7" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.13" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.7" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.5", + "PA2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.3", + "27002: 12.3", + "27001: A.8.3.1", + "27002: 8.3.1", + "27001: A.12.2", + "27002: 12.2", + "27001: A.18.1.3", + "27002: 18.1.3", + "27001: A.6.1.1", + "27017: 6.1.1", + "27018: 12.3.1", + "27018: 10.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.12", + "27001: A.8.3" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-7", + "SC-7(10)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-02", + "PR.DS-10", + "PR.PS-01", + "ID.AM-08", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "A3.2.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "A3.2.6" + ] + } + ] + } + ], + "Checks": [ + "macie_is_enabled", + "macie_automated_sensitive_data_discovery_enabled" + ] + } + ] +} diff --git a/prowler/lib/check/compliance_models.py b/prowler/lib/check/compliance_models.py index 349e80902b..5dadf2c405 100644 --- a/prowler/lib/check/compliance_models.py +++ b/prowler/lib/check/compliance_models.py @@ -226,6 +226,18 @@ class C5Germany_Requirement_Attribute(BaseModel): ComplementaryCriteria: str +# CSA CCM v4 Requirement Attribute +class CSA_CCM_Requirement_Attribute(BaseModel): + """CSA Cloud Controls Matrix (CCM) v4 Requirement Attribute""" + + Section: str + CCMLite: str + IaaS: str + PaaS: str + SaaS: str + ScopeApplicability: list[dict] + + # Base Compliance Model # TODO: move this to compliance folder class Compliance_Requirement(BaseModel): @@ -244,6 +256,7 @@ class Compliance_Requirement(BaseModel): Prowler_ThreatScore_Requirement_Attribute, CCC_Requirement_Attribute, C5Germany_Requirement_Attribute, + CSA_CCM_Requirement_Attribute, # Generic_Compliance_Requirement_Attribute must be the last one since it is the fallback for generic compliance framework Generic_Compliance_Requirement_Attribute, ] diff --git a/prowler/lib/outputs/compliance/compliance.py b/prowler/lib/outputs/compliance/compliance.py index 56f6084d03..bb7fbf1146 100644 --- a/prowler/lib/outputs/compliance/compliance.py +++ b/prowler/lib/outputs/compliance/compliance.py @@ -4,6 +4,7 @@ from prowler.lib.check.models import Check_Report from prowler.lib.logger import logger from prowler.lib.outputs.compliance.c5.c5 import get_c5_table from prowler.lib.outputs.compliance.cis.cis import get_cis_table +from prowler.lib.outputs.compliance.csa.csa import get_csa_table from prowler.lib.outputs.compliance.ens.ens import get_ens_table from prowler.lib.outputs.compliance.generic.generic_table import ( get_generic_compliance_table, @@ -85,6 +86,15 @@ def display_compliance_table( output_directory, compliance_overview, ) + elif "csa_ccm_" in compliance_framework: + get_csa_table( + findings, + bulk_checks_metadata, + compliance_framework, + output_filename, + output_directory, + compliance_overview, + ) elif "c5_" in compliance_framework: get_c5_table( findings, diff --git a/prowler/lib/outputs/compliance/csa/__init__.py b/prowler/lib/outputs/compliance/csa/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/lib/outputs/compliance/csa/csa.py b/prowler/lib/outputs/compliance/csa/csa.py new file mode 100644 index 0000000000..ab8a021a70 --- /dev/null +++ b/prowler/lib/outputs/compliance/csa/csa.py @@ -0,0 +1,101 @@ +from colorama import Fore, Style +from tabulate import tabulate + +from prowler.config.config import orange_color + + +def get_csa_table( + findings: list, + bulk_checks_metadata: dict, + compliance_framework: str, + output_filename: str, + output_directory: str, + compliance_overview: bool, +): + section_table = { + "Provider": [], + "Section": [], + "Status": [], + "Muted": [], + } + pass_count = [] + fail_count = [] + muted_count = [] + sections = {} + for index, finding in enumerate(findings): + check = bulk_checks_metadata[finding.check_metadata.CheckID] + check_compliances = check.Compliance + for compliance in check_compliances: + if ( + compliance.Framework == "CSA-CCM" + and compliance.Version in compliance_framework + ): + for requirement in compliance.Requirements: + for attribute in requirement.Attributes: + section = attribute.Section + + if section not in sections: + sections[section] = {"FAIL": 0, "PASS": 0, "Muted": 0} + + if finding.muted: + if index not in muted_count: + muted_count.append(index) + sections[section]["Muted"] += 1 + else: + if finding.status == "FAIL" and index not in fail_count: + fail_count.append(index) + sections[section]["FAIL"] += 1 + elif finding.status == "PASS" and index not in pass_count: + pass_count.append(index) + sections[section]["PASS"] += 1 + + sections = dict(sorted(sections.items())) + for section in sections: + section_table["Provider"].append(compliance.Provider) + section_table["Section"].append(section) + if sections[section]["FAIL"] > 0: + section_table["Status"].append( + f"{Fore.RED}FAIL({sections[section]['FAIL']}){Style.RESET_ALL}" + ) + else: + if sections[section]["PASS"] > 0: + section_table["Status"].append( + f"{Fore.GREEN}PASS({sections[section]['PASS']}){Style.RESET_ALL}" + ) + else: + section_table["Status"].append(f"{Fore.GREEN}PASS{Style.RESET_ALL}") + section_table["Muted"].append( + f"{orange_color}{sections[section]['Muted']}{Style.RESET_ALL}" + ) + + if ( + len(fail_count) + len(pass_count) + len(muted_count) > 1 + ): # If there are no resources, don't print the compliance table + print( + f"\nCompliance Status of {Fore.YELLOW}{compliance_framework.upper()}{Style.RESET_ALL} Framework:" + ) + total_findings_count = len(fail_count) + len(pass_count) + len(muted_count) + overview_table = [ + [ + f"{Fore.RED}{round(len(fail_count) / total_findings_count * 100, 2)}% ({len(fail_count)}) FAIL{Style.RESET_ALL}", + f"{Fore.GREEN}{round(len(pass_count) / total_findings_count * 100, 2)}% ({len(pass_count)}) PASS{Style.RESET_ALL}", + f"{orange_color}{round(len(muted_count) / total_findings_count * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}", + ] + ] + print(tabulate(overview_table, tablefmt="rounded_grid")) + if not compliance_overview: + if len(fail_count) > 0 and len(section_table["Section"]) > 0: + print( + f"\nFramework {Fore.YELLOW}{compliance_framework.upper()}{Style.RESET_ALL} Results:" + ) + print( + tabulate( + section_table, + tablefmt="rounded_grid", + headers="keys", + ) + ) + print(f"\nDetailed results of {compliance_framework.upper()} are in:") + print( + f" - CSV: {output_directory}/compliance/{output_filename}_{compliance_framework}.csv\n" + ) diff --git a/prowler/lib/outputs/compliance/csa/csa_aws.py b/prowler/lib/outputs/compliance/csa/csa_aws.py new file mode 100644 index 0000000000..0f371bfb3a --- /dev/null +++ b/prowler/lib/outputs/compliance/csa/csa_aws.py @@ -0,0 +1,96 @@ +from prowler.config.config import timestamp +from prowler.lib.check.compliance_models import Compliance +from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput +from prowler.lib.outputs.compliance.csa.models import AWSCSAModel +from prowler.lib.outputs.finding import Finding + + +class AWSCSA(ComplianceOutput): + """ + This class represents the AWS CSA compliance output. + + Attributes: + - _data (list): A list to store transformed data from findings. + - _file_descriptor (TextIOWrapper): A file descriptor to write data to a file. + + Methods: + - transform: Transforms findings into AWS CSA compliance format. + """ + + def transform( + self, + findings: list[Finding], + compliance: Compliance, + compliance_name: str, + ) -> None: + """ + Transforms a list of findings into AWS CSA compliance format. + + Parameters: + - findings (list): A list of findings. + - compliance (Compliance): A compliance model. + - compliance_name (str): The name of the compliance model. + + Returns: + - None + """ + for finding in findings: + # Get the compliance requirements for the finding + finding_requirements = finding.compliance.get(compliance_name, []) + for requirement in compliance.Requirements: + if requirement.Id in finding_requirements: + for attribute in requirement.Attributes: + compliance_row = AWSCSAModel( + Provider=finding.provider, + Description=compliance.Description, + AccountId=finding.account_uid, + Region=finding.region, + AssessmentDate=str(timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Name=requirement.Name, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_CCMLite=attribute.CCMLite, + Requirements_Attributes_IaaS=attribute.IaaS, + Requirements_Attributes_PaaS=attribute.PaaS, + Requirements_Attributes_SaaS=attribute.SaaS, + Requirements_Attributes_ScopeApplicability=attribute.ScopeApplicability, + Status=finding.status, + StatusExtended=finding.status_extended, + ResourceId=finding.resource_uid, + ResourceName=finding.resource_name, + CheckId=finding.check_id, + Muted=finding.muted, + Framework=compliance.Framework, + Name=compliance.Name, + ) + self._data.append(compliance_row) + # Add manual requirements to the compliance output + for requirement in compliance.Requirements: + if not requirement.Checks: + for attribute in requirement.Attributes: + compliance_row = AWSCSAModel( + Provider=compliance.Provider.lower(), + Description=compliance.Description, + AccountId="", + Region="", + AssessmentDate=str(timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Name=requirement.Name, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_CCMLite=attribute.CCMLite, + Requirements_Attributes_IaaS=attribute.IaaS, + Requirements_Attributes_PaaS=attribute.PaaS, + Requirements_Attributes_SaaS=attribute.SaaS, + Requirements_Attributes_ScopeApplicability=attribute.ScopeApplicability, + Status="MANUAL", + StatusExtended="Manual check", + ResourceId="manual_check", + ResourceName="Manual check", + CheckId="manual", + Muted=False, + Framework=compliance.Framework, + Name=compliance.Name, + ) + self._data.append(compliance_row) diff --git a/prowler/lib/outputs/compliance/csa/models.py b/prowler/lib/outputs/compliance/csa/models.py new file mode 100644 index 0000000000..2e9ad3a4f5 --- /dev/null +++ b/prowler/lib/outputs/compliance/csa/models.py @@ -0,0 +1,30 @@ +from pydantic.v1 import BaseModel + + +class AWSCSAModel(BaseModel): + """ + AWSCSAModel generates a finding's output in CSV CSA format for AWS. + """ + + Provider: str + Description: str + AccountId: str + Region: str + AssessmentDate: str + Requirements_Id: str + Requirements_Description: str + Requirements_Name: str + Requirements_Attributes_Section: str + Requirements_Attributes_CCMLite: str + Requirements_Attributes_IaaS: str + Requirements_Attributes_PaaS: str + Requirements_Attributes_SaaS: str + Requirements_Attributes_ScopeApplicability: list[dict] + Status: str + StatusExtended: str + ResourceId: str + CheckId: str + Muted: bool + ResourceName: str + Framework: str + Name: str diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 069e8b40ec..f13e3406a0 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to the **Prowler UI** are documented in this file. ### 🔄 Changed - Attack Paths: Query list now shows their name and short description, when one is selected it also shows a longer description and an attribution if it has it [(#9983)](https://github.com/prowler-cloud/prowler/pull/9983) +- CSA CCM detailed view and small fix related with `Top Failed Sections` width [(#10018)](https://github.com/prowler-cloud/prowler/pull/10018) --- diff --git a/ui/app/(prowler)/compliance/[compliancetitle]/page.tsx b/ui/app/(prowler)/compliance/[compliancetitle]/page.tsx index 294d637b24..93c90912f8 100644 --- a/ui/app/(prowler)/compliance/[compliancetitle]/page.tsx +++ b/ui/app/(prowler)/compliance/[compliancetitle]/page.tsx @@ -151,8 +151,9 @@ export default async function ComplianceDetail({ {/* Mobile: each card on own row | Tablet: ThreatScore full row, others share row | Desktop: all 3 in one row */}
{isThreatScore && ( @@ -209,7 +210,7 @@ const SSRComplianceContent = async ({ if (!scanId || type === "tasks") { return (
-
+
{/* */} @@ -244,8 +245,9 @@ const SSRComplianceContent = async ({ {/* Mobile: each card on own row | Tablet: ThreatScore full row, others share row | Desktop: all 3 in one row */}
{threatScoreData && ( diff --git a/ui/components/compliance/compliance-custom-details/csa-details.tsx b/ui/components/compliance/compliance-custom-details/csa-details.tsx new file mode 100644 index 0000000000..738e4a8aab --- /dev/null +++ b/ui/components/compliance/compliance-custom-details/csa-details.tsx @@ -0,0 +1,93 @@ +import { cn } from "@/lib"; +import { CSA_MAPPING_SECTIONS } from "@/lib/compliance/csa"; +import { Requirement } from "@/types/compliance"; + +import { + ComplianceBadge, + ComplianceBadgeContainer, + ComplianceDetailContainer, + ComplianceDetailSection, + ComplianceDetailText, +} from "./shared-components"; + +interface CSADetailsProps { + requirement: Requirement; +} + +export const CSACustomDetails = ({ requirement }: CSADetailsProps) => { + const mappingSections = CSA_MAPPING_SECTIONS.map((section) => ({ + ...section, + data: requirement[section.key] as Array<{ + ReferenceId: string; + Identifiers: string[]; + }>, + })).filter((section) => section.data && section.data.length > 0); + + return ( + + {requirement.description && ( + + {requirement.description} + + )} + + + {requirement.ccm_lite && ( + + )} + {requirement.iaas && ( + + )} + {requirement.paas && ( + + )} + {requirement.saas && ( + + )} + + + {mappingSections.map((section) => ( + +
+ {section.data.map((mapping, index) => ( +
+ + {mapping.ReferenceId} + +
+ {mapping.Identifiers.map((identifier, idx) => ( + + {identifier} + + ))} +
+
+ ))} +
+
+ ))} +
+ ); +}; diff --git a/ui/components/icons/compliance/IconCompliance.tsx b/ui/components/icons/compliance/IconCompliance.tsx index aac9801eb3..032e0bdecc 100644 --- a/ui/components/icons/compliance/IconCompliance.tsx +++ b/ui/components/icons/compliance/IconCompliance.tsx @@ -3,6 +3,7 @@ import C5Logo from "./c5.svg"; import CCCLogo from "./ccc.svg"; import CISLogo from "./cis.svg"; import CISALogo from "./cisa.svg"; +import CSALogo from "./csa.svg"; import ENSLogo from "./ens.png"; import FedRAMPLogo from "./fedramp.svg"; import FFIECLogo from "./ffiec.svg"; @@ -40,6 +41,7 @@ const COMPLIANCE_LOGOS = { nis2: NIS2Logo, c5: C5Logo, ccc: CCCLogo, + csa: CSALogo, } as const; export const getComplianceIcon = (complianceTitle: string) => { diff --git a/ui/components/icons/compliance/csa.svg b/ui/components/icons/compliance/csa.svg new file mode 100644 index 0000000000..99204d146e --- /dev/null +++ b/ui/components/icons/compliance/csa.svg @@ -0,0 +1 @@ + diff --git a/ui/lib/compliance/compliance-mapper.ts b/ui/lib/compliance/compliance-mapper.ts index 2446156e2b..0c739fa322 100644 --- a/ui/lib/compliance/compliance-mapper.ts +++ b/ui/lib/compliance/compliance-mapper.ts @@ -4,6 +4,7 @@ import { AWSWellArchitectedCustomDetails } from "@/components/compliance/complia import { C5CustomDetails } from "@/components/compliance/compliance-custom-details/c5-details"; import { CCCCustomDetails } from "@/components/compliance/compliance-custom-details/ccc-details"; import { CISCustomDetails } from "@/components/compliance/compliance-custom-details/cis-details"; +import { CSACustomDetails } from "@/components/compliance/compliance-custom-details/csa-details"; import { ENSCustomDetails } from "@/components/compliance/compliance-custom-details/ens-details"; import { GenericCustomDetails } from "@/components/compliance/compliance-custom-details/generic-details"; import { ISOCustomDetails } from "@/components/compliance/compliance-custom-details/iso-details"; @@ -37,6 +38,10 @@ import { toAccordionItems as toCISAccordionItems, } from "./cis"; import { calculateCategoryHeatmapData, getTopFailedSections } from "./commons"; +import { + mapComplianceData as mapCSAComplianceData, + toAccordionItems as toCSAAccordionItems, +} from "./csa"; import { mapComplianceData as mapENSComplianceData, toAccordionItems as toENSAccordionItems, @@ -179,6 +184,15 @@ const getComplianceMappers = (): Record => ({ getDetailsComponent: (requirement: Requirement) => createElement(CCCCustomDetails, { requirement }), }, + "CSA-CCM": { + mapComplianceData: mapCSAComplianceData, + toAccordionItems: toCSAAccordionItems, + getTopFailedSections, + calculateCategoryHeatmapData: (data: Framework[]) => + calculateCategoryHeatmapData(data), + getDetailsComponent: (requirement: Requirement) => + createElement(CSACustomDetails, { requirement }), + }, }); /** diff --git a/ui/lib/compliance/csa.tsx b/ui/lib/compliance/csa.tsx new file mode 100644 index 0000000000..93974d6b47 --- /dev/null +++ b/ui/lib/compliance/csa.tsx @@ -0,0 +1,143 @@ +import { ClientAccordionContent } from "@/components/compliance/compliance-accordion/client-accordion-content"; +import { ComplianceAccordionRequirementTitle } from "@/components/compliance/compliance-accordion/compliance-accordion-requeriment-title"; +import { ComplianceAccordionTitle } from "@/components/compliance/compliance-accordion/compliance-accordion-title"; +import { AccordionItemProps } from "@/components/ui/accordion/Accordion"; +import { FindingStatus } from "@/components/ui/table/status-finding-badge"; +import { + AttributesData, + CSAAttributesMetadata, + Framework, + Requirement, + REQUIREMENT_STATUS, + RequirementsData, + RequirementStatus, +} from "@/types/compliance"; + +import { + calculateFrameworkCounters, + createRequirementsMap, + findOrCreateCategory, + findOrCreateControl, + findOrCreateFramework, +} from "./commons"; + +export interface CSAMappingSection { + title: string; + key: keyof Requirement; + colorClasses: string; +} + +export const CSA_MAPPING_SECTIONS: CSAMappingSection[] = [ + { + title: "Scope Applicability", + key: "scope_applicability", + colorClasses: + "bg-blue-50 text-blue-700 ring-blue-600/10 dark:bg-blue-400/10 dark:text-blue-400 dark:ring-blue-400/20", + }, +]; + +const getStatusCounters = (status: RequirementStatus) => ({ + pass: status === REQUIREMENT_STATUS.PASS ? 1 : 0, + fail: status === REQUIREMENT_STATUS.FAIL ? 1 : 0, + manual: status === REQUIREMENT_STATUS.MANUAL ? 1 : 0, +}); + +export const mapComplianceData = ( + attributesData: AttributesData, + requirementsData: RequirementsData, +): Framework[] => { + const attributes = attributesData?.data || []; + const requirementsMap = createRequirementsMap(requirementsData); + const frameworks: Framework[] = []; + + for (const attributeItem of attributes) { + const id = attributeItem.id; + const metadataArray = attributeItem.attributes?.attributes + ?.metadata as unknown as CSAAttributesMetadata[]; + const attrs = metadataArray?.[0]; + if (!attrs) continue; + + const requirementData = requirementsMap.get(id); + if (!requirementData) continue; + + const frameworkName = attributeItem.attributes.framework; + const categoryName = attrs.Section; + const requirementName = attributeItem.attributes.name || ""; + const description = attributeItem.attributes.description; + const status = requirementData.attributes.status || ""; + const checks = attributeItem.attributes.attributes.check_ids || []; + + const framework = findOrCreateFramework(frameworks, frameworkName); + const category = findOrCreateCategory(framework.categories, categoryName); + // Use a single control per category to keep a flat 2-level structure + const control = findOrCreateControl(category.controls, categoryName); + + const finalStatus: RequirementStatus = status as RequirementStatus; + const requirement: Requirement = { + name: requirementName ? `${id} - ${requirementName}` : id, + description, + status: finalStatus, + check_ids: checks, + ...getStatusCounters(finalStatus), + ccm_lite: attrs.CCMLite, + iaas: attrs.IaaS, + paas: attrs.PaaS, + saas: attrs.SaaS, + scope_applicability: attrs.ScopeApplicability, + }; + + control.requirements.push(requirement); + } + + calculateFrameworkCounters(frameworks); + + return frameworks; +}; + +export const toAccordionItems = ( + data: Framework[], + scanId: string | undefined, +): AccordionItemProps[] => { + const safeId = scanId || ""; + + return data.flatMap((framework) => + framework.categories.map((category) => ({ + key: `${framework.name}-${category.name}`, + title: ( + + ), + content: "", + // Flatten: requirements are direct children of the section + items: category.controls.flatMap((control) => + control.requirements.map((requirement, reqIndex) => ({ + key: `${framework.name}-${category.name}-req-${reqIndex}`, + title: ( + + ), + content: ( + + ), + items: [], + })), + ), + })), + ); +}; diff --git a/ui/types/compliance.ts b/ui/types/compliance.ts index 5c77ed1ee0..1557671537 100644 --- a/ui/types/compliance.ts +++ b/ui/types/compliance.ts @@ -189,6 +189,18 @@ export interface GenericAttributesMetadata { Type: string | null; } +export interface CSAAttributesMetadata { + Section: string; + CCMLite: string; + IaaS: string; + PaaS: string; + SaaS: string; + ScopeApplicability: Array<{ + ReferenceId: string; + Identifiers: string[]; + }>; +} + export interface CCCAttributesMetadata { FamilyName: string; FamilyDescription: string; @@ -227,6 +239,7 @@ export interface AttributesItemData { | C5AttributesMetadata[] | MITREAttributesMetadata[] | CCCAttributesMetadata[] + | CSAAttributesMetadata[] | GenericAttributesMetadata[]; check_ids: string[]; // MITRE structure From 78bd9adeedd544c230babba4fe9af8f6ac3c3e7d Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Thu, 12 Feb 2026 13:15:51 +0100 Subject: [PATCH 03/12] chore(cloudflare): parallelize zone API calls with threading (#9982) Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + .../cloudflare/lib/service/service.py | 31 +++ .../cloudflare/services/zone/zone_service.py | 198 ++++++++---------- 3 files changed, 115 insertions(+), 115 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index a28b648618..9f43f4f4c9 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to the **Prowler SDK** are documented in this file. ### 🔄 Changed - Update Azure Monitor service metadata to new format [(#9622)](https://github.com/prowler-cloud/prowler/pull/9622) +- Parallelize Cloudflare zone API calls with threading to improve scan performance [(#9982)](https://github.com/prowler-cloud/prowler/pull/9982) ## [5.18.2] (Prowler UNRELEASED) diff --git a/prowler/providers/cloudflare/lib/service/service.py b/prowler/providers/cloudflare/lib/service/service.py index 8a1ea7484e..9eceef3592 100644 --- a/prowler/providers/cloudflare/lib/service/service.py +++ b/prowler/providers/cloudflare/lib/service/service.py @@ -1,5 +1,10 @@ +from concurrent.futures import ThreadPoolExecutor, as_completed + +from prowler.lib.logger import logger from prowler.providers.cloudflare.cloudflare_provider import CloudflareProvider +MAX_WORKERS = 10 + class CloudflareService: """Base class for Cloudflare services to share provider context.""" @@ -10,3 +15,29 @@ class CloudflareService: self.audit_config = provider.audit_config self.fixer_config = provider.fixer_config self.service = service.lower() if not service.islower() else service + + # Thread pool for __threading_call__ + self.thread_pool = ThreadPoolExecutor(max_workers=MAX_WORKERS) + + def __threading_call__(self, call, iterator): + """Execute a function across multiple items using threading.""" + items = list(iterator) if not isinstance(iterator, list) else iterator + + futures = {self.thread_pool.submit(call, item): item for item in items} + results = [] + + for future in as_completed(futures): + try: + result = future.result() + if result is not None: + results.append(result) + except Exception as error: + # Log unhandled exceptions from threaded calls + item = futures[future] + item_id = getattr(item, "id", str(item)) + logger.error( + f"{self.service} - Threading error processing {item_id}: " + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + + return results diff --git a/prowler/providers/cloudflare/services/zone/zone_service.py b/prowler/providers/cloudflare/services/zone/zone_service.py index 1fdb133e68..040bd59e92 100644 --- a/prowler/providers/cloudflare/services/zone/zone_service.py +++ b/prowler/providers/cloudflare/services/zone/zone_service.py @@ -49,13 +49,13 @@ class Zone(CloudflareService): super().__init__(__class__.__name__, provider) self.zones: dict[str, "CloudflareZone"] = {} self._list_zones() - self._get_zones_settings() - self._get_zones_dnssec() - self._get_zones_universal_ssl() - self._get_zones_rate_limit_rules() - self._get_zones_bot_management() - self._get_zones_firewall_rules() - self._get_zones_waf_rulesets() + self.__threading_call__(self._get_zone_settings_threaded, self.zones.values()) + self.__threading_call__(self._get_zone_dnssec, self.zones.values()) + self.__threading_call__(self._get_zone_universal_ssl, self.zones.values()) + self.__threading_call__(self._get_zone_rate_limit_rules, self.zones.values()) + self.__threading_call__(self._get_zone_bot_management, self.zones.values()) + self.__threading_call__(self._get_zone_firewall_rules, self.zones.values()) + self.__threading_call__(self._get_zone_waf_rulesets, self.zones.values()) def _list_zones(self) -> None: """List all Cloudflare zones with their basic information.""" @@ -124,110 +124,89 @@ class Zone(CloudflareService): f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) - def _get_zones_settings(self) -> None: - """Get settings for all zones.""" - logger.info("Zone - Getting zone settings...") - for zone in self.zones.values(): - try: - zone.settings = self._get_zone_settings(zone.id) - except Exception as error: - logger.error( - f"{zone.id} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" - ) + def _get_zone_settings_threaded(self, zone: "CloudflareZone") -> None: + """Get settings for a single zone (thread-safe).""" + try: + zone.settings = self._get_zone_settings(zone.id) + except Exception as error: + logger.error( + f"{zone.id} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) - def _get_zones_dnssec(self) -> None: - """Get DNSSEC status for all zones.""" - logger.info("Zone - Getting DNSSEC status...") - for zone in self.zones.values(): - try: - dnssec = self.client.dns.dnssec.get(zone_id=zone.id) - zone.dnssec_status = getattr(dnssec, "status", None) - except Exception as error: - logger.error( - f"{zone.id} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" - ) + def _get_zone_dnssec(self, zone: "CloudflareZone") -> None: + """Get DNSSEC status for a single zone.""" + try: + dnssec = self.client.dns.dnssec.get(zone_id=zone.id) + zone.dnssec_status = getattr(dnssec, "status", None) + except Exception as error: + logger.error( + f"{zone.id} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) - def _get_zones_universal_ssl(self) -> None: - """Get Universal SSL settings for all zones.""" - logger.info("Zone - Getting Universal SSL settings...") - for zone in self.zones.values(): - try: - universal_ssl = self.client.ssl.universal.settings.get(zone_id=zone.id) - zone.settings.universal_ssl_enabled = getattr( - universal_ssl, "enabled", False - ) - except Exception as error: - logger.error( - f"{zone.id} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" - ) + def _get_zone_universal_ssl(self, zone: "CloudflareZone") -> None: + """Get Universal SSL settings for a single zone.""" + try: + universal_ssl = self.client.ssl.universal.settings.get(zone_id=zone.id) + zone.settings.universal_ssl_enabled = getattr( + universal_ssl, "enabled", False + ) + except Exception as error: + logger.error( + f"{zone.id} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) - def _get_zones_rate_limit_rules(self) -> None: - """Get rate limiting rules for all zones.""" - logger.info("Zone - Getting rate limit rules...") - for zone in self.zones.values(): - try: - seen_ruleset_ids: set[str] = set() - for ruleset in self.client.rulesets.list(zone_id=zone.id): - ruleset_id = getattr(ruleset, "id", "") - if ruleset_id in seen_ruleset_ids: - break - seen_ruleset_ids.add(ruleset_id) + def _get_zone_rate_limit_rules(self, zone: "CloudflareZone") -> None: + """Get rate limiting rules for a single zone.""" + try: + seen_ruleset_ids: set[str] = set() + for ruleset in self.client.rulesets.list(zone_id=zone.id): + ruleset_id = getattr(ruleset, "id", "") + if ruleset_id in seen_ruleset_ids: + break + seen_ruleset_ids.add(ruleset_id) - phase = getattr(ruleset, "phase", "") - if phase == "http_ratelimit": - try: - ruleset_detail = self.client.rulesets.get( - ruleset_id=ruleset_id, zone_id=zone.id - ) - rules = getattr(ruleset_detail, "rules", []) or [] - seen_rule_ids: set[str] = set() - for rule in rules: - rule_id = getattr(rule, "id", "") - if rule_id in seen_rule_ids: - break - seen_rule_ids.add(rule_id) - zone.rate_limit_rules.append( - CloudflareRateLimitRule( - id=rule_id, - description=getattr(rule, "description", None), - action=getattr(rule, "action", None), - enabled=getattr(rule, "enabled", True), - expression=getattr(rule, "expression", None), - ) + phase = getattr(ruleset, "phase", "") + if phase == "http_ratelimit": + try: + ruleset_detail = self.client.rulesets.get( + ruleset_id=ruleset_id, zone_id=zone.id + ) + rules = getattr(ruleset_detail, "rules", []) or [] + seen_rule_ids: set[str] = set() + for rule in rules: + rule_id = getattr(rule, "id", "") + if rule_id in seen_rule_ids: + break + seen_rule_ids.add(rule_id) + zone.rate_limit_rules.append( + CloudflareRateLimitRule( + id=rule_id, + description=getattr(rule, "description", None), + action=getattr(rule, "action", None), + enabled=getattr(rule, "enabled", True), + expression=getattr(rule, "expression", None), ) - except Exception as error: - logger.debug( - f"{zone.id} ruleset {ruleset_id} -- {error.__class__.__name__}: {error}" ) - except Exception as error: - logger.error( - f"{zone.id} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" - ) + except Exception as error: + logger.debug( + f"{zone.id} ruleset {ruleset_id} -- {error.__class__.__name__}: {error}" + ) + except Exception as error: + logger.error( + f"{zone.id} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) - def _get_zones_bot_management(self) -> None: - """Get Bot Management settings for all zones.""" - logger.info("Zone - Getting Bot Management settings...") - for zone in self.zones.values(): - try: - bot_management = self.client.bot_management.get(zone_id=zone.id) - zone.settings.bot_fight_mode_enabled = getattr( - bot_management, "fight_mode", False - ) - except Exception as error: - logger.error( - f"{zone.id} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" - ) - - def _get_zones_firewall_rules(self) -> None: - """Get firewall rules for all zones.""" - logger.info("Zone - Getting firewall rules...") - for zone in self.zones.values(): - try: - self._get_zone_firewall_rules(zone) - except Exception as error: - logger.error( - f"{zone.id} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" - ) + def _get_zone_bot_management(self, zone: "CloudflareZone") -> None: + """Get Bot Management settings for a single zone.""" + try: + bot_management = self.client.bot_management.get(zone_id=zone.id) + zone.settings.bot_fight_mode_enabled = getattr( + bot_management, "fight_mode", False + ) + except Exception as error: + logger.error( + f"{zone.id} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) def _get_zone_firewall_rules(self, zone: "CloudflareZone") -> None: """List firewall rules from custom rulesets for a zone.""" @@ -282,17 +261,6 @@ class Zone(CloudflareService): f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) - def _get_zones_waf_rulesets(self) -> None: - """Get WAF rulesets for all zones.""" - logger.info("Zone - Getting WAF rulesets...") - for zone in self.zones.values(): - try: - self._get_zone_waf_rulesets(zone) - except Exception as error: - logger.error( - f"{zone.id} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" - ) - def _get_zone_waf_rulesets(self, zone: "CloudflareZone") -> None: """List WAF rulesets for a zone using the rulesets API.""" seen_ids: set[str] = set() From 29090adb039a690af4d781849f3fda91ceff2091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Thu, 12 Feb 2026 13:35:22 +0100 Subject: [PATCH 04/12] feat(compliance): add csa ccm for the azure provider (#10039) --- api/CHANGELOG.md | 1 + api/src/backend/tasks/jobs/export.py | 2 + dashboard/compliance/csa_ccm_4_0_azure.py | 31 + prowler/CHANGELOG.md | 1 + prowler/__main__.py | 13 + .../compliance/azure/csa_ccm_4.0_azure.json | 7548 +++++++++++++++++ .../lib/outputs/compliance/csa/csa_azure.py | 96 + prowler/lib/outputs/compliance/csa/models.py | 29 + 8 files changed, 7721 insertions(+) create mode 100644 dashboard/compliance/csa_ccm_4_0_azure.py create mode 100644 prowler/compliance/azure/csa_ccm_4.0_azure.json create mode 100644 prowler/lib/outputs/compliance/csa/csa_azure.py diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 1b57de2998..4ff37ae274 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to the **Prowler API** are documented in this file. - Attack Paths: Queries definition now has short description and attribution [(#9983)](https://github.com/prowler-cloud/prowler/pull/9983) - Attack Paths: Internet node is created while scan [(#9992)](https://github.com/prowler-cloud/prowler/pull/9992) - Support CSA CCM for the AWS provider [(#10018)](https://github.com/prowler-cloud/prowler/pull/10018) +- Support CSA CCM for the Azure provider [(#10039)](https://github.com/prowler-cloud/prowler/pull/10039) --- diff --git a/api/src/backend/tasks/jobs/export.py b/api/src/backend/tasks/jobs/export.py index c652095fba..494e48a12a 100644 --- a/api/src/backend/tasks/jobs/export.py +++ b/api/src/backend/tasks/jobs/export.py @@ -36,6 +36,7 @@ from prowler.lib.outputs.compliance.cis.cis_kubernetes import KubernetesCIS from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS from prowler.lib.outputs.compliance.cis.cis_oraclecloud import OracleCloudCIS from prowler.lib.outputs.compliance.csa.csa_aws import AWSCSA +from prowler.lib.outputs.compliance.csa.csa_azure import AzureCSA from prowler.lib.outputs.compliance.ens.ens_aws import AWSENS from prowler.lib.outputs.compliance.ens.ens_azure import AzureENS from prowler.lib.outputs.compliance.ens.ens_gcp import GCPENS @@ -101,6 +102,7 @@ COMPLIANCE_CLASS_MAP = { (lambda name: name == "ccc_azure", CCC_Azure), (lambda name: name == "prowler_threatscore_azure", ProwlerThreatScoreAzure), (lambda name: name == "c5_azure", AzureC5), + (lambda name: name.startswith("csa_"), AzureCSA), ], "gcp": [ (lambda name: name.startswith("cis_"), GCPCIS), diff --git a/dashboard/compliance/csa_ccm_4_0_azure.py b/dashboard/compliance/csa_ccm_4_0_azure.py new file mode 100644 index 0000000000..346576729d --- /dev/null +++ b/dashboard/compliance/csa_ccm_4_0_azure.py @@ -0,0 +1,31 @@ +import warnings + +from dashboard.common_methods import get_section_containers_kisa_ismsp + +warnings.filterwarnings("ignore") + + +def get_table(data): + data["REQUIREMENTS_ID"] = ( + data["REQUIREMENTS_ID"] + " - " + data["REQUIREMENTS_DESCRIPTION"] + ) + + data["REQUIREMENTS_ID"] = data["REQUIREMENTS_ID"].apply( + lambda x: x[:150] + "..." if len(str(x)) > 150 else x + ) + + aux = data[ + [ + "REQUIREMENTS_ID", + "REQUIREMENTS_ATTRIBUTES_SECTION", + "CHECKID", + "STATUS", + "REGION", + "ACCOUNTID", + "RESOURCEID", + ] + ].copy() + + return get_section_containers_kisa_ismsp( + aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID" + ) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 9f43f4f4c9..e2ade79ce4 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - `defender_safelinks_policy_enabled` check for M365 provider [(#9832)](https://github.com/prowler-cloud/prowler/pull/9832) - AI Skills: Added a skill for creating new Attack Paths queries in openCypher, compatible with Neo4j and Neptune [(#9975)](https://github.com/prowler-cloud/prowler/pull/9975) - CSA CCM 4.0 for the AWS provider [(#10018)](https://github.com/prowler-cloud/prowler/pull/10018) +- CSA CCM for the Azure provider [(#10039)](https://github.com/prowler-cloud/prowler/pull/10039) ### 🔄 Changed diff --git a/prowler/__main__.py b/prowler/__main__.py index a9344ec433..ac3c587e65 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -66,6 +66,7 @@ from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS from prowler.lib.outputs.compliance.cis.cis_oraclecloud import OracleCloudCIS from prowler.lib.outputs.compliance.compliance import display_compliance_table from prowler.lib.outputs.compliance.csa.csa_aws import AWSCSA +from prowler.lib.outputs.compliance.csa.csa_azure import AzureCSA from prowler.lib.outputs.compliance.ens.ens_aws import AWSENS from prowler.lib.outputs.compliance.ens.ens_azure import AzureENS from prowler.lib.outputs.compliance.ens.ens_gcp import GCPENS @@ -742,6 +743,18 @@ def prowler(): ) generated_outputs["compliance"].append(c5_azure) c5_azure.batch_write_data_to_file() + elif compliance_name == "csa_ccm_4.0_azure": + filename = ( + f"{output_options.output_directory}/compliance/" + f"{output_options.output_filename}_{compliance_name}.csv" + ) + csa_ccm_4_0_azure = AzureCSA( + findings=finding_outputs, + compliance=bulk_compliance_frameworks[compliance_name], + file_path=filename, + ) + generated_outputs["compliance"].append(csa_ccm_4_0_azure) + csa_ccm_4_0_azure.batch_write_data_to_file() else: filename = ( f"{output_options.output_directory}/compliance/" diff --git a/prowler/compliance/azure/csa_ccm_4.0_azure.json b/prowler/compliance/azure/csa_ccm_4.0_azure.json new file mode 100644 index 0000000000..b4505ac089 --- /dev/null +++ b/prowler/compliance/azure/csa_ccm_4.0_azure.json @@ -0,0 +1,7548 @@ +{ + "Framework": "CSA-CCM", + "Name": "CSA Cloud Controls Matrix (CCM) v4.0.13", + "Version": "4.0", + "Provider": "Azure", + "Description": "The Cloud Security Alliance (CSA) Cloud Controls Matrix (CCM) is a cybersecurity control framework for cloud computing, composed of 197 control objectives structured in 17 domains covering all key aspects of cloud technology. The CCM can be used as a tool for the systematic assessment of a cloud implementation, and provides guidance on which security controls should be implemented by which actor within the cloud supply chain.", + "Requirements": [ + { + "Id": "A&A-02", + "Description": "Conduct independent audit and assurance assessments according to relevant standards at least annually.", + "Name": "Independent Assessments", + "Attributes": [ + { + "Section": "Audit & Assurance", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC4.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "AAC-02" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.5.2", + "5.2.6" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "AS1.1", + "AS2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.2.1", + "27002: 18.2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.35", + "27001: A.5.36" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CA-2", + "CA-2(1)", + "CA-2(2)", + "CA-7", + "CA-7(1)" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.IM-01" + ] + } + ] + } + ], + "Checks": [ + "defender_ensure_defender_for_app_services_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_databases_is_on", + "defender_ensure_defender_for_keyvault_is_on", + "defender_ensure_defender_for_server_is_on" + ] + }, + { + "Id": "A&A-04", + "Description": "Verify compliance with all relevant standards, regulations, legal/contractual, and statutory requirements applicable to the audit.", + "Name": "Requirements Compliance", + "Attributes": [ + { + "Section": "Audit & Assurance", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC3.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-01", + "GRM-03" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "7.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "AS1.1", + "AS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 9.3.2", + "27001: A.18.2.2", + "27002: 18.2.2", + "27001: A.18.2.3", + "27002: 18.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 9.3.2", + "27001: A.5.31", + "27001: A.5.32", + "27001: A.5.33", + "27001: A.5.34", + "27001: A.5.36" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CA-1" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-3", + "DE.DP-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.IM-01" + ] + } + ] + } + ], + "Checks": [ + "defender_ensure_defender_for_app_services_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_databases_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_mcas_is_enabled", + "monitor_diagnostic_settings_exists", + "policy_ensure_asc_enforcement_enabled" + ] + }, + { + "Id": "AIS-04", + "Description": "Define and implement a SDLC process for application design, development, deployment, and operation in accordance with security requirements defined by the organization.", + "Name": "Secure Application Design and Development", + "Attributes": [ + { + "Section": "Application & Interface Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.8", + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "AIS-01", + "AIS-03" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.3.4", + "5.3.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SD1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.14.1.1", + "27002: 14.1.1", + "27017: 14.1.1", + "27001: A.14.1.2", + "27002: 14.1.2", + "27017: 14.1.2", + "27001: A.14.2.1", + "27002: 14.2.1", + "27017: 14.2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.8", + "27001: A.8.25", + "27001: A.8.26", + "27001: A.8.28" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PL-2", + "PL-8", + "PL-8(1)", + "SA-3", + "SA-3(1)", + "SA-4", + "SA-4(2)", + "SA-4(3)", + "SA-4(8)", + "SA-4(9)", + "SA-5", + "SA-8", + "SA-8(1)-(7)", + "SA-8(9)-(13)", + "SA-8(15)-(20)", + "SA-8(22)", + "SA-8(24)-(28)", + "SA-8(30)-(33)", + "SA-17", + "SA-17(1)-(9)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-6", + "PR.DS-7", + "PR.IP-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "PR.IR-01", + "PR.PS-01", + "PR.PS-02", + "PR.PS-06" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.3" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.2.1", + "6.2.3", + "6.5.2" + ] + } + ] + } + ], + "Checks": [ + "app_ensure_auth_is_set_up", + "app_ftp_deployment_disabled", + "app_function_access_keys_configured", + "app_function_ftps_deployment_disabled", + "app_register_with_identity" + ] + }, + { + "Id": "AIS-05", + "Description": "Implement a testing strategy, including criteria for acceptance of new information systems, upgrades and new versions, which provides application security assurance and maintains compliance while enabling organizational speed of delivery goals. Automate when applicable and possible.", + "Name": "Automated Application Security Testing", + "Attributes": [ + { + "Section": "Application & Interface Security", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.8", + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "AIS-01", + "AIS-03" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.12", + "16.13" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SD2.3", + "SD2.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.14.2.8", + "27001: A.14.2.9", + "27001: A.12.1.2", + "27002: 12.1.2", + "27001: A.14.1.1", + "27002: 14.1.1", + "27001: A.14.2.2", + "27002: 14.2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.25", + "27001: A.8.29", + "27001: A.8.32", + "27002: 8.25 (e)", + "27002: 8.32 (d)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SA-11", + "SA-11(1)-(9)", + "SI-6", + "SI-6(2)", + "SI-6(3)", + "SI-10", + "SI-10(1)-(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-2", + "PR.PT-3", + "PR.IP-12", + "DE.CM-8" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "ID.RA-01", + "PR.PS-01", + "PR.PS-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "A.3.2.2", + "A.3.2.2.1", + "6.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.2.4", + "6.4.1", + "6.4.2", + "6.5.1" + ] + } + ] + } + ], + "Checks": [ + "defender_auto_provisioning_vulnerabilty_assessments_machines_on", + "defender_container_images_resolved_vulnerabilities", + "defender_container_images_scan_enabled", + "defender_ensure_defender_for_containers_is_on", + "sqlserver_va_periodic_recurring_scans_enabled", + "sqlserver_vulnerability_assessment_enabled" + ] + }, + { + "Id": "AIS-07", + "Description": "Define and implement a process to remediate application security vulnerabilities, automating remediation when possible.", + "Name": "Application Vulnerability Remediation", + "Attributes": [ + { + "Section": "Application & Interface Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.1", + "CC7.4", + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "TVM-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.2", + "16.6" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.16.1.5", + "27002: 16.1.5", + "27017: 16.1.5", + "27001: A.12.6.1", + "27002: 12.6.1", + "27017: 12.6.1", + "27018: 12.6.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.26", + "27001: A.8.8", + "27002: 5.26 (j)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SI-2", + "SI-2(2)-(6)", + "SA-11", + "SA-11(2)", + "SA-15", + "SA-15(1)-(3)", + "SA-15(5)-(8)", + "SA-15(10)-(12)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-2", + "PR.IP-12", + "DE.CM-8", + "RS.AN-5", + "RS.MI-3", + "PR.DS-6" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "ID.RA-01", + "ID.RA-06", + "ID.RA-08", + "PR.PS-02", + "PR.PS-06" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.2", + "6.5", + "6.5.1-10" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.3.1", + "11.3.1", + "11.3.1.1" + ] + } + ] + } + ], + "Checks": [ + "defender_container_images_resolved_vulnerabilities", + "defender_container_images_scan_enabled", + "defender_ensure_defender_for_containers_is_on", + "sqlserver_va_scan_reports_configured", + "sqlserver_vulnerability_assessment_enabled" + ] + }, + { + "Id": "BCR-08", + "Description": "Periodically backup data stored in the cloud. Ensure the confidentiality, integrity and availability of the backup, and verify data restoration from backup for resiliency.", + "Name": "Backup", + "Attributes": [ + { + "Section": "Business Continuity Management and Operational Resilience", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "A1.2", + "A1.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "BCR-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "11.1", + "11.2", + "11.3", + "11.4", + "11.5" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.8", + "5.2.9" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.3", + "27017: 12.3", + "27018: 12.3.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.13", + "27001: A.5.23", + "27001: A.5.30", + "27002: 8.13", + "27002: 5.23 2nd (i)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-4", + "CP-4(4)", + "CP-6", + "CP-6(1)-(3)", + "CP-9", + "CP-9(1)", + "CP-9(2)", + "CP-10", + "CP-10(2)", + "CP-10(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-4", + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01", + "PR.DS-11", + "RC.RP-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "9.5.1", + "12.10.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.10.1", + "10.3.3" + ] + } + ] + } + ], + "Checks": [ + "storage_ensure_encryption_with_customer_managed_keys", + "vm_backup_enabled", + "vm_sufficient_daily_backup_retention_period" + ] + }, + { + "Id": "BCR-09", + "Description": "Establish, document, approve, communicate, apply, evaluate and maintain a disaster response plan to recover from natural and man-made disasters. Update the plan at least annually or upon significant changes.", + "Name": "Disaster Response Plan", + "Attributes": [ + { + "Section": "Business Continuity Management and Operational Resilience", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "A1.2", + "CC3.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.8", + "5.2.9", + "1.6.1", + "1.6.2", + "1.6.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "BC1.4", + "BC2.1", + "BC2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.29", + "27001: A.5.30", + "27002: 5.29", + "27002: 5.30" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-2(1)", + "CP-2(2)", + "CP-2(3)", + "CP-2(5)", + "CP-2(6)", + "CP-2(7)", + "CP-2(8)", + "PE-13", + "PE-13(1)", + "PE-13(2)", + "PE-13(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-9", + "PR.IP-10", + "RC.IM-1", + "RC.IM-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.IM-04" + ] + } + ] + } + ], + "Checks": [ + "defender_ensure_defender_for_server_is_on", + "vm_backup_enabled" + ] + }, + { + "Id": "BCR-11", + "Description": "Supplement business-critical equipment with redundant equipment independently located at a reasonable minimum distance in accordance with applicable industry standards.", + "Name": "Equipment Redundancy", + "Attributes": [ + { + "Section": "Business Continuity Management and Operational Resilience", + "CCMLite": "No", + "IaaS": "CSP-Owned", + "PaaS": "CSP-Owned", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "A1.2", + "CC3.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "BCR-06" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.8" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "BC1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.20", + "27001: A.7.11", + "27001: A.8.14", + "27002: 5.20 (t)", + "27002: 8.14 (c)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-2", + "CP-2(2)", + "CP-4(3)", + "CP-6", + "CP-6(1)", + "CP-7", + "CP-8", + "CP-8(1)-(3)", + "CP-9", + "CP-9(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.BE-4", + "ID.BE-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.OC-04", + "GV.OC-05", + "PR.IR-03" + ] + } + ] + } + ], + "Checks": [ + "storage_blob_versioning_is_enabled", + "storage_geo_redundant_enabled", + "vm_scaleset_associated_with_load_balancer", + "vm_scaleset_not_empty" + ] + }, + { + "Id": "CCC-04", + "Description": "Restrict the unauthorized addition, removal, update, and management of organization assets.", + "Name": "Unauthorized Change Protection", + "Attributes": [ + { + "Section": "Change Control and Configuration Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "CCC-04" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.1", + "1.3.4", + "5.3.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY2.4", + "SM2.6" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.1.4", + "27002: 12.1.4", + "27001: A.12.4.2", + "27002: 12.4.2", + "27001: A.14.2.2", + "27017: 14.2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.3", + "27001: A.8.4", + "27001: A.8.15", + "27001: A.8.31", + "27001: A.8.32" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CA-7", + "CA-7(4)", + "CM-3", + "CM-3(1)", + "CM-3(5)", + "CM-3(7)", + "CM-3(8)", + "CM-5", + "CM-5(1)", + "CM-5(4)", + "CM-5(5)", + "CM-6", + "CM-6(1)", + "CM-6(2)", + "CM-7", + "CM-7(1)", + "CM-7(4)", + "CM-7(5)", + "CM-7(9)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.AM-1", + "ID.AM-2", + "ID.AM-4", + "PR.MA-1", + "PR.MA-2", + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-01", + "ID.AM-02", + "ID.AM-04", + "ID.AM-08", + "PR.PS-02", + "PR.PS-03", + "PR.PS-05", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.4.5.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.5.1", + "6.5.2" + ] + } + ] + } + ], + "Checks": [ + "iam_custom_role_has_permissions_to_administer_resource_locks", + "monitor_alert_create_policy_assignment", + "monitor_diagnostic_setting_with_appropriate_categories", + "monitor_diagnostic_settings_exists", + "policy_ensure_asc_enforcement_enabled", + "storage_ensure_soft_delete_is_enabled" + ] + }, + { + "Id": "CCC-07", + "Description": "Implement detection measures with proactive notification in case of changes deviating from the established baseline.", + "Name": "Detection of Baseline Deviation", + "Attributes": [ + { + "Section": "Change Control and Configuration Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-01" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.5.1", + "1.5.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY2.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.14.2.2", + "27001: A.14.2.4", + "27001: A.12.4.1", + "27002: 12.4.1 (g)", + "27001: A.5.1.1", + "27017: 5.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.9", + "27001: A.8.15", + "27002: 8.9" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-6", + "CM-6(2)", + "SI-2", + "SI-2(2)-(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.MA-1", + "PR.IP-1", + "DE.DP-4", + "PR.IP-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-01", + "DE.CM-09", + "DE.AE-06" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.4.5.3", + "6.4.5.4", + "11.5", + "11.5.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "11.5.2", + "11.6.1" + ] + } + ] + } + ], + "Checks": [ + "defender_ensure_defender_for_app_services_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_wdatp_is_enabled", + "monitor_alert_create_policy_assignment", + "monitor_alert_create_update_nsg", + "monitor_alert_create_update_public_ip_address_rule", + "monitor_alert_create_update_security_solution", + "monitor_alert_create_update_sqlserver_fr", + "monitor_alert_delete_nsg", + "monitor_alert_delete_policy_assignment", + "monitor_alert_delete_public_ip_address_rule", + "monitor_alert_delete_security_solution", + "monitor_alert_delete_sqlserver_fr", + "monitor_diagnostic_settings_exists", + "policy_ensure_asc_enforcement_enabled" + ] + }, + { + "Id": "CEK-03", + "Description": "Provide cryptographic protection to data at-rest and in-transit, using cryptographic libraries certified to approved standards.", + "Name": "Data Encryption", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-03", + "EKM-04" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.6", + "3.1", + "3.11", + "11.3", + "16.11" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1.1", + "27001: A.18.1.2", + "27001: A.18.1.3", + "27001: A.18.1.4", + "27001: A.18.1.5", + "27001: A.10.1", + "27002: 10.1", + "27001: A.13.2.1", + "27002: 13.2.1", + "27001: A.18", + "27002: 18", + "27001: A.14.1.2", + "27002: 14.1.2", + "27001: A.14.1.3", + "27002 14.1.3 c)", + "27001 - A.10.1.1", + "27017 - 10.1.1", + "27001 - A.10.1.2", + "27017 - 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.14", + "27001: A.8.24", + "27002: 8.24 Other Information (a)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-19", + "AC-19(5)", + "SC-8", + "SC-8(1)", + "SC-8(3)", + "SC-8(4)", + "SC-12", + "SC-12(2)", + "SC-12(3)", + "SC-28", + "SC-28(1)-(3)", + "SI-4", + "SI-4(10)", + "SI-7", + "SI-7(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-1", + "PR.DS-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01", + "PR.DS-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "Requirement 3", + "2.2.3", + "2.3", + "3.4", + "3.5.3", + "4.1", + "8.2.1", + "PCI Glossary - Strong Cryptography" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "2.2.7", + "3.5.1", + "4.2.1", + "4.2.1.2", + "4.2.2" + ] + } + ] + } + ], + "Checks": [ + "app_minimum_tls_version_12", + "databricks_workspace_cmk_encryption_enabled", + "mysql_flexible_server_ssl_connection_enabled", + "postgresql_flexible_server_enforce_ssl_enabled", + "sqlserver_tde_encrypted_with_cmk", + "sqlserver_tde_encryption_enabled", + "storage_ensure_encryption_with_customer_managed_keys", + "storage_infrastructure_encryption_is_enabled", + "storage_secure_transfer_required_is_enabled", + "storage_smb_channel_encryption_with_secure_algorithm", + "vm_ensure_attached_disks_encrypted_with_cmk", + "vm_ensure_unattached_disks_encrypted_with_cmk" + ] + }, + { + "Id": "CEK-04", + "Description": "Use encryption algorithms that are appropriate for data protection, considering the classification of data, associated risks, and usability of the encryption technology.", + "Name": "Encryption Algorithm", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-04" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.11" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1.2", + "27001: 6.1.3", + "27001: A.8.2", + "27002: 8.2", + "27001: A.8.3", + "27001: A.10.1.1", + "27002: 10.1.1 (b)", + "27001: A.10.1.2", + "27002: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1.2", + "27001: 6.1.3", + "27001: A.8.24", + "27001: A.5.12", + "27001: A.5.13", + "27002: 8.24 General (b)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-12", + "SC-12(2)", + "SC-12(3)", + "SC-28", + "SC-28(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-1", + "PR.DS-2", + "ID.AM-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01", + "PR.DS-02", + "ID.AM-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "A2", + "Requirement 3", + "2.3", + "2.2.3", + "3.4", + "3.5.3", + "4.1", + "8.2.1", + "PCI Glossary - Strong Cryptography" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "2.2.7", + "3.5.1", + "4.2.1", + "4.2.1.2", + "4.2.2" + ] + } + ] + } + ], + "Checks": [ + "app_minimum_tls_version_12", + "keyvault_key_rotation_enabled", + "mysql_flexible_server_minimum_tls_version_12", + "postgresql_flexible_server_enforce_ssl_enabled", + "sqlserver_recommended_minimal_tls_version", + "storage_ensure_minimum_tls_version_12", + "storage_smb_protocol_version_is_latest" + ] + }, + { + "Id": "CEK-08", + "Description": "CSPs must provide the capability for CSCs to manage their own data encryption keys.", + "Name": "CSC Key Management Capability", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2", + "SC2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1", + "27017: 10.1", + "27001: A.10.1.1", + "27017: 10.1.1", + "27001: A.10.1.2", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.23", + "27001: A.8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-9", + "CP-9(8)", + "SA-9", + "SA-9(6)", + "SC-12", + "SC-12(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.SC-3", + "ID.AM-6", + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.SC-05" + ] + } + ] + } + ], + "Checks": [ + "databricks_workspace_cmk_encryption_enabled", + "keyvault_access_only_through_private_endpoints", + "keyvault_private_endpoints", + "keyvault_rbac_enabled", + "storage_ensure_encryption_with_customer_managed_keys" + ] + }, + { + "Id": "CEK-10", + "Description": "Generate Cryptographic keys using industry accepted cryptographic libraries specifying the algorithm strength and the random number generator used.", + "Name": "Key Generation", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-04" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.11" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2", + "TS2.3", + "SY1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1.1", + "27002: 10.1.1 (e)", + "27017: 10.1.1", + "27001: A.10.1.2", + "27002: 10.1.2", + "27002: 10.1.2 (a)", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.24", + "27002: 8.24 (d), Key management (a)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-12", + "SC-12(2)", + "SC-12(3)", + "SC-13" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.2.3", + "3.6.1", + "PCI Glossary - Cryptographic Key Generation" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.6.1", + "3.6.1.1", + "3.7.1" + ] + } + ] + } + ], + "Checks": [ + "keyvault_rbac_enabled", + "storage_ensure_encryption_with_customer_managed_keys" + ] + }, + { + "Id": "CEK-12", + "Description": "Rotate cryptographic keys in accordance with the calculated cryptoperiod, which includes provisions for considering the risk of information disclosure and legal and regulatory requirements.", + "Name": "Key Rotation", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1.1", + "27017: 10.1.1", + "27001: A.10.1.2", + "27002: 10.1.2 e)", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.31", + "27001: A.8.24", + "27002: 5.31 Cryptography", + "27002: 8.24 Key management (e,m)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-12", + "SC-12(2)", + "SC-12(3)", + "SC-13" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "ID.GV-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-05", + "GV.OC-03" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.7.4", + "3.7.5" + ] + } + ] + } + ], + "Checks": [ + "keyvault_key_expiration_set_in_non_rbac", + "keyvault_key_rotation_enabled", + "keyvault_non_rbac_secret_expiration_set", + "keyvault_rbac_key_expiration_set", + "keyvault_rbac_secret_expiration_set", + "storage_key_rotation_90_days" + ] + }, + { + "Id": "CEK-14", + "Description": "Define, implement and evaluate processes, procedures and technical measures to destroy keys stored outside a secure environment and revoke keys stored in Hardware Security Modules (HSMs) when they are no longer needed, which include provisions for legal and regulatory requirements.", + "Name": "Key Destruction", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1.1", + "27017: 10.1.1", + "27017: 10.1.2", + "27001: A.10.1.2", + "27002: 10.1.2 (j)", + "27001: A.18.1.3", + "27002: 18.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.31", + "27001: A.8.24", + "27002: 5.31 Cryptography", + "27002: 8.24 Key management (j,m)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-12", + "SC-12(2)", + "SC-12(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.IP-6", + "ID.GV-3", + "PR.DS-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-05", + "ID.AM-08", + "GV.OC-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.6.4", + "3.6.5" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.7.4", + "3.7.5" + ] + } + ] + } + ], + "Checks": [ + "keyvault_recoverable" + ] + }, + { + "Id": "DCS-06", + "Description": "Catalogue and track all relevant physical and logical assets located at all of the CSP's sites within a secured system.", + "Name": "Assets Cataloguing and Tracking", + "Attributes": [ + { + "Section": "Datacenter Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "DCS - 01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "1.1", + "2.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.3.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SM2.6" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.8.1.1", + "27002: 8.1.1", + "27017: 8.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.9" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-8", + "CM-8(1)", + "CM-8(2)", + "CM-8(4)", + "CM-8(7)", + "CM-8(8)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.AM-1", + "ID.AM-2", + "ID.AM-4", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-01", + "ID.AM-02", + "ID.AM-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.4", + "9.7.1", + "9.9.1", + "9.9.1.a", + "9.9.1.b", + "9.9.1.c", + "12.3.3", + "12.3.4" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.6.1.1", + "6.3.2", + "9.4.2", + "9.4.3", + "12.5.1" + ] + } + ] + } + ], + "Checks": [ + "defender_ensure_mcas_is_enabled", + "monitor_diagnostic_settings_exists", + "policy_ensure_asc_enforcement_enabled" + ] + }, + { + "Id": "DSP-02", + "Description": "Apply industry accepted methods for the secure disposal of data from storage media such that data is not recoverable by any forensic means.", + "Name": "Secure Disposal", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2", + "CC6.3", + "CC6.4", + "CC6.5", + "CC6.7", + "P4.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "DSI-07" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.5" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.3.3", + "7.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.1", + "IM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.8.3.2", + "27002: 8.3.2", + "27001: A.11.2.7", + "27002: 11.2.7" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.7.10", + "27001: A.7.14", + "27001: A.8.10", + "27002: 7.10 (Secure reuse or disposal)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PM-22", + "SI-12", + "SI-12(3)", + "SI-18", + "SI-18(1)", + "SI-18(4)", + "SI-18(5)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-6" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.SC-10", + "PR.PS-02", + "PR.PS-03", + "ID.AM-08" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.1", + "9.8", + "9.8.1", + "9.8.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.2.1", + "3.7.5", + "9.4.7" + ] + } + ] + } + ], + "Checks": [ + "storage_ensure_file_shares_soft_delete_is_enabled", + "storage_ensure_soft_delete_is_enabled", + "vm_sufficient_daily_backup_retention_period" + ] + }, + { + "Id": "DSP-03", + "Description": "Create and maintain a data inventory, at least for any sensitive data and personal data.", + "Name": "Data Inventory", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.3.1", + "1.3.2", + "1.3.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.1", + "IM2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.8.1.1", + "27002: 8.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.9", + "27001: A.8.12" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-12", + "CM-12(1)", + "PM-5", + "PM-5(1)", + "SI-12", + "SI-12(1)", + "SI-19", + "SI-19(1)", + "SI-19(2)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.AM-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-07" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.2.1", + "9.4.5" + ] + } + ] + } + ], + "Checks": [ + "defender_ensure_defender_for_storage_is_on", + "defender_ensure_mcas_is_enabled", + "monitor_diagnostic_settings_exists", + "policy_ensure_asc_enforcement_enabled" + ] + }, + { + "Id": "DSP-04", + "Description": "Classify data according to its type and sensitivity level.", + "Name": "Data Classification", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "C1.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "DSI-01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.7" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.3.1", + "1.3.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.8.2.1", + "27002: 8.2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.12" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-16", + "AC-16(9)", + "PM-22", + "PM-23", + "PT-2", + "PT-2(1)", + "SI-18", + "SI-18(2)", + "SI-19", + "SI-19(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.AM-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-05", + "ID.AM-07" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "9.6.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "9.4.2", + "9.4.3" + ] + } + ] + } + ], + "Checks": [ + "defender_ensure_defender_for_storage_is_on" + ] + }, + { + "Id": "DSP-07", + "Description": "Develop systems, products, and business practices based upon a principle of security by design and industry best practices.", + "Name": "Data Protection by Design and Default", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "PI1.2", + "PI1.3" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.3.1", + "5.3.2", + "5.3.3", + "5.3.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SD2.2", + "IM1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.14.1.1", + "27002:14.1.1", + "27001: A.14.2.5", + "27002:14.2.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.27", + "27001: A.8.28", + "27001: A.8.29", + "27002: 5.8 (Information security requirements a-i)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PM-17", + "PM-24", + "PM-25", + "PT-2", + "PT-2(2)", + "SA-3", + "SA-4", + "SA-5", + "SA-8", + "SA-8(9)", + "SA-8(13)", + "SA-8(18)", + "SA-8(20)", + "SA-8(22)", + "SA-8(23)", + "SA-8(33)", + "SA-15", + "SA-15(12)", + "SC-3", + "SC-3(3)", + "SC-7", + "SC-7(24)", + "SC-8", + "SC-8(1)-(4)", + "SC-28", + "SC-28(1)", + "SI-12", + "SI-12(1)-(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-2", + "PR.PT-3", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "PR.PS-06" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.2.1" + ] + } + ] + } + ], + "Checks": [ + "aisearch_service_not_publicly_accessible", + "aks_clusters_public_access_disabled", + "containerregistry_not_publicly_accessible", + "cosmosdb_account_firewall_use_selected_networks", + "sqlserver_unrestricted_inbound_access", + "storage_blob_public_access_level_is_disabled", + "storage_default_network_access_rule_is_denied", + "storage_ensure_private_endpoints_in_storage_accounts", + "vm_ensure_attached_disks_encrypted_with_cmk", + "vm_ensure_unattached_disks_encrypted_with_cmk" + ] + }, + { + "Id": "DSP-10", + "Description": "Define, implement and evaluate processes, procedures and technical measures that ensure any transfer of personal or sensitive data is protected from unauthorized access and only processed within scope as permitted by the respective laws and regulations.", + "Name": "Sensitive Data Transfer", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-02", + "EKM-03" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.1", + "3.12", + "3.13" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.2", + "9.5.1", + "9.5.2", + "9.5.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.4", + "IM2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.13.2.1", + "27002: 13.2.1", + "27001: A.8.3.3", + "27002: 8.3.3", + "27001: A.13.2.3", + "27002: 13.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.14", + "27001: A.7.10" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-4", + "AC-4(23)-(25)", + "CA-3", + "CA-3(6)", + "CA-6", + "CA-6(1)", + "CA-6(2)", + "SC-4", + "SC-4(2)", + "SC-7", + "SC-7(10)", + "SC-7(24)", + "SC-8", + "SC-8(1)-(5)", + "SC-16", + "SC-16(1)-(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-2", + "PR.DS-5", + "PR.PT-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-02", + "PR.IR-01", + "ID.AM-03", + "GV.OC-03", + "ID.AM-07" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "4.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "4.1.1", + "4.2.1", + "4.2.2" + ] + } + ] + } + ], + "Checks": [ + "app_ensure_http_is_redirected_to_https", + "app_ensure_using_http20", + "sqlserver_recommended_minimal_tls_version", + "storage_ensure_minimum_tls_version_12", + "storage_secure_transfer_required_is_enabled" + ] + }, + { + "Id": "DSP-16", + "Description": "Data retention, archiving and deletion is managed in accordance with business requirements, applicable laws and regulations.", + "Name": "Data Retention and Deletion", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "C1.1", + "C1.2", + "CC3.1", + "P4.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-02", + "BCR-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.4", + "3.5" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.3.1", + "7.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.1", + "IM2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.33", + "27001: A.8.10", + "27002: 5.33 (b)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SI-12", + "SI-12(1)-(3)", + "SI-18", + "SI-18(1)", + "SI-18(4)", + "SI-18(5)", + "SI-19", + "SI-19(2)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-3", + "PR.IP-6", + "ID.GV-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "GV.OC-03", + "GV.SC-10", + "PR.DS-11" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.2.1" + ] + } + ] + } + ], + "Checks": [ + "monitor_storage_account_with_activity_logs_cmk_encrypted", + "monitor_storage_account_with_activity_logs_is_private", + "postgresql_flexible_server_log_retention_days_greater_3", + "sqlserver_auditing_retention_90_days", + "storage_ensure_file_shares_soft_delete_is_enabled", + "storage_ensure_soft_delete_is_enabled" + ] + }, + { + "Id": "DSP-17", + "Description": "Define and implement, processes, procedures and technical measures to protect sensitive data throughout it's lifecycle.", + "Name": "Sensitive Data Protection", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "CSP-Owned", + "PaaS": "CSP-Owned", + "SaaS": "CSC-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC2.1", + "CC6.1", + "CC6.3", + "CC6.7", + "CC8.1", + "C1.1", + "P2.0", + "P3.0", + "P4.0", + "P5.0", + "P6.0" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.1", + "3.1", + "3.14" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.3.3", + "9.1.1", + "9.2.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.1", + "IM2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1.3", + "27002: 18.1.3", + "27001:A.18.1.4", + "27002:18.1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.11", + "27001: A.8.12" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PL-2", + "PM-22", + "PM-24", + "PT-7", + "PT-7(1)", + "PT-7(2)", + "PT-8", + "SC-8", + "SC-8(1)-(5)", + "SC-28", + "SC-28(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-1", + "PR.DS-2", + "PR.DS-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01", + "PR.DS-02", + "PR.DS-10" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.0 (including all subsections)", + "4.0 (including all subsections)" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.1.1", + "4.1.1" + ] + } + ] + } + ], + "Checks": [ + "containerregistry_not_publicly_accessible", + "cosmosdb_account_firewall_use_selected_networks", + "defender_ensure_defender_for_storage_is_on", + "sqlserver_tde_encrypted_with_cmk", + "sqlserver_tde_encryption_enabled", + "sqlserver_unrestricted_inbound_access", + "storage_account_key_access_disabled", + "storage_blob_public_access_level_is_disabled", + "storage_cross_tenant_replication_disabled", + "storage_default_network_access_rule_is_denied", + "storage_default_to_entra_authorization_enabled", + "storage_ensure_encryption_with_customer_managed_keys", + "vm_ensure_attached_disks_encrypted_with_cmk" + ] + }, + { + "Id": "GRC-05", + "Description": "Develop and implement an Information Security Program, which includes programs for all the relevant domains of the CCM.", + "Name": "Information Security Program", + "Attributes": [ + { + "Section": "Governance, Risk and Compliance", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-04" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "14.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SG2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 4.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 4.3" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PM-1", + "PM-3", + "PM-14", + "PL-2", + "PM-18", + "PM-31" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "12.4.1", + "A.3.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.4.1", + "A3.1.1" + ] + } + ] + } + ], + "Checks": [ + "defender_ensure_defender_for_app_services_is_on", + "defender_ensure_defender_for_arm_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_databases_is_on", + "defender_ensure_defender_for_dns_is_on", + "defender_ensure_defender_for_keyvault_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_mcas_is_enabled", + "defender_ensure_wdatp_is_enabled" + ] + }, + { + "Id": "IAM-02", + "Description": "Establish, document, approve, communicate, implement, apply, evaluate and maintain strong password policies and procedures. Review and update the policies and procedures at least annually.", + "Name": "Strong Password Policy and Procedures", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-02", + "IAM-12", + "GRM-06", + "GRM-09" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.1.1", + "1.5.1", + "4.1.2", + "4.1.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.1", + "SA1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 5.1", + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: 9.1", + "27001: 9.3", + "27001: A.5", + "27002: 5", + "27001: A.9.4.3", + "27002: 9.4.3", + "27017: 9.4.3", + "27018: 9.4.3", + "27001: A.9.2.4", + "27002: 9.2.4", + "27017: 9.2.4", + "27001: A.7.2.2", + "27002: 7.2.2", + "27001: A.9.2.6", + "27002: 9.2.6", + "27001: A.9.2.3", + "27002: 9.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 5.1", + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: 9.1", + "27001: 9.3", + "27001: A.5.1", + "27001: A.5.4", + "27001: A.5.17", + "27001: A.6.3", + "27001: A.8.5", + "27001: A.5.37" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(3)", + "AC-2(11)", + "AC-3", + "AC-3(3)", + "AC-12", + "AC-12(1)", + "IA-2", + "IA-2(10)", + "IA-5", + "IA-5(1)", + "IA-5(18)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-1", + "PR.AC-1", + "PR.AC-7" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.PO-01", + "GV.PO-02", + "ID.IM-03", + "PR.AA-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.4", + "12.1", + "12.1.1", + "12.11" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "8.1.1", + "8.3.8" + ] + } + ] + } + ], + "Checks": [ + "entra_privileged_user_has_mfa", + "entra_security_defaults_enabled" + ] + }, + { + "Id": "IAM-03", + "Description": "Manage, store, and review the information of system identities, and level of access.", + "Name": "Identity Inventory", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-04", + "IAM-08", + "IAM-10" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.1", + "5.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.3", + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 9.2 (c)", + "27001: A.8.1.1", + "27002: 8.1.1", + "27001: A.9.4.1", + "27002: 9.4.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 9.2 (c)", + "27001: A.5.15", + "27001: A.5.16", + "27001: A.5.18", + "27001: A.7.4", + "27001: A.8.15", + "27001: A.8.2", + "27001: A.8.3" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-10", + "AU-10(1)", + "AU-10(2)", + "AU-16", + "AU-16(1)", + "IA-4", + "IA-4(8)", + "IA-4(9)", + "IA-5", + "IA-5(5)", + "IA-8", + "IA-8(4)", + "PM-5(1)", + "SA-8", + "SA-8(22)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-6", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-02", + "PR.AA-04", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.4.a" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.5", + "7.2.5.1" + ] + } + ] + } + ], + "Checks": [ + "entra_global_admin_in_less_than_five_users" + ] + }, + { + "Id": "IAM-04", + "Description": "Employ the separation of duties principle when implementing information system access.", + "Name": "Separation of Duties", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC1.3", + "CC5.1", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-05" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "6.8" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.2.2", + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.6.1.2", + "27002: 6.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.15", + "27001: A.5.18", + "27001: A.5.3", + "27001: A.8.2" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(3)", + "AC-2(11)", + "AC-6", + "AC-6(1)-(10)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.4", + "6.4.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.5.3", + "6.5.4", + "7.2.1", + "7.2.2" + ] + } + ] + } + ], + "Checks": [ + "entra_policy_default_users_cannot_create_security_groups", + "entra_policy_ensure_default_user_cannot_create_apps", + "iam_role_user_access_admin_restricted", + "iam_subscription_roles_owner_custom_not_created" + ] + }, + { + "Id": "IAM-05", + "Description": "Employ the least privilege principle when implementing information system access.", + "Name": "Least Privilege", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-02", + "IAM-06", + "IVS-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "6.8" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.1.1", + "27002: 9.1.1", + "27001: A.9.1.2", + "27002: 9.1.2", + "27001: A.9.2.3", + "27002: 9.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.15", + "27001: A.8.2", + "27002: 5.15 (Other information 2nd (a))" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-6", + "AC-6(4)", + "IA-12", + "IA-12(2)", + "IA-12(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "7.1", + "7.1.1", + "7.1.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.1", + "7.2.2", + "7.2.5", + "7.2.6" + ] + } + ] + } + ], + "Checks": [ + "app_function_identity_without_admin_privileges", + "entra_policy_ensure_default_user_cannot_create_apps", + "entra_policy_ensure_default_user_cannot_create_tenants", + "entra_policy_restricts_user_consent_for_apps", + "iam_custom_role_has_permissions_to_administer_resource_locks", + "iam_subscription_roles_owner_custom_not_created" + ] + }, + { + "Id": "IAM-07", + "Description": "De-provision or respectively modify access of movers / leavers or system identity changes in a timely manner in order to effectively adopt and communicate identity and access management policies.", + "Name": "User Access Changes and Revocation", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC5.3", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.3", + "6.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.15", + "27001: A.5.18" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(1)", + "AC-2(2)", + "AC-2(6)", + "AC-2(8)", + "AC-3", + "AC-3(8)", + "AC-6", + "AC-6(7)", + "AU-10", + "AU-10(4)", + "AU-16", + "AU-16(1)", + "CM-7", + "CM-7(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-4", + "PR.IP-11" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.RR-04", + "GV.SC-10", + "PR.AA-01", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.1.2", + "8.1.3" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "8.2.5", + "8.2.6" + ] + } + ] + } + ], + "Checks": [ + "entra_global_admin_in_less_than_five_users" + ] + }, + { + "Id": "IAM-08", + "Description": "Review and revalidate user access for least privilege and separation of duties with a frequency that is commensurate with organizational risk tolerance.", + "Name": "User Access Review", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.2", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-10" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.5", + "27001: A.9.2.6", + "27001: A.9.4.1", + "27017: 9.4.1", + "27001: A.6.1.2", + "27001: A 9.2.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.3", + "27001: A.5.18", + "27001: A.8.3" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-6", + "AC-6(4)", + "AC-6(8)", + "IA-8", + "IA-8(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "12.5.5" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.5.1", + "7.2.5", + "7.2.4" + ] + } + ] + } + ], + "Checks": [ + "entra_global_admin_in_less_than_five_users", + "keyvault_non_rbac_secret_expiration_set", + "keyvault_rbac_secret_expiration_set", + "storage_key_rotation_90_days" + ] + }, + { + "Id": "IAM-09", + "Description": "Define, implement and evaluate processes, procedures and technical measures for the segregation of privileged access roles such that administrative access to data, encryption and key management capabilities and logging capabilities are distinct and separated.", + "Name": "Segregation of Privileged Access Roles", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC5.1", + "CC6.1", + "CC6.3" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.3", + "27002: 9.2.3", + "27017: 9.2.3", + "27018: 9.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.2", + "27001: A.8.18", + "27002: 8.2 (j)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-6", + "AC-3(7)", + "AC-6(4)", + "AC-6(8)", + "IA-5", + "IA-5(6)", + "IA-8", + "IA-8(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.3", + "3.5.2", + "7.1.2", + "7.1.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.6.1", + "3.7.6", + "6.5.3", + "6.5.4", + "7.2.1", + "7.2.2", + "10.3.1" + ] + } + ] + } + ], + "Checks": [ + "entra_global_admin_in_less_than_five_users", + "entra_policy_guest_invite_only_for_admin_roles", + "entra_policy_guest_users_access_restrictions", + "iam_custom_role_has_permissions_to_administer_resource_locks", + "iam_subscription_roles_owner_custom_not_created" + ] + }, + { + "Id": "IAM-10", + "Description": "Define and implement an access process to ensure privileged access roles and rights are granted for a time limited period, and implement procedures to prevent the culmination of segregated privileged access.", + "Name": "Management of Privileged Access Roles", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2", + "CC6.3" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.1", + "6.5" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.3", + "27002: 9.2.3", + "27017: 9.2.3", + "27018: 9.2.3", + "27001: A.9.4.4", + "27002: 9.4.4", + "27017: 9.4.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.2", + "27001: A.8.18", + "27002: 8.2 (i)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(7)", + "AC-3", + "AC-3(4)", + "AC-3(11)", + "AC-3(13)", + "AC-3(14)", + "AC-6", + "AC-6(4)", + "AC-6(5)", + "AC-6(8)", + "AC-12", + "AC-12(3)", + "AC-17", + "AC-17(4)", + "IA-8", + "IA-8(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "7.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.1", + "7.2.2" + ] + } + ] + } + ], + "Checks": [ + "entra_conditional_access_policy_require_mfa_for_management_api", + "entra_global_admin_in_less_than_five_users", + "entra_user_with_vm_access_has_mfa", + "iam_role_user_access_admin_restricted", + "iam_subscription_roles_owner_custom_not_created", + "vm_jit_access_enabled" + ] + }, + { + "Id": "IAM-12", + "Description": "Define, implement and evaluate processes, procedures and technical measures to ensure the logging infrastructure is read-only for all with write access, including privileged access roles, and that the ability to disable it is controlled through a procedure that ensures the segregation of duties and break glass procedures.", + "Name": "Safeguard Logs Integrity", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.3" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.1", + "27002: 12.4.1", + "27017: 12.4.1", + "27018: 12.4.1", + "27001: A.12.4.2", + "27002: 12.4.2", + "27017: 12.4.2", + "27018: 12.4.2", + "27001: A.12.4.3", + "27002: 12.4.3", + "27017: 12.4.3", + "27018: 12.4.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.15", + "27001: A.8.18", + "27002: 8.15 Protection of Logs" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(11)", + "AC-2(12)", + "IA-8", + "IA-8(4)", + "SA-8", + "SA-8(22)", + "SC-34", + "SC-34(1)", + "SC-34(2)", + "SC-36", + "SI-4", + "SI-4(5)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.5" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.3.1", + "10.3.2", + "10.3.3", + "10.3.4" + ] + } + ] + } + ], + "Checks": [ + "entra_trusted_named_locations_exists", + "keyvault_logging_enabled", + "monitor_diagnostic_setting_with_appropriate_categories", + "monitor_storage_account_with_activity_logs_is_private" + ] + }, + { + "Id": "IAM-13", + "Description": "Define, implement and evaluate processes, procedures and technical measures that ensure users are identifiable through unique IDs or which can associate individuals to the usage of user IDs.", + "Name": "Uniquely Identifiable Users", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.1", + "27002: 9.2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.16" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-3", + "AC-3(14)", + "AC-24", + "AC-24(2)", + "AU-10", + "AU-10(1)", + "IA-2", + "IA-2(1)", + "IA-2(2)", + "IA-2(12)", + "IA-4", + "IA-4(1)", + "SA-8", + "SA-8(22)", + "SC-23", + "SC-23(3)", + "SC-40(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-6" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.1", + "8.2", + "8.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "8.2.1", + "8.2.2", + "8.2.4" + ] + } + ] + } + ], + "Checks": [ + "entra_conditional_access_policy_require_mfa_for_management_api", + "entra_non_privileged_user_has_mfa", + "entra_privileged_user_has_mfa", + "entra_security_defaults_enabled", + "postgresql_flexible_server_entra_id_authentication_enabled", + "sqlserver_azuread_administrator_enabled" + ] + }, + { + "Id": "IAM-14", + "Description": "Define, implement and evaluate processes, procedures and technical measures for authenticating access to systems, application and data assets, including multifactor authentication for at least privileged user and sensitive data access. Adopt digital certificates or alternatives which achieve an equivalent level of security for system identities.", + "Name": "Strong Authentication", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-02", + "IAM-05" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "6.3", + "6.5", + "12.5", + "12.7" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3", + "SA1.4", + "SA1.8" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.1.2", + "27002: 9.1.2", + "27017: 9.1.2", + "27001: A.9.2.4", + "27002: 9.2.4", + "27017: 9.2.4", + "27001: A.9.4.2", + "27002: 9.4.2", + "27017: 9.4.2", + "27018: 9.4.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.15", + "27001: A.5.17", + "27001: A.8.5", + "27001: A.8.24", + "27002: 8.5", + "27002: 8.24 other information (d)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-6", + "AC-6(5)", + "AC-7", + "AC-7(4)", + "AU-10", + "AU-10(2)", + "IA-2", + "IA-2(1)", + "IA-2(2)", + "IA-2(8)", + "IA-2(12)", + "IA-3", + "IA-3(1)", + "IA-5", + "IA-5(2)", + "IA-5(7)", + "IA-5(9)", + "IA-5(10)", + "IA-5(12)", + "IA-5(14)-(16)", + "IA-8", + "IA-8(1)", + "IA-8(6)", + "SC-23", + "SC-23(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-6", + "PR.AC-7" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-02", + "PR.AA-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.1.2", + "8.1.3", + "8.1.6", + "8.2", + "8.3", + "8.3.2", + "12.3.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.1", + "8.3.1", + "8.3.2", + "8.4.1", + "8.4.2", + "8.4.3" + ] + } + ] + } + ], + "Checks": [ + "entra_non_privileged_user_has_mfa", + "entra_privileged_user_has_mfa", + "entra_security_defaults_enabled", + "entra_user_with_vm_access_has_mfa" + ] + }, + { + "Id": "IAM-15", + "Description": "Define, implement and evaluate processes, procedures and technical measures for the secure management of passwords.", + "Name": "Passwords Management", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.4", + "27002: 9.2.4", + "27017: 9.2.4", + "27018: 9.2.4", + "27001: A.9.3.1", + "27002: 9.3.1", + "27017: 9.3.1", + "27018: 9.3.1", + "27001: A.9.4.3", + "27002: 9.4.3", + "27017: 9.4.3", + "27018: 9.4.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.17" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "IA-4", + "IA-4(8)", + "IA-5", + "IA-5(1)", + "IA-5(8)", + "IA-5(18)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.2", + "8.2.1-6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "2.2.2", + "2.3.1", + "8.3.5", + "8.3.6", + "8.3.7", + "8.3.8", + "8.3.9", + "8.3.10", + "8.3.10.1", + "8.6.2" + ] + } + ] + } + ], + "Checks": [ + "entra_privileged_user_has_mfa", + "entra_security_defaults_enabled" + ] + }, + { + "Id": "IAM-16", + "Description": "Define, implement and evaluate processes, procedures and technical measures to verify access to data and system functions is authorized.", + "Name": "Authorization Mechanisms", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3", + "SA1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.5", + "27002: 9.2.5", + "27017: 9.2.5", + "27018: 9.2.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.18" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-3", + "AC-3(5)", + "AC-4", + "AC-4(17)", + "AC-4(21)", + "AC-4(22)", + "AC-6", + "AC-6(8)", + "AC-6(9)", + "AC-12", + "AC-12(1)", + "AC-20", + "AC-20(1)", + "AU-10", + "AU-10(1)", + "AU-10(2)", + "IA-2", + "IA-2(1)", + "IA-2(2)", + "IA-2(12)", + "IA-3", + "IA-3(1)", + "IA-5(1)", + "IA-5(2)", + "IA-5(5)", + "IA-5(8)", + "IA-5(10)", + "IA-5(12)", + "IA-8", + "IA-8(1)", + "IA-8(2)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-4", + "PR.AC-6", + "PR.AC-7", + "PR.PT-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-02", + "PR.AA-03", + "PR.AA-04", + "PR.AA-05", + "PR.PS-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "5.3", + "7.1.4" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.4", + "7.2.3", + "7.2.5.1" + ] + } + ] + } + ], + "Checks": [ + "aks_cluster_rbac_enabled", + "app_function_identity_is_configured", + "app_function_identity_without_admin_privileges", + "app_function_not_publicly_accessible", + "entra_policy_user_consent_for_verified_apps", + "iam_subscription_roles_owner_custom_not_created" + ] + }, + { + "Id": "IPY-03", + "Description": "Implement cryptographically secure and standardized network protocols for the management, import and export of data.", + "Name": "Secure Interoperability and Portability Management", + "Attributes": [ + { + "Section": "Interoperability & Portability", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IPY-04" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY1.1", + "SY1.2", + "NC1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1", + "27001: A.15.1.1", + "27002: 15.1.1", + "27017: 15.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.19", + "27001: A.5.23", + "27001: A.5.31", + "27001: A.5.32", + "27001: A.5.33", + "27001: A.5.34" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PT-2", + "PT-2(2)", + "SA-4", + "SC-16", + "SC-16(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-02" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "1.2.1", + "1.2.5", + "1.2.6", + "2.2.4", + "2.2.5", + "2.2.7", + "4.2.1" + ] + } + ] + } + ], + "Checks": [ + "storage_ensure_azure_services_are_trusted_to_access_is_enabled", + "storage_secure_transfer_required_is_enabled" + ] + }, + { + "Id": "IVS-02", + "Description": "Plan and monitor the availability, quality, and adequate capacity of resources in order to deliver the required system performance as determined by the business.", + "Name": "Capacity and Resource Planning", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "No", + "IaaS": "CSP-Owned", + "PaaS": "CSP-Owned", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "A1.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-04" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 5.3", + "27001: 6.1", + "27001: 9.1", + "27001: A.12.1.3", + "27002: 12.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 5.3 (b)", + "27001: 6.1", + "27001: 9.1", + "27001: A.8.6", + "27001: A.8.14" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-2", + "CP-2(2)", + "SC-5", + "SC-5(2)", + "SC-4", + "SI-4" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-4", + "ID.BE-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.IR-04", + "GV.OC-04" + ] + } + ] + } + ], + "Checks": [ + "vm_scaleset_associated_with_load_balancer", + "vm_scaleset_not_empty" + ] + }, + { + "Id": "IVS-03", + "Description": "Monitor, encrypt and restrict communications between environments to only authenticated and authorized connections, as justified by the business. Review these configurations at least annually, and support them by a documented justification of all allowed services, protocols, ports, and compensating controls.", + "Name": "Network Security", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-06" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.8", + "3.1", + "12.2", + "13.6", + "13.9" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.2", + "5.2.7" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "NC1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 7.5", + "27001: 9.1", + "27001: A.13.1.1", + "27002: 13.1.1", + "27001: A.13.1.2", + "27002: 13.1.2", + "27001: A.13.1.3", + "27002: 13.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 7.5", + "27001: 9.1", + "27001: A.5.15", + "27001: A.5.37", + "27001: A.8.5", + "27001: A.8.9", + "27001: A.8.16", + "27001: A.8.20", + "27001: A.8.21", + "27001: A.8.22", + "27001: A.8.24", + "27002: A.5.15 2nd c)", + "27002: 8.20", + "27002: 8.21", + "27002: 8.22", + "27002: 8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-1", + "SC-4", + "SC-7", + "SC-7(4)", + "SC-7(5)", + "SC-7(8)", + "SC-7(9)", + "SC-7(11)", + "SC-8", + "SC-8(1)", + "SC-11", + "SC-12", + "SC-16", + "SC-23", + "SC-29", + "SC-29(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-5", + "PR.AC-7", + "PR.PT-4", + "DE.CM-1", + "DE.CM-7", + "PR.DS-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.IR-01", + "PR.AA-03", + "PR.AA-05", + "DE.CM-01", + "PR.DS-02", + "ID.AM-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "1.1.6", + "1.2", + "1.2.3", + "2.2", + "4.1.1", + "10.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "1.2.5", + "1.2.6", + "1.2.7", + "1.4.2", + "2.2.4", + "2.2.5", + "2.2.7", + "4.2.1", + "10.1.1" + ] + } + ] + } + ], + "Checks": [ + "aks_clusters_created_with_private_nodes", + "aks_clusters_public_access_disabled", + "aks_network_policy_enabled", + "network_bastion_host_exists", + "network_flow_log_captured_sent", + "network_flow_log_more_than_90_days", + "network_http_internet_access_restricted", + "network_rdp_internet_access_restricted", + "network_ssh_internet_access_restricted", + "network_udp_internet_access_restricted", + "network_watcher_enabled" + ] + }, + { + "Id": "IVS-04", + "Description": "Harden host and guest OS, hypervisor or infrastructure control plane according to their respective best practices, and supported by technical controls, as part of a security baseline.", + "Name": "OS Hardening and Base Controls", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "CSP-Owned", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.8", + "CC7.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-07", + "IVS-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "4.1", + "4.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.3", + "5.2.5" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY1.1", + "SY1.3", + "SY1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 7.5", + "27001: 9.1", + "27001: A.14.2.2", + "27002: 14.2.2", + "27001: A.14.2.3", + "27001 A.14.2.4", + "27018: 12.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 7.5", + "27001: 9.1", + "27001: A.5.37", + "27001: A.8.5", + "27001: A.8.9", + "27001: A.8.16", + "27001: A.8.20", + "27001: A.8.22", + "27001: A.8.24", + "27002: 8.20", + "27002: 8.22", + "27002: 8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-6", + "CM-6(1)", + "SC-29", + "SC-29(1)", + "SC-2", + "SC-7", + "SC-7(12)", + "SC-30", + "SC-34", + "SC-35", + "SC-39", + "SC-44" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-1", + "PR.PT-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "2.2.1" + ] + } + ] + } + ], + "Checks": [ + "defender_assessments_vm_endpoint_protection_installed", + "defender_ensure_system_updates_are_applied", + "vm_ensure_using_managed_disks", + "vm_linux_enforce_ssh_authentication", + "vm_trusted_launch_enabled" + ] + }, + { + "Id": "IVS-06", + "Description": "Design, develop, deploy and configure applications and infrastructures such that CSP and CSC (tenant) user access and intra-tenant access is appropriately segmented and segregated, monitored and restricted from other tenants.", + "Name": "Segmentation and Segregation", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-09" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1", + "5.3.4", + "5.2.7" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SC2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 9.1", + "27001: A.13.1.3", + "27002: 13.1.3", + "27017: 13.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 9.1", + "27001: A.5.15", + "27001: A.5.20", + "27001: A.8.3", + "27001: A.8.9", + "27001: A.8.16", + "27001: A.8.22", + "27002: 5.15 (b)", + "27002: 8.3 (b)", + "27002: 8.16 (b)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-3", + "SC-7", + "SC-7(20)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4", + "PR.AC-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05", + "PR.IR-01", + "PR.PS-01", + "PR.PS-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.6", + "8.3.1", + "10.8", + "11.3", + "A3.2.1", + "A3.3.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "A1.1.1", + "A1.1.2", + "A1.1.3" + ] + } + ] + } + ], + "Checks": [ + "app_function_not_publicly_accessible", + "app_function_vnet_integration_enabled", + "containerregistry_uses_private_link", + "cosmosdb_account_use_private_endpoints", + "databricks_workspace_vnet_injection_enabled", + "network_http_internet_access_restricted", + "storage_ensure_private_endpoints_in_storage_accounts" + ] + }, + { + "Id": "IVS-07", + "Description": "Use secure and encrypted communication channels when migrating servers, services, applications, or data to cloud environments. Such channels must include only up-to-date and approved protocols.", + "Name": "Migration to Cloud Environments", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-10" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.4", + "IM1.4", + "NC1.4", + "SC2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.13.1.1", + "27002: 13.1.1", + "27017: 13.1.1", + "27018: 13.1.1", + "27001: A.13.1.2", + "27002: 13.1.2", + "27017: 13.1.2", + "27018: 13.1.2", + "27001: A.13.1.3", + "27002: 13.1.3", + "27017: 13.1.3", + "27018: 13.1.3", + "27001: A.13.2.1", + "27002: 13.2.1", + "27017: 13.2.1", + "27018: 13.2.1", + "27001: A.13.2.2", + "27002: 13.2.2", + "27017: 13.2.2", + "27018: 13.2.2", + "27001: A.13.2.3", + "27002: 13.2.3", + "27017: 13.2.3", + "27018: 13.2.3", + "27001: A.13.2.4", + "27002: 13.2.4", + "27017: 13.2.4", + "27018: 13.2.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.14", + "27001: A.8.20", + "27001: A.8.24", + "27002: 8.20 (e)", + "27002: 8.24 Guidance (b,f), other information (a)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-17", + "AC-20", + "SC-7", + "SC-7(28)", + "SC-8", + "SC-8(1)", + "SC-12", + "SC-23", + "SC-29", + "SI-7", + "SI-7(1)-(3)", + "SI-7(5)-(10)", + "SI-7(12)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-2", + "PR.PT-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-02" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "4.2.1" + ] + } + ] + } + ], + "Checks": [ + "mysql_flexible_server_ssl_connection_enabled", + "postgresql_flexible_server_enforce_ssl_enabled" + ] + }, + { + "Id": "IVS-09", + "Description": "Define, implement and evaluate processes, procedures and defense-in-depth techniques for protection, detection, and timely response to network-based attacks.", + "Name": "Network Defense", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.6", + "CC6.8", + "CC7.1", + "CC7.2", + "CC7.5" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-13" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "13.3", + "13.8" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.3", + "5.2.4", + "5.2.5", + "5.2.7", + "5.3.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "NC1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1", + "27001: 6.2", + "27001: A.14.1.2", + "27002: 14.1.2", + "27017: 14.1.2", + "27001: A.11.1.4", + "27002: 11.1.4", + "27017: 11.1.4", + "27018: 16.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1", + "27001: 6.2", + "27001: A.5.24", + "27001: A.5.26", + "27001: A.8.8", + "27001: A.8.16", + "27001: A.8.20", + "27001: A.8.21", + "27001: A.8.22", + "27001: A.8.26", + "27002: 8.8 (i)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PL-8", + "PL-8(1)", + "SC-5", + "SC-5(1)", + "SC-5(3)", + "SC-7", + "SC-7(13)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.AE-1", + "DE.DP-1", + "DE.CM-1", + "DE.CM-7", + "PR.AC-5", + "RS.MI-2", + "PR.DS-2", + "RS.RP-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-03", + "DE.CM-01", + "PR.IR-01", + "RS.MA-01", + "RS.MI-01", + "RS.MI-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.6", + "1.1", + "1.2", + "1.3", + "1.5", + "12.10.5" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "1.1.1", + "1.3.1", + "1.3.2", + "1.3.3", + "1.4.1", + "1.4.2", + "1.4.3", + "1.4.4", + "1.4.5", + "1.5.1", + "12.10.1" + ] + } + ] + } + ], + "Checks": [ + "defender_ensure_defender_for_arm_is_on", + "defender_ensure_defender_for_dns_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_iot_hub_defender_is_on", + "defender_ensure_wdatp_is_enabled", + "network_flow_log_captured_sent", + "network_watcher_enabled", + "sqlserver_microsoft_defender_enabled", + "vm_jit_access_enabled" + ] + }, + { + "Id": "LOG-02", + "Description": "Define, implement and evaluate processes, procedures and technical measures to ensure the security and retention of audit logs.", + "Name": "Audit Logs Protection", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.1", + "8.9", + "8.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "3.1.3", + "5.1.2", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1.3", + "27002: 18.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.28", + "27001: A.5.33", + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-4", + "AU-11" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4", + "PR.IP-4", + "PR.IP-6", + "PR.PT-1", + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05", + "PR.DS-01", + "PR.DS-02", + "ID.AM-08", + "PR.DS-11", + "PR.PS-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.5", + "10.7" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.3.1", + "10.3.2", + "10.3.3", + "10.3.4", + "10.5.1" + ] + } + ] + } + ], + "Checks": [ + "keyvault_logging_enabled", + "monitor_diagnostic_setting_with_appropriate_categories", + "monitor_storage_account_with_activity_logs_cmk_encrypted", + "monitor_storage_account_with_activity_logs_is_private", + "storage_ensure_encryption_with_customer_managed_keys", + "storage_ensure_soft_delete_is_enabled" + ] + }, + { + "Id": "LOG-03", + "Description": "Identify and monitor security-related events within applications and the underlying infrastructure. Define and implement a system to generate alerts to responsible stakeholders based on such events and corresponding metrics.", + "Name": "Security Monitoring and Alerting", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.8", + "CC7.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "SEF-03", + "SEF-05" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.5" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.4", + "5.2.7", + "1.6.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2", + "TM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.1", + "27002: 12.4.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.28", + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-5", + "AU-5(2)", + "AU-13" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.AE-1", + "DE.AE-2", + "DE.AE-3", + "DE.AE-5", + "DE.CM-1", + "DE.CM-2", + "DE.CM-3", + "DE.CM-4", + "DE.CM-5", + "DE.CM-6", + "DE.CM-7", + "DE.DP-1", + "DE.DP-4", + "DE.AE-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.AE-02", + "DE.AE-03", + "DE.AE-04", + "DE.AE-06", + "DE.AE-07", + "DE.AE-08", + "DE.CM-01", + "DE.CM-02", + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.2.1", + "10.2.2", + "10.4.1.1", + "10.4.2.1", + "10.4.3" + ] + } + ] + } + ], + "Checks": [ + "defender_attack_path_notifications_properly_configured", + "defender_ensure_defender_for_app_services_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_notify_alerts_severity_is_high", + "defender_ensure_notify_emails_to_owners", + "defender_ensure_wdatp_is_enabled", + "monitor_alert_create_update_security_solution", + "monitor_alert_service_health_exists" + ] + }, + { + "Id": "LOG-04", + "Description": "Restrict audit logs access to authorized personnel and maintain records that provide unique access accountability.", + "Name": "Audit Logs Access and Accountability", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.14" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "3.1.1", + "4.1.2", + "4.1.3", + "4.2.1", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.2", + "27001: A.12.4.1", + "27002: 12.4.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.33", + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-9", + "AU-9(4)", + "AU-9(6)", + "AU-10" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05", + "PR.PS-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.1", + "10.2.1", + "10.2.3", + "10.5.1", + "10.5.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.2.1.3", + "10.3.1" + ] + } + ] + } + ], + "Checks": [ + "monitor_storage_account_with_activity_logs_is_private" + ] + }, + { + "Id": "LOG-05", + "Description": "Monitor security audit logs to detect activity outside of typical or expected patterns. Establish and follow a defined process to review and take appropriate and timely actions on detected anomalies.", + "Name": "Audit Logs Monitoring and Response", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.8", + "8.11" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.1", + "1.6.2", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.3", + "27002: 12.4.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.15", + "27001: A.8.16" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-6", + "AU-6(1)", + "AU-6(5)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.AE-3", + "PR.PT-1", + "RS.AN-1", + "RS.CO-1.", + "DE.AE-1", + "DE.AE-5", + "DE.DP-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-03", + "PR.PS-04", + "DE.AE-02", + "DE.AE-03", + "DE.AE-06", + "DE.AE-07", + "DE.AE-08", + "DE.CM-01", + "DE.CM-02", + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.6", + "10.6.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.4.1.1", + "10.4.2.1" + ] + } + ] + } + ], + "Checks": [ + "monitor_alert_create_policy_assignment", + "monitor_alert_create_update_nsg", + "monitor_alert_create_update_public_ip_address_rule", + "monitor_alert_create_update_security_solution", + "monitor_alert_create_update_sqlserver_fr", + "monitor_alert_delete_nsg", + "monitor_alert_delete_policy_assignment", + "monitor_alert_delete_public_ip_address_rule", + "monitor_alert_delete_security_solution", + "monitor_alert_delete_sqlserver_fr", + "monitor_alert_service_health_exists" + ] + }, + { + "Id": "LOG-07", + "Description": "Establish, document and implement which information meta/data system events should be logged. Review and update the scope at least annually or whenever there is a change in the threat environment.", + "Name": "Logging Scope", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 7.5.3", + "27001: A.12.4.1", + "27002: 12.4.1", + "27017: 12.4.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 7.5.3", + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-1", + "AU-14", + "AU-16" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.SC-3", + "ID.SC-4", + "PR.PT-1", + "ID.GV-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.3" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.2.1", + "10.2.2" + ] + } + ] + } + ], + "Checks": [ + "app_function_application_insights_enabled", + "appinsights_ensure_is_configured", + "monitor_diagnostic_setting_with_appropriate_categories", + "monitor_diagnostic_settings_exists", + "network_flow_log_captured_sent", + "network_flow_log_more_than_90_days" + ] + }, + { + "Id": "LOG-08", + "Description": "Generate audit records containing relevant security information.", + "Name": "Log Records", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.1", + "27002: 12.4.1", + "27017: 12.4.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-3", + "AU-3(1)", + "AU-3(3)", + "AU-6", + "AU-6(8)", + "AU-12", + "AU-12(1)", + "AU-12(2)", + "AU-12(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.PT-1", + "DE.AE-3", + "DE.CM-1", + "DE.CM-2", + "DE.CM-3", + "DE.CM-6", + "DE.CM-7" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.CM-01", + "DE.CM-02", + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.3" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.2.2" + ] + } + ] + } + ], + "Checks": [ + "app_function_application_insights_enabled", + "app_http_logs_enabled", + "appinsights_ensure_is_configured", + "keyvault_logging_enabled", + "monitor_diagnostic_setting_with_appropriate_categories", + "monitor_diagnostic_settings_exists", + "mysql_flexible_server_audit_log_connection_activated", + "mysql_flexible_server_audit_log_enabled", + "network_flow_log_captured_sent", + "network_flow_log_more_than_90_days", + "postgresql_flexible_server_log_checkpoints_on", + "postgresql_flexible_server_log_connections_on", + "postgresql_flexible_server_log_disconnections_on", + "postgresql_flexible_server_log_retention_days_greater_3", + "sqlserver_auditing_enabled", + "sqlserver_auditing_retention_90_days" + ] + }, + { + "Id": "LOG-09", + "Description": "The information system protects audit records from unauthorized access, modification, and deletion.", + "Name": "Log Protection", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-04", + "IVS-01" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.4", + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.2", + "27002: 12.4.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-9", + "AU-9(2)", + "AU-9(3)", + "AU-9(4)", + "AU-12(3)", + "AU-12(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4", + "PR.IP-4", + "PR.IP-6", + "PR.PT-1", + "PR.DS-1", + "PR.DS-6" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05", + "PR.DS-01", + "PR.DS-02", + "PR.DS-11" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.5", + "10.5.1", + "10.5.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.3.1", + "10.3.2", + "10.3.3", + "10.3.4" + ] + } + ] + } + ], + "Checks": [ + "keyvault_logging_enabled", + "monitor_diagnostic_setting_with_appropriate_categories", + "monitor_storage_account_with_activity_logs_cmk_encrypted", + "monitor_storage_account_with_activity_logs_is_private", + "storage_ensure_encryption_with_customer_managed_keys" + ] + }, + { + "Id": "LOG-10", + "Description": "Establish and maintain a monitoring and internal reporting capability over the operations of cryptographic, encryption and key management policies, processes, procedures, and controls.", + "Name": "Encryption Monitoring and Reporting", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC7.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-02", + "EKM-03" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1", + "5.1.1", + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1", + "27002: 10.1", + "27001: A.10.1.2", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-1", + "AU-9", + "AU-9(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-1", + "PR.PT-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.1.1", + "10.2.1", + "10.4.1" + ] + } + ] + } + ], + "Checks": [ + "keyvault_key_expiration_set_in_non_rbac", + "keyvault_key_rotation_enabled", + "keyvault_rbac_key_expiration_set" + ] + }, + { + "Id": "LOG-11", + "Description": "Log and monitor key lifecycle management events to enable auditing and reporting on usage of cryptographic keys.", + "Name": "Transaction/Activity Logging", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC7.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-02" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1.2", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-9", + "AU-9(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.PT-1", + "DE.AE-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.CM-09" + ] + } + ] + } + ], + "Checks": [ + "monitor_diagnostic_setting_with_appropriate_categories", + "monitor_diagnostic_settings_exists" + ] + }, + { + "Id": "LOG-13", + "Description": "Define, implement and evaluate processes, procedures and technical measures for the reporting of anomalies and failures of the monitoring system and provide immediate notification to the accountable party.", + "Name": "Failures and Anomalies Reporting", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC2.3", + "CC7.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "SEF-03" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.1", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.16.1.1", + "27002: 16.1.1", + "27001: A.16.1.2", + "27017: 16.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.24", + "27001: A.6.8", + "27002: 6.8 (g)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-5", + "AU-5(2)", + "AU-6", + "AU-6(3)", + "AU-6(4)", + "AU-6(5)", + "AU-16" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.DP-3", + "DE.DP-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.AE-06" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.4.3", + "10.7.1", + "10.7.2", + "10.7.3" + ] + } + ] + } + ], + "Checks": [ + "defender_container_images_resolved_vulnerabilities", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_notify_alerts_severity_is_high", + "defender_ensure_notify_emails_to_owners", + "defender_ensure_wdatp_is_enabled", + "monitor_alert_service_health_exists" + ] + }, + { + "Id": "SEF-03", + "Description": "'Establish, document, approve, communicate, apply, evaluate and maintain a security incident response plan, which includes but is not limited to: relevant internal departments, impacted CSCs, and other business critical relationships (such as supply-chain) that may be impacted.'", + "Name": "Incident Response Plans", + "Attributes": [ + { + "Section": "Security Incident Management, E-Discovery, & Cloud Forensics", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2", + "CC7.3", + "CC7.4" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "BCR-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "17.2", + "17.4" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.2", + "1.6.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: A.16.1.5", + "27002: 16.1.5", + "27017: 16.1.5", + "27017: CLD.12.1.5", + "27018: 16.1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: A.5.26", + "27002: 5.26 (e,f)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "IR-1", + "IR-2", + "IR-2(1)-(3)", + "IR-3", + "IR-3(1)-(3)", + "IR-4", + "IR-4(1)-(15)", + "IR-5", + "IR-5(1)", + "IR-6", + "IR-6(1)-(3)", + "IR-7", + "IR-7(1)", + "IR-7(2)", + "IR-8", + "IR-8(1)", + "IR-9", + "IR-9(1)-(4)", + "PM-12" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "RS.CO-1", + "RS.CO-4", + "ID.AM-6", + "ID.GV-2", + "ID.SC-5", + "PR.IP-9", + "PR.IP10" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AT-01", + "PR.AT-02", + "RS.MA-01", + "GV.SC-08", + "ID.IM-02", + "ID.IM-04", + "RC.RP-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "12.1", + "12.10.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.10.1", + "12.10.5" + ] + } + ] + } + ], + "Checks": [ + "defender_attack_path_notifications_properly_configured", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_notify_alerts_severity_is_high" + ] + }, + { + "Id": "SEF-06", + "Description": "Define, implement and evaluate processes, procedures and technical measures supporting business processes to triage security-related events.", + "Name": "Event Triage Processes", + "Attributes": [ + { + "Section": "Security Incident Management, E-Discovery, & Cloud Forensics", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "SEF-02" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.16.1.4", + "27002: 16.1.4", + "27017: 16.1.4", + "27018: 16.1.4", + "27001: A.16.1.5", + "27002: 16.1.5", + "27017: 16.1.5", + "27018: 16.1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.25" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CA-7", + "CA-7(3)", + "CA-7(4)", + "CA-7(5)", + "CA-7(6)", + "IR-4", + "IR-4(1)", + "IR-4(3)", + "IR-4(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.AE-1", + "DE.AE-2", + "DE.AE-4", + "RS.RP-1", + "RS.AN-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "RS.MA-02", + "RS.MA-03", + "RS.AN-03", + "DE.AE-02", + "DE.AE-04", + "DE.AE-06", + "DE.AE-07", + "DE.AE-08", + "RS.MI-02", + "RC.RP-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "12.5.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.10.1" + ] + } + ] + } + ], + "Checks": [ + "defender_ensure_defender_for_app_services_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_databases_is_on", + "defender_ensure_defender_for_keyvault_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_mcas_is_enabled", + "defender_ensure_wdatp_is_enabled" + ] + }, + { + "Id": "SEF-08", + "Description": "Maintain points of contact for applicable regulation authorities, national and local law enforcement, and other legal jurisdictional authorities.", + "Name": "Points of Contact Maintenance", + "Attributes": [ + { + "Section": "Security Incident Management, E-Discovery, & Cloud Forensics", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC2.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "SEF-01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "17.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.2", + "1.6.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SM2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 4.2", + "27001: A.6.1.3", + "27002: 6.1.3", + "27017: 6.1.3", + "27018: 6.1.3", + "27001: A.16.1.1", + "27002: 16.1.1", + "27001: A.18.1.1", + "27002: 18.1.1", + "27017: 18.1.1", + "27018: 18.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.5", + "27001: A.5.24", + "27002: 5.24 Incident management procedure (d)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "IR-4", + "IR-4(8)", + "IR-6", + "IR-6(3)", + "IR-7", + "IR-7(2)", + "PM-21", + "PM-23", + "PM-26" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-2", + "RS.CO-3", + "RS.CO-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.RR-02", + "RS.CO-02", + "RS.CO-03" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.10.1" + ] + } + ] + } + ], + "Checks": [ + "defender_additional_email_configured_with_a_security_contact", + "defender_ensure_notify_emails_to_owners" + ] + }, + { + "Id": "TVM-02", + "Description": "Establish, document, approve, communicate, apply, evaluate and maintain policies and procedures to protect against malware on managed assets. Review and update the policies and procedures at least annually.", + "Name": "Malware Protection Policy and Procedures", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC5.3", + "CC6.8" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "TVM-01", + "GRM-06", + "GRM-09" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "9.7", + "10.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.1.1", + "1.5.1", + "5.2.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS1.2", + "TS1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 5.1", + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: 9.1", + "27001: 9.3", + "27001: A.5", + "27002: 5", + "27001: A.12.2.1", + "27001: A.6.2.1", + "27002: 6.2.1 (h)", + "27001: A.6.2.2", + "27002: 6.2.2 (j)", + "27001: A.7.2.2", + "27002: 7.2.2 (d)", + "27001: A.10.1.1", + "27002: 10.1.1 (g)", + "27001: A.13.2.1", + "27002: 13.2.1 (b)", + "27001: A.15.1.2", + "27017: 15.1.2", + "27001: A.12.2.1", + "27002: 12.2.1 (a),(d)", + "27017: CLD.9.5.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 5.1", + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: 9.1", + "27001: 9.3", + "27001: A.5.1", + "27001: A.5.4", + "27001: A.5.7", + "27001: A.5.37", + "27001: A.8.7", + "27002: 5.7 (b)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "RA-3", + "RA-3(3)", + "RA-5", + "RA-5(3)", + "RA-5(5)", + "SI-3", + "SI-3(4)", + "SI-3(10)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-1", + "DE.CM-4", + "DE.CM-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.PO-01", + "GV.PO-02", + "ID.IM-03", + "DE.CM-01", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "5.4", + "12.1", + "12.1.1", + "12.3.1", + "12.5.1", + "12.11" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.1.1", + "12.1.2", + "5.1.1", + "5.3.2.1" + ] + } + ] + } + ], + "Checks": [ + "defender_assessments_vm_endpoint_protection_installed", + "defender_auto_provisioning_log_analytics_agent_vms_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_wdatp_is_enabled" + ] + }, + { + "Id": "TVM-03", + "Description": "Define, implement and evaluate processes, procedures and technical measures to enable both scheduled and emergency responses to vulnerability identifications, based on the identified risk.", + "Name": "Vulnerability Remediation Schedule", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC5.3", + "CC7.1", + "CC7.4" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "TVM-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "7.2", + "7.7", + "17.9" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.5" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.1", + "TM2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.12.2.1", + "27001: A.12.6.1", + "27002: 12.6.1(c)(d)(j)", + "27018: 12.6.1(k)(i)" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.8.7", + "27001: A.8.8", + "27001: A.8.32", + "27002: 8.7", + "27002: 8.8", + "27002: 8.32" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PM-31", + "RA-3", + "RA-3(1)", + "RA-5", + "RA-5(2)-(4)", + "RA-5(6)", + "SI-3", + "SI-3(10)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "RS.AN-5", + "PR.IP-12" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.RA-01", + "ID.RA-06", + "ID.RA-08", + "PR.PS-02", + "PR.PS-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.1", + "6.1.a", + "6.1.b" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.1.1", + "6.3.1", + "6.3.2", + "6.3.3", + "12.10.1" + ] + } + ] + } + ], + "Checks": [ + "app_ensure_java_version_is_latest", + "app_ensure_php_version_is_latest", + "app_ensure_python_version_is_latest", + "app_function_latest_runtime_version", + "defender_ensure_system_updates_are_applied" + ] + }, + { + "Id": "TVM-04", + "Description": "Define, implement and evaluate processes, procedures and technical measures to update detection tools, threat signatures, and indicators of compromise on a weekly, or more frequent basis.", + "Name": "Detection Updates", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "No mapping" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "10.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS1.3", + "TS1.4", + "TM1.3", + "TM1.4", + "IM1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.5.1.1", + "27002: 5.1.1 (h)", + "27001: A.12.6.1", + "27002: 12.6.1 (b),(c)" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.5.1", + "27001: A.8.8", + "27001: A.8.15", + "27001: A.8.16", + "27002: 5.1", + "27002: 5.37", + "27002: 8.8", + "27002: 8.15 (d)", + "27002: 8.16 (d,e)", + "27002: 8.31 2nd (a)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-7", + "CM-7(4)", + "RA-3", + "RA-3(3)", + "RA-5(2)", + "SA-10", + "SA-10(5)", + "SA-11", + "SA-11(2)", + "SI-2", + "SI-2(4)", + "SI-3", + "SI-3(4)", + "SI-4", + "SI-4(9)", + "SI-4(24)", + "SI-8", + "SI-8(2)", + "SI-8(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.DP-5", + "PR.IP-12" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-02", + "ID.RA-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "5.2", + "5.2a", + "5.2b", + "5.2c" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "5.3.1" + ] + } + ] + } + ], + "Checks": [ + "defender_auto_provisioning_vulnerabilty_assessments_machines_on", + "defender_container_images_scan_enabled", + "defender_ensure_defender_for_containers_is_on", + "defender_ensure_defender_for_cosmosdb_is_on", + "defender_ensure_defender_for_os_relational_databases_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_defender_for_sql_servers_is_on", + "defender_ensure_wdatp_is_enabled" + ] + }, + { + "Id": "TVM-05", + "Description": "Define, implement and evaluate processes, procedures and technical measures to identify updates for applications which use third party or open source libraries according to the organization's vulnerability management policy.", + "Name": "External Library Vulnerabilities", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC3.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "No mapping" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "2.6" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.1", + "SD2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.12.6.2", + "27002: 12.6.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1.3", + "27001: A 5.6", + "27001: A.8.19", + "27001: A.8.8", + "27001: A.8.28", + "27001: A.8.31", + "27002: 5.6 (c)", + "27001: 8.19", + "27001: 8.8", + "27001: 8.28", + "27001: 8.31" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "RA-5", + "RA-5(3)", + "SA-11", + "SA-11(2)", + "SA-11(5)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.DP-5", + "PR.IP-12" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.RA-01", + "ID.RA-03", + "PR.PS-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.1", + "6.2", + "6.3.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.3.1", + "6.3.2", + "6.3.3" + ] + } + ] + } + ], + "Checks": [ + "defender_container_images_resolved_vulnerabilities", + "defender_container_images_scan_enabled", + "defender_ensure_defender_for_containers_is_on", + "sqlserver_va_emails_notifications_admins_enabled", + "sqlserver_va_periodic_recurring_scans_enabled", + "sqlserver_va_scan_reports_configured", + "sqlserver_vulnerability_assessment_enabled" + ] + }, + { + "Id": "TVM-07", + "Description": "Define, implement and evaluate processes, procedures and technical measures for the detection of vulnerabilities on organizationally managed assets at least monthly.", + "Name": "Vulnerability Identification", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "TVM-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "7.1", + "7.5", + "7.6" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.5", + "5.2.6" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.6", + "27001: A.12.6.1", + "27002: 12.6.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.8", + "27002: 8.8" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "RA-5", + "RA-5(4)", + "RA-5(5)", + "SA-11", + "SA-11(5)", + "SA-15(5)", + "SC-7", + "SC-7(10)", + "SI-3(8)", + "SI-3(10)", + "SI-7", + "SI-7(9)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.RA-1", + "DE.CM-8", + "PR.IP-12" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.RA-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.1", + "11.2", + "11.2.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.3.1", + "6.3.2", + "6.3.3", + "11.3.2", + "11.3.2.1" + ] + } + ] + } + ], + "Checks": [ + "defender_auto_provisioning_vulnerabilty_assessments_machines_on", + "defender_container_images_resolved_vulnerabilities", + "defender_container_images_scan_enabled", + "defender_ensure_defender_for_containers_is_on", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_wdatp_is_enabled", + "sqlserver_microsoft_defender_enabled", + "sqlserver_vulnerability_assessment_enabled" + ] + }, + { + "Id": "UEM-08", + "Description": "Protect information from unauthorized disclosure on managed endpoint devices with storage encryption.", + "Name": "Storage Encryption", + "Attributes": [ + { + "Section": "Universal Endpoint Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "MOS-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.6" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.2", + "3.1.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "PA1.2", + "PA1.3", + "PA1.5", + "PA2.2", + "PM1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.11.2.7", + "27002: 11.2.7", + "27001: A.18.1.1", + "27017: 18.1.1", + "27001: A.12.3.1", + "27017: 12.3.1", + "27018: A.11.4", + "27018: A.11.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.1", + "27002: 8.1 (h)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-19(5)", + "SC-28", + "SC-28(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.4", + "3.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.5.1", + "3.6" + ] + } + ] + } + ], + "Checks": [ + "databricks_workspace_cmk_encryption_enabled", + "storage_infrastructure_encryption_is_enabled", + "vm_ensure_attached_disks_encrypted_with_cmk", + "vm_ensure_unattached_disks_encrypted_with_cmk" + ] + }, + { + "Id": "UEM-11", + "Description": "Configure managed endpoints with Data Loss Prevention (DLP) technologies and rules in accordance with a risk assessment.", + "Name": "Data Loss Prevention", + "Attributes": [ + { + "Section": "Universal Endpoint Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.7" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.13" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.7" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.5", + "PA2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.3", + "27002: 12.3", + "27001: A.8.3.1", + "27002: 8.3.1", + "27001: A.12.2", + "27002: 12.2", + "27001: A.18.1.3", + "27002: 18.1.3", + "27001: A.6.1.1", + "27017: 6.1.1", + "27018: 12.3.1", + "27018: 10.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.12", + "27001: A.8.3" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-7", + "SC-7(10)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-02", + "PR.DS-10", + "PR.PS-01", + "ID.AM-08", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "A3.2.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "A3.2.6" + ] + } + ] + } + ], + "Checks": [ + "defender_ensure_defender_for_storage_is_on", + "defender_ensure_mcas_is_enabled" + ] + } + ] +} diff --git a/prowler/lib/outputs/compliance/csa/csa_azure.py b/prowler/lib/outputs/compliance/csa/csa_azure.py new file mode 100644 index 0000000000..9bb16e6f11 --- /dev/null +++ b/prowler/lib/outputs/compliance/csa/csa_azure.py @@ -0,0 +1,96 @@ +from prowler.config.config import timestamp +from prowler.lib.check.compliance_models import Compliance +from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput +from prowler.lib.outputs.compliance.csa.models import AzureCSAModel +from prowler.lib.outputs.finding import Finding + + +class AzureCSA(ComplianceOutput): + """ + This class represents the Azure CSA compliance output. + + Attributes: + - _data (list): A list to store transformed data from findings. + - _file_descriptor (TextIOWrapper): A file descriptor to write data to a file. + + Methods: + - transform: Transforms findings into Azure CSA compliance format. + """ + + def transform( + self, + findings: list[Finding], + compliance: Compliance, + compliance_name: str, + ) -> None: + """ + Transforms a list of findings into Azure CSA compliance format. + + Parameters: + - findings (list): A list of findings. + - compliance (Compliance): A compliance model. + - compliance_name (str): The name of the compliance model. + + Returns: + - None + """ + for finding in findings: + # Get the compliance requirements for the finding + finding_requirements = finding.compliance.get(compliance_name, []) + for requirement in compliance.Requirements: + if requirement.Id in finding_requirements: + for attribute in requirement.Attributes: + compliance_row = AzureCSAModel( + Provider=finding.provider, + Description=compliance.Description, + SubscriptionId=finding.account_uid, + Location=finding.region, + AssessmentDate=str(timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Name=requirement.Name, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_CCMLite=attribute.CCMLite, + Requirements_Attributes_IaaS=attribute.IaaS, + Requirements_Attributes_PaaS=attribute.PaaS, + Requirements_Attributes_SaaS=attribute.SaaS, + Requirements_Attributes_ScopeApplicability=attribute.ScopeApplicability, + Status=finding.status, + StatusExtended=finding.status_extended, + ResourceId=finding.resource_uid, + ResourceName=finding.resource_name, + CheckId=finding.check_id, + Muted=finding.muted, + Framework=compliance.Framework, + Name=compliance.Name, + ) + self._data.append(compliance_row) + # Add manual requirements to the compliance output + for requirement in compliance.Requirements: + if not requirement.Checks: + for attribute in requirement.Attributes: + compliance_row = AzureCSAModel( + Provider=compliance.Provider.lower(), + Description=compliance.Description, + SubscriptionId="", + Location="", + AssessmentDate=str(timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Name=requirement.Name, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_CCMLite=attribute.CCMLite, + Requirements_Attributes_IaaS=attribute.IaaS, + Requirements_Attributes_PaaS=attribute.PaaS, + Requirements_Attributes_SaaS=attribute.SaaS, + Requirements_Attributes_ScopeApplicability=attribute.ScopeApplicability, + Status="MANUAL", + StatusExtended="Manual check", + ResourceId="manual_check", + ResourceName="Manual check", + CheckId="manual", + Muted=False, + Framework=compliance.Framework, + Name=compliance.Name, + ) + self._data.append(compliance_row) diff --git a/prowler/lib/outputs/compliance/csa/models.py b/prowler/lib/outputs/compliance/csa/models.py index 2e9ad3a4f5..e981671d38 100644 --- a/prowler/lib/outputs/compliance/csa/models.py +++ b/prowler/lib/outputs/compliance/csa/models.py @@ -28,3 +28,32 @@ class AWSCSAModel(BaseModel): ResourceName: str Framework: str Name: str + + +class AzureCSAModel(BaseModel): + """ + AzureCSAModel generates a finding's output in CSV CSA format for Azure. + """ + + Provider: str + Description: str + SubscriptionId: str + Location: str + AssessmentDate: str + Requirements_Id: str + Requirements_Description: str + Requirements_Name: str + Requirements_Attributes_Section: str + Requirements_Attributes_CCMLite: str + Requirements_Attributes_IaaS: str + Requirements_Attributes_PaaS: str + Requirements_Attributes_SaaS: str + Requirements_Attributes_ScopeApplicability: list[dict] + Status: str + StatusExtended: str + ResourceId: str + CheckId: str + Muted: bool + ResourceName: str + Framework: str + Name: str From c5707ae9f1617db97bc220fe5d4d49876f59d11c Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:02:05 +0100 Subject: [PATCH 05/12] chore(ui): update npm dependencies to fix security vulnerabilities (#10052) --- ui/CHANGELOG.md | 4 + ui/dependency-log.json | 22 +- ui/package.json | 17 +- ui/pnpm-lock.yaml | 1818 ++++++++++++++++++++++------------------ 4 files changed, 1038 insertions(+), 823 deletions(-) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index f13e3406a0..1e7e252047 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -9,6 +9,10 @@ All notable changes to the **Prowler UI** are documented in this file. - Attack Paths: Query list now shows their name and short description, when one is selected it also shows a longer description and an attribution if it has it [(#9983)](https://github.com/prowler-cloud/prowler/pull/9983) - CSA CCM detailed view and small fix related with `Top Failed Sections` width [(#10018)](https://github.com/prowler-cloud/prowler/pull/10018) +### 🔐 Security + +- npm dependencies updated to resolve 11 Dependabot alerts (4 HIGH, 7 MEDIUM): fast-xml-parser, @modelcontextprotocol/sdk, tar, @isaacs/brace-expansion, hono, lodash, lodash-es [(#10052)](https://github.com/prowler-cloud/prowler/pull/10052) + --- ## [1.18.2] (Prowler UNRELEASED) diff --git a/ui/dependency-log.json b/ui/dependency-log.json index 65b799d3f9..656f637ecd 100644 --- a/ui/dependency-log.json +++ b/ui/dependency-log.json @@ -10,10 +10,10 @@ { "section": "dependencies", "name": "@aws-sdk/client-bedrock-runtime", - "from": "3.943.0", - "to": "3.948.0", + "from": "3.948.0", + "to": "3.988.0", "strategy": "installed", - "generatedAt": "2025-12-15T08:24:46.195Z" + "generatedAt": "2026-02-12T11:04:39.164Z" }, { "section": "dependencies", @@ -67,9 +67,9 @@ "section": "dependencies", "name": "@langchain/mcp-adapters", "from": "1.0.3", - "to": "1.0.3", + "to": "1.1.3", "strategy": "installed", - "generatedAt": "2025-12-12T10:01:54.132Z" + "generatedAt": "2026-02-12T11:04:39.164Z" }, { "section": "dependencies", @@ -283,9 +283,9 @@ "section": "dependencies", "name": "@tailwindcss/postcss", "from": "4.1.13", - "to": "4.1.13", + "to": "4.1.18", "strategy": "installed", - "generatedAt": "2025-10-22T12:36:37.962Z" + "generatedAt": "2026-02-12T11:04:39.164Z" }, { "section": "dependencies", @@ -947,9 +947,9 @@ "section": "devDependencies", "name": "shadcn", "from": "3.4.1", - "to": "3.4.1", + "to": "3.8.4", "strategy": "installed", - "generatedAt": "2025-10-22T15:52:15.849Z" + "generatedAt": "2026-02-12T11:04:39.164Z" }, { "section": "devDependencies", @@ -963,9 +963,9 @@ "section": "devDependencies", "name": "tailwindcss", "from": "4.1.13", - "to": "4.1.13", + "to": "4.1.18", "strategy": "installed", - "generatedAt": "2025-10-22T12:36:37.962Z" + "generatedAt": "2026-02-12T11:04:39.164Z" }, { "section": "devDependencies", diff --git a/ui/package.json b/ui/package.json index 5a79cb5cce..a27209a601 100644 --- a/ui/package.json +++ b/ui/package.json @@ -25,14 +25,14 @@ }, "dependencies": { "@ai-sdk/react": "2.0.111", - "@aws-sdk/client-bedrock-runtime": "3.948.0", + "@aws-sdk/client-bedrock-runtime": "3.988.0", "@extractus/feed-extractor": "7.1.7", "@heroui/react": "2.8.4", "@hookform/resolvers": "5.2.2", "@internationalized/date": "3.10.0", "@langchain/aws": "1.1.0", "@langchain/core": "1.1.15", - "@langchain/mcp-adapters": "1.0.3", + "@langchain/mcp-adapters": "1.1.3", "@langchain/openai": "1.1.3", "@next/third-parties": "16.1.6", "@radix-ui/react-alert-dialog": "1.1.14", @@ -59,7 +59,7 @@ "@react-types/datepicker": "3.13.2", "@react-types/shared": "3.26.0", "@sentry/nextjs": "10.27.0", - "@tailwindcss/postcss": "4.1.13", + "@tailwindcss/postcss": "4.1.18", "@tailwindcss/typography": "0.5.16", "@tanstack/react-table": "8.21.3", "@types/dagre": "0.7.53", @@ -144,9 +144,9 @@ "postcss": "8.4.38", "prettier": "3.6.2", "prettier-plugin-tailwindcss": "0.6.14", - "shadcn": "3.4.1", + "shadcn": "3.8.4", "tailwind-variants": "0.1.20", - "tailwindcss": "4.1.13", + "tailwindcss": "4.1.18", "typescript": "5.5.4" }, "pnpm": { @@ -158,7 +158,12 @@ "@react-aria/ssr>react": "19.2.4", "@react-aria/ssr>react-dom": "19.2.4", "@react-aria/visually-hidden>react": "19.2.4", - "@react-aria/interactions>react": "19.2.4" + "@react-aria/interactions>react": "19.2.4", + "lodash": "4.17.23", + "lodash-es": "4.17.23", + "hono": "4.11.7", + "@isaacs/brace-expansion": "5.0.1", + "fast-xml-parser": "5.3.4" } }, "version": "0.0.1", diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index 86bac336d4..af29b99b3e 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -13,6 +13,11 @@ overrides: '@react-aria/ssr>react-dom': 19.2.4 '@react-aria/visually-hidden>react': 19.2.4 '@react-aria/interactions>react': 19.2.4 + lodash: 4.17.23 + lodash-es: 4.17.23 + hono: 4.11.7 + '@isaacs/brace-expansion': 5.0.1 + fast-xml-parser: 5.3.4 importers: @@ -22,14 +27,14 @@ importers: specifier: 2.0.111 version: 2.0.111(react@19.2.4)(zod@4.1.11) '@aws-sdk/client-bedrock-runtime': - specifier: 3.948.0 - version: 3.948.0 + specifier: 3.988.0 + version: 3.988.0 '@extractus/feed-extractor': specifier: 7.1.7 version: 7.1.7 '@heroui/react': specifier: 2.8.4 - version: 2.8.4(@types/react@19.2.8)(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.13) + version: 2.8.4(@types/react@19.2.8)(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18) '@hookform/resolvers': specifier: 5.2.2 version: 5.2.2(react-hook-form@7.62.0(react@19.2.4)) @@ -43,8 +48,8 @@ importers: specifier: 1.1.15 version: 1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)) '@langchain/mcp-adapters': - specifier: 1.0.3 - version: 1.0.3(@cfworker/json-schema@4.1.1)(@langchain/core@1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)))(@langchain/langgraph@1.1.0(@langchain/core@1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@4.1.11))(zod@4.1.11))(hono@4.11.4) + specifier: 1.1.3 + version: 1.1.3(@cfworker/json-schema@4.1.1)(@langchain/core@1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)))(@langchain/langgraph@1.1.0(@langchain/core@1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@4.1.11))(zod@4.1.11)) '@langchain/openai': specifier: 1.1.3 version: 1.1.3(@langchain/core@1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11))) @@ -124,11 +129,11 @@ importers: specifier: 10.27.0 version: 10.27.0(@opentelemetry/context-async-hooks@2.4.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.4.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(next@16.1.6(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(webpack@5.104.1) '@tailwindcss/postcss': - specifier: 4.1.13 - version: 4.1.13 + specifier: 4.1.18 + version: 4.1.18 '@tailwindcss/typography': specifier: 0.5.16 - version: 0.5.16(tailwindcss@4.1.13) + version: 0.5.16(tailwindcss@4.1.18) '@tanstack/react-table': specifier: 8.21.3 version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -242,7 +247,7 @@ importers: version: 3.3.1 tailwindcss-animate: specifier: 1.0.7 - version: 1.0.7(tailwindcss@4.1.13) + version: 1.0.7(tailwindcss@4.1.18) topojson-client: specifier: 3.1.0 version: 3.1.0 @@ -374,14 +379,14 @@ importers: specifier: 0.6.14 version: 0.6.14(prettier@3.6.2) shadcn: - specifier: 3.4.1 - version: 3.4.1(@cfworker/json-schema@4.1.1)(@types/node@24.10.8)(hono@4.11.4)(typescript@5.5.4) + specifier: 3.8.4 + version: 3.8.4(@cfworker/json-schema@4.1.1)(@types/node@24.10.8)(typescript@5.5.4) tailwind-variants: specifier: 0.1.20 - version: 0.1.20(tailwindcss@4.1.13) + version: 0.1.20(tailwindcss@4.1.18) tailwindcss: - specifier: 4.1.13 - version: 4.1.13 + specifier: 4.1.18 + version: 4.1.18 typescript: specifier: 5.5.4 version: 5.5.4 @@ -466,200 +471,191 @@ packages: resolution: {integrity: sha512-QDD0sl0Wfm1FI/JK6Yexg/j1l51LtPL/8aaqMPGpa4yZpIU3K9wJd5LKPOoO0dMB9M0PrVq+JbsUpJ+mS8bgAA==} engines: {node: '>=20.0.0'} - '@aws-sdk/client-bedrock-runtime@3.948.0': - resolution: {integrity: sha512-JRlqANr0wY63ZXZPKaWIoH0zYXsllROynPVj8XdOFwiO/pRr/2hol8popfMhD7T5Zb6yZQ/FM8Tu5Mc61l2HHQ==} - engines: {node: '>=18.0.0'} + '@aws-sdk/client-bedrock-runtime@3.988.0': + resolution: {integrity: sha512-NZlsQ8rjmAG0zRteqEiRakV97/nToIwDqT0zbye+j+HN60wiRSESAFCEozdwiiuVr0xl69NcoTiMg64xbh2I9g==} + engines: {node: '>=20.0.0'} '@aws-sdk/client-kendra@3.971.0': resolution: {integrity: sha512-iDkT0oMDfgjPctzR+g61Ends/QX/SeyFJL0m9tZqMAgDWsoht+N4INgtuKCmmIXggvh39BwWHM1/tQEbPIcq9A==} engines: {node: '>=20.0.0'} - '@aws-sdk/client-sso@3.948.0': - resolution: {integrity: sha512-iWjchXy8bIAVBUsKnbfKYXRwhLgRg3EqCQ5FTr3JbR+QR75rZm4ZOYXlvHGztVTmtAZ+PQVA1Y4zO7v7N87C0A==} - engines: {node: '>=18.0.0'} - '@aws-sdk/client-sso@3.971.0': resolution: {integrity: sha512-Xx+w6DQqJxDdymYyIxyKJnRzPvVJ4e/Aw0czO7aC9L/iraaV7AG8QtRe93OGW6aoHSh72CIiinnpJJfLsQqP4g==} engines: {node: '>=20.0.0'} - '@aws-sdk/core@3.947.0': - resolution: {integrity: sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw==} - engines: {node: '>=18.0.0'} + '@aws-sdk/client-sso@3.988.0': + resolution: {integrity: sha512-ThqQ7aF1k0Zz4yJRwegHw+T1rM3a7ZPvvEUSEdvn5Z8zTeWgJAbtqW/6ejPsMLmFOlHgNcwDQN/e69OvtEOoIQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/core@3.970.0': resolution: {integrity: sha512-klpzObldOq8HXzDjDlY6K8rMhYZU6mXRz6P9F9N+tWnjoYFfeBMra8wYApydElTUYQKP1O7RLHwH1OKFfKcqIA==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-env@3.947.0': - resolution: {integrity: sha512-VR2V6dRELmzwAsCpK4GqxUi6UW5WNhAXS9F9AzWi5jvijwJo3nH92YNJUP4quMpgFZxJHEWyXLWgPjh9u0zYOA==} - engines: {node: '>=18.0.0'} + '@aws-sdk/core@3.973.8': + resolution: {integrity: sha512-WeYJ2sfvRLbbUIrjGMUXcEHGu5SJk53jz3K9F8vFP42zWyROzPJ2NB6lMu9vWl5hnMwzwabX7pJc9Euh3JyMGw==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-env@3.970.0': resolution: {integrity: sha512-rtVzXzEtAfZBfh+lq3DAvRar4c3jyptweOAJR2DweyXx71QSMY+O879hjpMwES7jl07a3O1zlnFIDo4KP/96kQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-http@3.947.0': - resolution: {integrity: sha512-inF09lh9SlHj63Vmr5d+LmwPXZc2IbK8lAruhOr3KLsZAIHEgHgGPXWDC2ukTEMzg0pkexQ6FOhXXad6klK4RA==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-env@3.972.6': + resolution: {integrity: sha512-+dYEBWgTqkQQHFUllvBL8SLyXyLKWdxLMD1LmKJRvmb0NMJuaJFG/qg78C+LE67eeGbipYcE+gJ48VlLBGHlMw==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-http@3.970.0': resolution: {integrity: sha512-CjDbWL7JxjLc9ZxQilMusWSw05yRvUJKRpz59IxDpWUnSMHC9JMMUUkOy5Izk8UAtzi6gupRWArp4NG4labt9Q==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-ini@3.948.0': - resolution: {integrity: sha512-Cl//Qh88e8HBL7yYkJNpF5eq76IO6rq8GsatKcfVBm7RFVxCqYEPSSBtkHdbtNwQdRQqAMXc6E/lEB/CZUDxnA==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-http@3.972.8': + resolution: {integrity: sha512-z3QkozMV8kOFisN2pgRag/f0zPDrw96mY+ejAM0xssV/+YQ2kklbylRNI/TcTQUDnGg0yPxNjyV6F2EM2zPTwg==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-ini@3.971.0': resolution: {integrity: sha512-c0TGJG4xyfTZz3SInXfGU8i5iOFRrLmy4Bo7lMyH+IpngohYMYGYl61omXqf2zdwMbDv+YJ9AviQTcCaEUKi8w==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-login@3.948.0': - resolution: {integrity: sha512-gcKO2b6eeTuZGp3Vvgr/9OxajMrD3W+FZ2FCyJox363ZgMoYJsyNid1vuZrEuAGkx0jvveLXfwiVS0UXyPkgtw==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-ini@3.972.6': + resolution: {integrity: sha512-6tkIYFv3sZH1XsjQq+veOmx8XWRnyqTZ5zx/sMtdu/xFRIzrJM1Y2wAXeCJL1rhYSB7uJSZ1PgALI2WVTj78ow==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-login@3.971.0': resolution: {integrity: sha512-yhbzmDOsk0RXD3rTPhZra4AWVnVAC4nFWbTp+sUty1hrOPurUmhuz8bjpLqYTHGnlMbJp+UqkQONhS2+2LzW2g==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-node@3.948.0': - resolution: {integrity: sha512-ep5vRLnrRdcsP17Ef31sNN4g8Nqk/4JBydcUJuFRbGuyQtrZZrVT81UeH2xhz6d0BK6ejafDB9+ZpBjXuWT5/Q==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-login@3.972.6': + resolution: {integrity: sha512-LXsoBoaTSGHdRCQXlWSA0CHHh05KWncb592h9ElklnPus++8kYn1Ic6acBR4LKFQ0RjjMVgwe5ypUpmTSUOjPA==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-node@3.971.0': resolution: {integrity: sha512-epUJBAKivtJqalnEBRsYIULKYV063o/5mXNJshZfyvkAgNIzc27CmmKRXTN4zaNOZg8g/UprFp25BGsi19x3nQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-process@3.947.0': - resolution: {integrity: sha512-WpanFbHe08SP1hAJNeDdBDVz9SGgMu/gc0XJ9u3uNpW99nKZjDpvPRAdW7WLA4K6essMjxWkguIGNOpij6Do2Q==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-node@3.972.7': + resolution: {integrity: sha512-PuJ1IkISG7ZDpBFYpGotaay6dYtmriBYuHJ/Oko4VHxh8YN5vfoWnMNYFEWuzOfyLmP7o9kDVW0BlYIpb3skvw==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-process@3.970.0': resolution: {integrity: sha512-0XeT8OaT9iMA62DFV9+m6mZfJhrD0WNKf4IvsIpj2Z7XbaYfz3CoDDvNoALf3rPY9NzyMHgDxOspmqdvXP00mw==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-sso@3.948.0': - resolution: {integrity: sha512-gqLhX1L+zb/ZDnnYbILQqJ46j735StfWV5PbDjxRzBKS7GzsiYoaf6MyHseEopmWrez5zl5l6aWzig7UpzSeQQ==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-process@3.972.6': + resolution: {integrity: sha512-Yf34cjIZJHVnD92jnVYy3tNjM+Q4WJtffLK2Ehn0nKpZfqd1m7SI0ra22Lym4C53ED76oZENVSS2wimoXJtChQ==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-sso@3.971.0': resolution: {integrity: sha512-dY0hMQ7dLVPQNJ8GyqXADxa9w5wNfmukgQniLxGVn+dMRx3YLViMp5ZpTSQpFhCWNF0oKQrYAI5cHhUJU1hETw==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-web-identity@3.948.0': - resolution: {integrity: sha512-MvYQlXVoJyfF3/SmnNzOVEtANRAiJIObEUYYyjTqKZTmcRIVVky0tPuG26XnB8LmTYgtESwJIZJj/Eyyc9WURQ==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-sso@3.972.6': + resolution: {integrity: sha512-2+5UVwUYdD4BBOkLpKJ11MQ8wQeyJGDVMDRH5eWOULAh9d6HJq07R69M/mNNMC9NTjr3mB1T0KGDn4qyQh5jzg==} + engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-web-identity@3.971.0': resolution: {integrity: sha512-F1AwfNLr7H52T640LNON/h34YDiMuIqW/ZreGzhRR6vnFGaSPtNSKAKB2ssAMkLM8EVg8MjEAYD3NCUiEo+t/w==} engines: {node: '>=20.0.0'} - '@aws-sdk/eventstream-handler-node@3.936.0': - resolution: {integrity: sha512-4zIbhdRmol2KosIHmU31ATvNP0tkJhDlRj9GuawVJoEnMvJA1pd2U3SRdiOImJU3j8pT46VeS4YMmYxfjGHByg==} - engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-web-identity@3.972.6': + resolution: {integrity: sha512-pdJzwKtlDxBnvZ04pWMqttijmkUIlwOsS0GcxCjzEVyUMpARysl0S0ks74+gs2Pdev3Ujz+BTAjOc1tQgAxGqA==} + engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-eventstream@3.936.0': - resolution: {integrity: sha512-XQSH8gzLkk8CDUDxyt4Rdm9owTpRIPdtg2yw9Y2Wl5iSI55YQSiC3x8nM3c4Y4WqReJprunFPK225ZUDoYCfZA==} - engines: {node: '>=18.0.0'} + '@aws-sdk/eventstream-handler-node@3.972.5': + resolution: {integrity: sha512-xEmd3dnyn83K6t4AJxBJA63wpEoCD45ERFG0XMTViD2E/Ohls9TLxjOWPb1PAxR9/46cKy/TImez1GoqP6xVNQ==} + engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-host-header@3.936.0': - resolution: {integrity: sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw==} - engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-eventstream@3.972.3': + resolution: {integrity: sha512-pbvZ6Ye/Ks6BAZPa3RhsNjHrvxU9li25PMhSdDpbX0jzdpKpAkIR65gXSNKmA/REnSdEMWSD4vKUW+5eMFzB6w==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-host-header@3.969.0': resolution: {integrity: sha512-AWa4rVsAfBR4xqm7pybQ8sUNJYnjyP/bJjfAw34qPuh3M9XrfGbAHG0aiAfQGrBnmS28jlO6Kz69o+c6PRw1dw==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-logger@3.936.0': - resolution: {integrity: sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw==} - engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-host-header@3.972.3': + resolution: {integrity: sha512-aknPTb2M+G3s+0qLCx4Li/qGZH8IIYjugHMv15JTYMe6mgZO8VBpYgeGYsNMGCqCZOcWzuf900jFBG5bopfzmA==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-logger@3.969.0': resolution: {integrity: sha512-xwrxfip7Y2iTtCMJ+iifN1E1XMOuhxIHY9DreMCvgdl4r7+48x2S1bCYPWH3eNY85/7CapBWdJ8cerpEl12sQQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-recursion-detection@3.948.0': - resolution: {integrity: sha512-Qa8Zj+EAqA0VlAVvxpRnpBpIWJI9KUwaioY1vkeNVwXPlNaz9y9zCKVM9iU9OZ5HXpoUg6TnhATAHXHAE8+QsQ==} - engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-logger@3.972.3': + resolution: {integrity: sha512-Ftg09xNNRqaz9QNzlfdQWfpqMCJbsQdnZVJP55jfhbKi1+FTWxGuvfPoBhDHIovqWKjqbuiew3HuhxbJ0+OjgA==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-recursion-detection@3.969.0': resolution: {integrity: sha512-2r3PuNquU3CcS1Am4vn/KHFwLi8QFjMdA/R+CRDXT4AFO/0qxevF/YStW3gAKntQIgWgQV8ZdEtKAoJvLI4UWg==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-user-agent@3.947.0': - resolution: {integrity: sha512-7rpKV8YNgCP2R4F9RjWZFcD2R+SO/0R4VHIbY9iZJdH2MzzJ8ZG7h8dZ2m8QkQd1fjx4wrFJGGPJUTYXPV3baA==} - engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-recursion-detection@3.972.3': + resolution: {integrity: sha512-PY57QhzNuXHnwbJgbWYTrqIDHYSeOlhfYERTAuc16LKZpTZRJUjzBFokp9hF7u1fuGeE3D70ERXzdbMBOqQz7Q==} + engines: {node: '>=20.0.0'} '@aws-sdk/middleware-user-agent@3.970.0': resolution: {integrity: sha512-dnSJGGUGSFGEX2NzvjwSefH+hmZQ347AwbLhAsi0cdnISSge+pcGfOFrJt2XfBIypwFe27chQhlfuf/gWdzpZg==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-websocket@3.936.0': - resolution: {integrity: sha512-bPe3rqeugyj/MmjP0yBSZox2v1Wa8Dv39KN+RxVbQroLO8VUitBo6xyZ0oZebhZ5sASwSg58aDcMlX0uFLQnTA==} - engines: {node: '>= 14.0.0'} + '@aws-sdk/middleware-user-agent@3.972.8': + resolution: {integrity: sha512-3PGL+Kvh1PhB0EeJeqNqOWQgipdqFheO4OUKc6aYiFwEpM5t9AyE5hjjxZ5X6iSj8JiduWFZLPwASzF6wQRgFg==} + engines: {node: '>=20.0.0'} - '@aws-sdk/nested-clients@3.948.0': - resolution: {integrity: sha512-zcbJfBsB6h254o3NuoEkf0+UY1GpE9ioiQdENWv7odo69s8iaGBEQ4BDpsIMqcuiiUXw1uKIVNxCB1gUGYz8lw==} - engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-websocket@3.972.6': + resolution: {integrity: sha512-1DedO6N3m8zQ/vG6twNiHtsdwBgk773VdavLEbB3NXeKZDlzSK1BTviqWwvJdKx5UnIy4kGGP6WWpCEFEt/bhQ==} + engines: {node: '>= 14.0.0'} '@aws-sdk/nested-clients@3.971.0': resolution: {integrity: sha512-TWaILL8GyYlhGrxxnmbkazM4QsXatwQgoWUvo251FXmUOsiXDFDVX3hoGIfB3CaJhV2pJPfebHUNJtY6TjZ11g==} engines: {node: '>=20.0.0'} - '@aws-sdk/region-config-resolver@3.936.0': - resolution: {integrity: sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw==} - engines: {node: '>=18.0.0'} + '@aws-sdk/nested-clients@3.988.0': + resolution: {integrity: sha512-OgYV9k1oBCQ6dOM+wWAMNNehXA8L4iwr7ydFV+JDHyuuu0Ko7tDXnLEtEmeQGYRcAFU3MGasmlBkMB8vf4POrg==} + engines: {node: '>=20.0.0'} '@aws-sdk/region-config-resolver@3.969.0': resolution: {integrity: sha512-scj9OXqKpcjJ4jsFLtqYWz3IaNvNOQTFFvEY8XMJXTv+3qF5I7/x9SJtKzTRJEBF3spjzBUYPtGFbs9sj4fisQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/token-providers@3.948.0': - resolution: {integrity: sha512-V487/kM4Teq5dcr1t5K6eoUKuqlGr9FRWL3MIMukMERJXHZvio6kox60FZ/YtciRHRI75u14YUqm2Dzddcu3+A==} - engines: {node: '>=18.0.0'} + '@aws-sdk/region-config-resolver@3.972.3': + resolution: {integrity: sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow==} + engines: {node: '>=20.0.0'} '@aws-sdk/token-providers@3.971.0': resolution: {integrity: sha512-4hKGWZbmuDdONMJV0HJ+9jwTDb0zLfKxcCLx2GEnBY31Gt9GeyIQ+DZ97Bb++0voawj6pnZToFikXTyrEq2x+w==} engines: {node: '>=20.0.0'} - '@aws-sdk/types@3.936.0': - resolution: {integrity: sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg==} - engines: {node: '>=18.0.0'} + '@aws-sdk/token-providers@3.988.0': + resolution: {integrity: sha512-xvXVlRVKHnF2h6fgWBm64aPP5J+58aJyGfRrQa/uFh8a9mcK68mLfJOYq+ZSxQy/UN3McafJ2ILAy7IWzT9kRw==} + engines: {node: '>=20.0.0'} '@aws-sdk/types@3.969.0': resolution: {integrity: sha512-7IIzM5TdiXn+VtgPdVLjmE6uUBUtnga0f4RiSEI1WW10RPuNvZ9U+pL3SwDiRDAdoGrOF9tSLJOFZmfuwYuVYQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-endpoints@3.936.0': - resolution: {integrity: sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w==} - engines: {node: '>=18.0.0'} + '@aws-sdk/types@3.973.1': + resolution: {integrity: sha512-DwHBiMNOB468JiX6+i34c+THsKHErYUdNQ3HexeXZvVn4zouLjgaS4FejiGSi2HyBuzuyHg7SuOPmjSvoU9NRg==} + engines: {node: '>=20.0.0'} '@aws-sdk/util-endpoints@3.970.0': resolution: {integrity: sha512-TZNZqFcMUtjvhZoZRtpEGQAdULYiy6rcGiXAbLU7e9LSpIYlRqpLa207oMNfgbzlL2PnHko+eVg8rajDiSOYCg==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-format-url@3.936.0': - resolution: {integrity: sha512-MS5eSEtDUFIAMHrJaMERiHAvDPdfxc/T869ZjDNFAIiZhyc037REw0aoTNeimNXDNy2txRNZJaAUn/kE4RwN+g==} - engines: {node: '>=18.0.0'} + '@aws-sdk/util-endpoints@3.988.0': + resolution: {integrity: sha512-HuXu4boeUWU0DQiLslbgdvuQ4ZMCo4Lsk97w8BIUokql2o9MvjE5dwqI5pzGt0K7afO1FybjidUQVTMLuZNTOA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-format-url@3.972.3': + resolution: {integrity: sha512-n7F2ycckcKFXa01vAsT/SJdjFHfKH9s96QHcs5gn8AaaigASICeME8WdUL9uBp8XV/OVwEt8+6gzn6KFUgQa8g==} + engines: {node: '>=20.0.0'} '@aws-sdk/util-locate-window@3.965.2': resolution: {integrity: sha512-qKgO7wAYsXzhwCHhdbaKFyxd83Fgs8/1Ka+jjSPrv2Ll7mB55Wbwlo0kkfMLh993/yEc8aoDIAc1Fz9h4Spi4Q==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-user-agent-browser@3.936.0': - resolution: {integrity: sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw==} - '@aws-sdk/util-user-agent-browser@3.969.0': resolution: {integrity: sha512-bpJGjuKmFr0rA6UKUCmN8D19HQFMLXMx5hKBXqBlPFdalMhxJSjcxzX9DbQh0Fn6bJtxCguFmRGOBdQqNOt49g==} - '@aws-sdk/util-user-agent-node@3.947.0': - resolution: {integrity: sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - aws-crt: '>=1.0.0' - peerDependenciesMeta: - aws-crt: - optional: true + '@aws-sdk/util-user-agent-browser@3.972.3': + resolution: {integrity: sha512-JurOwkRUcXD/5MTDBcqdyQ9eVedtAsZgw5rBwktsPTN7QtPiS2Ld1jkJepNgYoCufz1Wcut9iup7GJDoIHp8Fw==} '@aws-sdk/util-user-agent-node@3.971.0': resolution: {integrity: sha512-Eygjo9mFzQYjbGY3MYO6CsIhnTwAMd3WmuFalCykqEmj2r5zf0leWrhPaqvA5P68V5JdGfPYgj7vhNOd6CtRBQ==} @@ -670,14 +666,23 @@ packages: aws-crt: optional: true - '@aws-sdk/xml-builder@3.930.0': - resolution: {integrity: sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA==} - engines: {node: '>=18.0.0'} + '@aws-sdk/util-user-agent-node@3.972.6': + resolution: {integrity: sha512-966xH8TPqkqOXP7EwnEThcKKz0SNP9kVJBKd9M8bNXE4GSqVouMKKnFBwYnzbWVKuLXubzX5seokcX4a0JLJIA==} + engines: {node: '>=20.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true '@aws-sdk/xml-builder@3.969.0': resolution: {integrity: sha512-BSe4Lx/qdRQQdX8cSSI7Et20vqBspzAjBy8ZmXVoyLkol3y4sXBXzn+BiLtR+oh60ExQn6o2DU4QjdOZbXaKIQ==} engines: {node: '>=20.0.0'} + '@aws-sdk/xml-builder@3.972.4': + resolution: {integrity: sha512-0zJ05ANfYqI6+rGqj8samZBFod0dPPousBjLEqg8WdxSgbMAkRgLyn81lP215Do0rFJ/17LIXwr7q0yK24mP6Q==} + engines: {node: '>=20.0.0'} + '@aws/lambda-invoke-store@0.2.3': resolution: {integrity: sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==} engines: {node: '>=18.0.0'} @@ -1487,7 +1492,7 @@ packages: resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} engines: {node: '>=18.14.1'} peerDependencies: - hono: ^4 + hono: 4.11.7 '@hookform/resolvers@5.2.2': resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} @@ -1814,18 +1819,14 @@ packages: resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + '@isaacs/brace-expansion@5.0.1': + resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} engines: {node: 20 || >=22} '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} - '@isaacs/fs-minipass@4.0.1': - resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} - engines: {node: '>=18.0.0'} - '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1886,8 +1887,8 @@ packages: zod-to-json-schema: optional: true - '@langchain/mcp-adapters@1.0.3': - resolution: {integrity: sha512-tQacqDcqikrli/gH7CGAOUfNJ0pFOwtoKPWq2mRP7BTApOPWyfZ8Okw5nSwPDZ7Eau/QyLAH7DaWfNHmwzXPGw==} + '@langchain/mcp-adapters@1.1.3': + resolution: {integrity: sha512-OPHIQNkTUJjnRj1pr+cp2nguMBZeF3Q1pVT1hCbgU7BrHgV7lov99wbU8po8Cm4zZzmeRtVO/T9X1SrDD1ogtQ==} engines: {node: '>=20.10.0'} peerDependencies: '@langchain/core': ^1.0.0 @@ -1902,8 +1903,8 @@ packages: '@mermaid-js/parser@0.6.3': resolution: {integrity: sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==} - '@modelcontextprotocol/sdk@1.25.2': - resolution: {integrity: sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==} + '@modelcontextprotocol/sdk@1.26.0': + resolution: {integrity: sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -4060,6 +4061,10 @@ packages: resolution: {integrity: sha512-aO7jmh3CtrmPsIJxUwYIzI5WVlMK8BMCPQ4D4nTzqTqBhbzvxHNzBMGcEg13yg/z9R2Qsz49NUFl0F0lVbTVFw==} engines: {node: '>=18.0.0'} + '@smithy/core@3.23.0': + resolution: {integrity: sha512-Yq4UPVoQICM9zHnByLmG8632t2M0+yap4T7ANVw482J0W7HW0pOuxwVmeOwzJqX2Q89fkXz0Vybz55Wj2Xzrsg==} + engines: {node: '>=18.0.0'} + '@smithy/credential-provider-imds@4.2.8': resolution: {integrity: sha512-FNT0xHS1c/CPN8upqbMFP83+ul5YgdisfCfkZ86Jh2NSmnqw/AJ6x5pEogVCTVvSm7j9MopRU89bmDelxuDMYw==} engines: {node: '>=18.0.0'} @@ -4108,6 +4113,10 @@ packages: resolution: {integrity: sha512-RO0jeoaYAB1qBRhfVyq0pMgBoUK34YEJxVxyjOWYZiOKOq2yMZ4MnVXMZCUDenpozHue207+9P5ilTV1zeda0A==} engines: {node: '>=18.0.0'} + '@smithy/middleware-endpoint@4.4.14': + resolution: {integrity: sha512-FUFNE5KVeaY6U/GL0nzAAHkaCHzXLZcY1EhtQnsAqhD8Du13oPKtMB9/0WK4/LK6a/T5OZ24wPoSShff5iI6Ag==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-endpoint@4.4.8': resolution: {integrity: sha512-TV44qwB/T0OMMzjIuI+JeS0ort3bvlPJ8XIH0MSlGADraXpZqmyND27ueuAL3E14optleADWqtd7dUgc2w+qhQ==} engines: {node: '>=18.0.0'} @@ -4116,6 +4125,10 @@ packages: resolution: {integrity: sha512-yiUY1UvnbUFfP5izoKLtfxDSTRv724YRRwyiC/5HYY6vdsVDcDOXKSXmkJl/Hovcxt5r+8tZEUAdrOaCJwrl9Q==} engines: {node: '>=18.0.0'} + '@smithy/middleware-retry@4.4.31': + resolution: {integrity: sha512-RXBzLpMkIrxBPe4C8OmEOHvS8aH9RUuCOH++Acb5jZDEblxDjyg6un72X9IcbrGTJoiUwmI7hLypNfuDACypbg==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-serde@4.2.9': resolution: {integrity: sha512-eMNiej0u/snzDvlqRGSN3Vl0ESn3838+nKyVfF2FKNXFbi4SERYT6PR392D39iczngbqqGG0Jl1DlCnp7tBbXQ==} engines: {node: '>=18.0.0'} @@ -4128,6 +4141,10 @@ packages: resolution: {integrity: sha512-aFP1ai4lrbVlWjfpAfRSL8KFcnJQYfTl5QxLJXY32vghJrDuFyPZ6LtUL+JEGYiFRG1PfPLHLoxj107ulncLIg==} engines: {node: '>=18.0.0'} + '@smithy/node-http-handler@4.4.10': + resolution: {integrity: sha512-u4YeUwOWRZaHbWaebvrs3UhwQwj+2VNmcVCwXcYTvPIuVyM7Ex1ftAj+fdbG/P4AkBwLq/+SKn+ydOI4ZJE9PA==} + engines: {node: '>=18.0.0'} + '@smithy/node-http-handler@4.4.8': resolution: {integrity: sha512-q9u+MSbJVIJ1QmJ4+1u+cERXkrhuILCBDsJUBAW1MPE6sFonbCNaegFuwW9ll8kh5UdyY3jOkoOGlc7BesoLpg==} engines: {node: '>=18.0.0'} @@ -4164,6 +4181,10 @@ packages: resolution: {integrity: sha512-Je0EvGXVJ0Vrrr2lsubq43JGRIluJ/hX17aN/W/A0WfE+JpoMdI8kwk2t9F0zTX9232sJDGcoH4zZre6m6f/sg==} engines: {node: '>=18.0.0'} + '@smithy/smithy-client@4.11.3': + resolution: {integrity: sha512-Q7kY5sDau8OoE6Y9zJoRGgje8P4/UY0WzH8R2ok0PDh+iJ+ZnEKowhjEqYafVcubkbYxQVaqwm3iufktzhprGg==} + engines: {node: '>=18.0.0'} + '@smithy/types@4.12.0': resolution: {integrity: sha512-9YcuJVTOBDjg9LWo23Qp0lTQ3D7fQsQtwle0jVfpbUHy9qBwCEgKuVH4FqFB3VYu0nwdHKiEMA+oXz7oV8X1kw==} engines: {node: '>=18.0.0'} @@ -4200,10 +4221,18 @@ packages: resolution: {integrity: sha512-mMg+r/qDfjfF/0psMbV4zd7F/i+rpyp7Hjh0Wry7eY15UnzTEId+xmQTGDU8IdZtDfbGQxuWNfgBZKBj+WuYbA==} engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-browser@4.3.30': + resolution: {integrity: sha512-cMni0uVU27zxOiU8TuC8pQLC1pYeZ/xEMxvchSK/ILwleRd1ugobOcIRr5vXtcRqKd4aBLWlpeBoDPJJ91LQng==} + engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-node@4.2.26': resolution: {integrity: sha512-EQqe/WkbCinah0h1lMWh9ICl0Ob4lyl20/10WTB35SC9vDQfD8zWsOT+x2FIOXKAoZQ8z/y0EFMoodbcqWJY/w==} engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-node@4.2.33': + resolution: {integrity: sha512-LEb2aq5F4oZUSzWBG7S53d4UytZSkOEJPXcBq/xbG2/TmK9EW5naUZ8lKu1BEyWMzdHIzEVN16M3k8oxDq+DJA==} + engines: {node: '>=18.0.0'} + '@smithy/util-endpoints@3.2.8': resolution: {integrity: sha512-8JaVTn3pBDkhZgHQ8R0epwWt+BqPSLCjdjXXusK1onwJlRuN69fbvSK66aIKKO7SwVFM6x2J2ox5X8pOaWcUEw==} engines: {node: '>=18.0.0'} @@ -4224,6 +4253,10 @@ packages: resolution: {integrity: sha512-jbqemy51UFSZSp2y0ZmRfckmrzuKww95zT9BYMmuJ8v3altGcqjwoV1tzpOwuHaKrwQrCjIzOib499ymr2f98g==} engines: {node: '>=18.0.0'} + '@smithy/util-stream@4.5.12': + resolution: {integrity: sha512-D8tgkrmhAX/UNeCZbqbEO3uqyghUnEmmoO9YEvRuwxjlkKKUE7FOgCJnqpTlQPe9MApdWPky58mNQQHbnCzoNg==} + engines: {node: '>=18.0.0'} + '@smithy/util-uri-escape@4.2.0': resolution: {integrity: sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==} engines: {node: '>=18.0.0'} @@ -4252,65 +4285,65 @@ packages: '@swc/helpers@0.5.18': resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} - '@tailwindcss/node@4.1.13': - resolution: {integrity: sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==} + '@tailwindcss/node@4.1.18': + resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} - '@tailwindcss/oxide-android-arm64@4.1.13': - resolution: {integrity: sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==} + '@tailwindcss/oxide-android-arm64@4.1.18': + resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.13': - resolution: {integrity: sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==} + '@tailwindcss/oxide-darwin-arm64@4.1.18': + resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.13': - resolution: {integrity: sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==} + '@tailwindcss/oxide-darwin-x64@4.1.18': + resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.13': - resolution: {integrity: sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==} + '@tailwindcss/oxide-freebsd-x64@4.1.18': + resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13': - resolution: {integrity: sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.13': - resolution: {integrity: sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==} + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.1.13': - resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==} + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.1.13': - resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==} + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.1.13': - resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==} + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-wasm32-wasi@4.1.13': - resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==} + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -4321,24 +4354,24 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.13': - resolution: {integrity: sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==} + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.13': - resolution: {integrity: sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==} + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.13': - resolution: {integrity: sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==} + '@tailwindcss/oxide@4.1.18': + resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} engines: {node: '>= 10'} - '@tailwindcss/postcss@4.1.13': - resolution: {integrity: sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==} + '@tailwindcss/postcss@4.1.18': + resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==} '@tailwindcss/typography@0.5.16': resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==} @@ -4553,6 +4586,9 @@ packages: '@types/uuid@10.0.0': resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + '@types/validate-npm-package-name@4.0.2': + resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==} + '@typescript-eslint/eslint-plugin@8.53.0': resolution: {integrity: sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4987,6 +5023,10 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -5049,10 +5089,6 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} - chownr@3.0.0: - resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} - engines: {node: '>=18'} - chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} @@ -5453,10 +5489,22 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -5834,8 +5882,8 @@ packages: resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} engines: {node: ^18.19.0 || >=20.5.0} - express-rate-limit@7.5.1: - resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + express-rate-limit@8.2.1: + resolution: {integrity: sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==} engines: {node: '>= 16'} peerDependencies: express: '>= 4.11' @@ -5877,8 +5925,8 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fast-xml-parser@5.2.5: - resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==} + fast-xml-parser@5.3.4: + resolution: {integrity: sha512-EFd6afGmXlCx8H8WTZHhAoDaWaGyuIBoZJ2mknrNxug+aZKjkp0a0dlars9Izl+jF+7Gu1/5f/2h68cQpe0IiA==} hasBin: true fastq@1.20.1: @@ -6179,8 +6227,8 @@ packages: hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - hono@4.11.4: - resolution: {integrity: sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==} + hono@4.11.7: + resolution: {integrity: sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==} engines: {node: '>=16.9.0'} html-entities@2.6.0: @@ -6274,6 +6322,10 @@ packages: intl-messageformat@10.7.16: resolution: {integrity: sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug==} + ip-address@10.0.1: + resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} + engines: {node: '>= 12'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -6332,6 +6384,11 @@ packages: is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -6363,6 +6420,15 @@ packages: is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + is-interactive@2.0.0: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} engines: {node: '>=12'} @@ -6464,6 +6530,10 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} + is-wsl@3.1.0: + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + engines: {node: '>=16'} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -6613,68 +6683,74 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-darwin-arm64@1.30.1: - resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.30.1: - resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.30.1: - resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.30.1: - resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.30.1: - resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-arm64-musl@1.30.1: - resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-x64-gnu@1.30.1: - resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-linux-x64-musl@1.30.1: - resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-win32-arm64-msvc@1.30.1: - resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.30.1: - resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.30.1: - resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} lilconfig@3.1.3: @@ -6701,11 +6777,8 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - - lodash-es@4.17.22: - resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==} + lodash-es@4.17.23: + resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} lodash.castarray@4.4.0: resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} @@ -6716,8 +6789,8 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash@4.17.23: + resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} log-symbols@6.0.0: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} @@ -7006,10 +7079,6 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - minizlib@3.1.0: - resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} - engines: {node: '>= 18'} - mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} @@ -7217,6 +7286,10 @@ packages: oniguruma-to-es@4.3.4: resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} + open@11.0.0: + resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} + engines: {node: '>=20'} + openai@6.16.0: resolution: {integrity: sha512-fZ1uBqjFUjXzbGc35fFtYKEOxd20kd9fDpFeqWtsOZWiubY8CZ1NAlXHW3iathaFvqmNtCWMIsosCuyeI7Joxg==} hasBin: true @@ -7396,6 +7469,10 @@ packages: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} engines: {node: '>=4'} + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} @@ -7427,6 +7504,10 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} + powershell-utils@0.1.0: + resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} + engines: {node: '>=20'} + preact-render-to-string@6.5.11: resolution: {integrity: sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==} peerDependencies: @@ -7801,6 +7882,10 @@ packages: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -7876,8 +7961,8 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shadcn@3.4.1: - resolution: {integrity: sha512-gKLLCGN0lZ9vjbndoGY2cZJKvDtUYGRyF0XoyejHBbCr9lwE6NGlrtRQbA50Wcd/pDdYFyOzT/1wl//HUjSSkw==} + shadcn@3.8.4: + resolution: {integrity: sha512-pSad/m1+PGzB0aLsRBV0EkyGg9al1nJqYUuucg6d8v8xZspPZ5/ehGNEp5M4b1KQYqdO5/gGPbkhVbgmXqG9Pw==} hasBin: true sharp@0.33.5: @@ -8131,17 +8216,13 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || insiders' - tailwindcss@4.1.13: - resolution: {integrity: sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==} + tailwindcss@4.1.18: + resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} - tar@7.5.3: - resolution: {integrity: sha512-ENg5JUHUm2rDD7IvKNFGzyElLXNjachNLp6RaGf4+JOgxXHkqA+gq81ZAMCUmtMtqBsoU62lcp6S27g1LCYGGQ==} - engines: {node: '>=18'} - terser-webpack-plugin@5.3.16: resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==} engines: {node: '>= 10.13.0'} @@ -8423,6 +8504,10 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true + validate-npm-package-name@7.0.2: + resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==} + engines: {node: ^20.17.0 || >=22.9.0} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -8551,6 +8636,10 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + wsl-utils@0.3.1: + resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} + engines: {node: '>=20'} + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -8562,10 +8651,6 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yallist@5.0.0: - resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} - engines: {node: '>=18'} - yaml@2.8.2: resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} @@ -8694,7 +8779,7 @@ snapshots: '@aws-crypto/crc32@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.973.1 tslib: 2.8.1 '@aws-crypto/sha256-browser@5.2.0': @@ -8702,7 +8787,7 @@ snapshots: '@aws-crypto/sha256-js': 5.2.0 '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.973.1 '@aws-sdk/util-locate-window': 3.965.2 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -8710,7 +8795,7 @@ snapshots: '@aws-crypto/sha256-js@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.973.1 tslib: 2.8.1 '@aws-crypto/supports-web-crypto@5.2.0': @@ -8719,7 +8804,7 @@ snapshots: '@aws-crypto/util@5.2.0': dependencies: - '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.973.1 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -8770,27 +8855,27 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-bedrock-runtime@3.948.0': + '@aws-sdk/client-bedrock-runtime@3.988.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.947.0 - '@aws-sdk/credential-provider-node': 3.948.0 - '@aws-sdk/eventstream-handler-node': 3.936.0 - '@aws-sdk/middleware-eventstream': 3.936.0 - '@aws-sdk/middleware-host-header': 3.936.0 - '@aws-sdk/middleware-logger': 3.936.0 - '@aws-sdk/middleware-recursion-detection': 3.948.0 - '@aws-sdk/middleware-user-agent': 3.947.0 - '@aws-sdk/middleware-websocket': 3.936.0 - '@aws-sdk/region-config-resolver': 3.936.0 - '@aws-sdk/token-providers': 3.948.0 - '@aws-sdk/types': 3.936.0 - '@aws-sdk/util-endpoints': 3.936.0 - '@aws-sdk/util-user-agent-browser': 3.936.0 - '@aws-sdk/util-user-agent-node': 3.947.0 + '@aws-sdk/core': 3.973.8 + '@aws-sdk/credential-provider-node': 3.972.7 + '@aws-sdk/eventstream-handler-node': 3.972.5 + '@aws-sdk/middleware-eventstream': 3.972.3 + '@aws-sdk/middleware-host-header': 3.972.3 + '@aws-sdk/middleware-logger': 3.972.3 + '@aws-sdk/middleware-recursion-detection': 3.972.3 + '@aws-sdk/middleware-user-agent': 3.972.8 + '@aws-sdk/middleware-websocket': 3.972.6 + '@aws-sdk/region-config-resolver': 3.972.3 + '@aws-sdk/token-providers': 3.988.0 + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-endpoints': 3.988.0 + '@aws-sdk/util-user-agent-browser': 3.972.3 + '@aws-sdk/util-user-agent-node': 3.972.6 '@smithy/config-resolver': 4.4.6 - '@smithy/core': 3.20.7 + '@smithy/core': 3.23.0 '@smithy/eventstream-serde-browser': 4.2.8 '@smithy/eventstream-serde-config-resolver': 4.3.8 '@smithy/eventstream-serde-node': 4.2.8 @@ -8798,25 +8883,25 @@ snapshots: '@smithy/hash-node': 4.2.8 '@smithy/invalid-dependency': 4.2.8 '@smithy/middleware-content-length': 4.2.8 - '@smithy/middleware-endpoint': 4.4.8 - '@smithy/middleware-retry': 4.4.24 + '@smithy/middleware-endpoint': 4.4.14 + '@smithy/middleware-retry': 4.4.31 '@smithy/middleware-serde': 4.2.9 '@smithy/middleware-stack': 4.2.8 '@smithy/node-config-provider': 4.3.8 - '@smithy/node-http-handler': 4.4.8 + '@smithy/node-http-handler': 4.4.10 '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.10.9 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 '@smithy/url-parser': 4.2.8 '@smithy/util-base64': 4.3.0 '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-body-length-node': 4.2.1 - '@smithy/util-defaults-mode-browser': 4.3.23 - '@smithy/util-defaults-mode-node': 4.2.26 + '@smithy/util-defaults-mode-browser': 4.3.30 + '@smithy/util-defaults-mode-node': 4.2.33 '@smithy/util-endpoints': 3.2.8 '@smithy/util-middleware': 4.2.8 '@smithy/util-retry': 4.2.8 - '@smithy/util-stream': 4.5.10 + '@smithy/util-stream': 4.5.12 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 transitivePeerDependencies: @@ -8866,49 +8951,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso@3.948.0': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.947.0 - '@aws-sdk/middleware-host-header': 3.936.0 - '@aws-sdk/middleware-logger': 3.936.0 - '@aws-sdk/middleware-recursion-detection': 3.948.0 - '@aws-sdk/middleware-user-agent': 3.947.0 - '@aws-sdk/region-config-resolver': 3.936.0 - '@aws-sdk/types': 3.936.0 - '@aws-sdk/util-endpoints': 3.936.0 - '@aws-sdk/util-user-agent-browser': 3.936.0 - '@aws-sdk/util-user-agent-node': 3.947.0 - '@smithy/config-resolver': 4.4.6 - '@smithy/core': 3.20.7 - '@smithy/fetch-http-handler': 5.3.9 - '@smithy/hash-node': 4.2.8 - '@smithy/invalid-dependency': 4.2.8 - '@smithy/middleware-content-length': 4.2.8 - '@smithy/middleware-endpoint': 4.4.8 - '@smithy/middleware-retry': 4.4.24 - '@smithy/middleware-serde': 4.2.9 - '@smithy/middleware-stack': 4.2.8 - '@smithy/node-config-provider': 4.3.8 - '@smithy/node-http-handler': 4.4.8 - '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.10.9 - '@smithy/types': 4.12.0 - '@smithy/url-parser': 4.2.8 - '@smithy/util-base64': 4.3.0 - '@smithy/util-body-length-browser': 4.2.0 - '@smithy/util-body-length-node': 4.2.1 - '@smithy/util-defaults-mode-browser': 4.3.23 - '@smithy/util-defaults-mode-node': 4.2.26 - '@smithy/util-endpoints': 3.2.8 - '@smithy/util-middleware': 4.2.8 - '@smithy/util-retry': 4.2.8 - '@smithy/util-utf8': 4.2.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/client-sso@3.971.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -8952,21 +8994,48 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/core@3.947.0': + '@aws-sdk/client-sso@3.988.0': dependencies: - '@aws-sdk/types': 3.936.0 - '@aws-sdk/xml-builder': 3.930.0 - '@smithy/core': 3.20.7 + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.8 + '@aws-sdk/middleware-host-header': 3.972.3 + '@aws-sdk/middleware-logger': 3.972.3 + '@aws-sdk/middleware-recursion-detection': 3.972.3 + '@aws-sdk/middleware-user-agent': 3.972.8 + '@aws-sdk/region-config-resolver': 3.972.3 + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-endpoints': 3.988.0 + '@aws-sdk/util-user-agent-browser': 3.972.3 + '@aws-sdk/util-user-agent-node': 3.972.6 + '@smithy/config-resolver': 4.4.6 + '@smithy/core': 3.23.0 + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/hash-node': 4.2.8 + '@smithy/invalid-dependency': 4.2.8 + '@smithy/middleware-content-length': 4.2.8 + '@smithy/middleware-endpoint': 4.4.14 + '@smithy/middleware-retry': 4.4.31 + '@smithy/middleware-serde': 4.2.9 + '@smithy/middleware-stack': 4.2.8 '@smithy/node-config-provider': 4.3.8 - '@smithy/property-provider': 4.2.8 + '@smithy/node-http-handler': 4.4.10 '@smithy/protocol-http': 5.3.8 - '@smithy/signature-v4': 5.3.8 - '@smithy/smithy-client': 4.10.9 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.30 + '@smithy/util-defaults-mode-node': 4.2.33 + '@smithy/util-endpoints': 3.2.8 '@smithy/util-middleware': 4.2.8 + '@smithy/util-retry': 4.2.8 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt '@aws-sdk/core@3.970.0': dependencies: @@ -8984,12 +9053,20 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.947.0': + '@aws-sdk/core@3.973.8': dependencies: - '@aws-sdk/core': 3.947.0 - '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.973.1 + '@aws-sdk/xml-builder': 3.972.4 + '@smithy/core': 3.23.0 + '@smithy/node-config-provider': 4.3.8 '@smithy/property-provider': 4.2.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/signature-v4': 5.3.8 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 + '@smithy/util-base64': 4.3.0 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 '@aws-sdk/credential-provider-env@3.970.0': @@ -9000,17 +9077,12 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.947.0': + '@aws-sdk/credential-provider-env@3.972.6': dependencies: - '@aws-sdk/core': 3.947.0 - '@aws-sdk/types': 3.936.0 - '@smithy/fetch-http-handler': 5.3.9 - '@smithy/node-http-handler': 4.4.8 + '@aws-sdk/core': 3.973.8 + '@aws-sdk/types': 3.973.1 '@smithy/property-provider': 4.2.8 - '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.10.9 '@smithy/types': 4.12.0 - '@smithy/util-stream': 4.5.10 tslib: 2.8.1 '@aws-sdk/credential-provider-http@3.970.0': @@ -9026,24 +9098,18 @@ snapshots: '@smithy/util-stream': 4.5.10 tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.948.0': + '@aws-sdk/credential-provider-http@3.972.8': dependencies: - '@aws-sdk/core': 3.947.0 - '@aws-sdk/credential-provider-env': 3.947.0 - '@aws-sdk/credential-provider-http': 3.947.0 - '@aws-sdk/credential-provider-login': 3.948.0 - '@aws-sdk/credential-provider-process': 3.947.0 - '@aws-sdk/credential-provider-sso': 3.948.0 - '@aws-sdk/credential-provider-web-identity': 3.948.0 - '@aws-sdk/nested-clients': 3.948.0 - '@aws-sdk/types': 3.936.0 - '@smithy/credential-provider-imds': 4.2.8 + '@aws-sdk/core': 3.973.8 + '@aws-sdk/types': 3.973.1 + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/node-http-handler': 4.4.10 '@smithy/property-provider': 4.2.8 - '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/protocol-http': 5.3.8 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 + '@smithy/util-stream': 4.5.12 tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt '@aws-sdk/credential-provider-ini@3.971.0': dependencies: @@ -9064,13 +9130,19 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-login@3.948.0': + '@aws-sdk/credential-provider-ini@3.972.6': dependencies: - '@aws-sdk/core': 3.947.0 - '@aws-sdk/nested-clients': 3.948.0 - '@aws-sdk/types': 3.936.0 + '@aws-sdk/core': 3.973.8 + '@aws-sdk/credential-provider-env': 3.972.6 + '@aws-sdk/credential-provider-http': 3.972.8 + '@aws-sdk/credential-provider-login': 3.972.6 + '@aws-sdk/credential-provider-process': 3.972.6 + '@aws-sdk/credential-provider-sso': 3.972.6 + '@aws-sdk/credential-provider-web-identity': 3.972.6 + '@aws-sdk/nested-clients': 3.988.0 + '@aws-sdk/types': 3.973.1 + '@smithy/credential-provider-imds': 4.2.8 '@smithy/property-provider': 4.2.8 - '@smithy/protocol-http': 5.3.8 '@smithy/shared-ini-file-loader': 4.4.3 '@smithy/types': 4.12.0 tslib: 2.8.1 @@ -9090,17 +9162,13 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.948.0': + '@aws-sdk/credential-provider-login@3.972.6': dependencies: - '@aws-sdk/credential-provider-env': 3.947.0 - '@aws-sdk/credential-provider-http': 3.947.0 - '@aws-sdk/credential-provider-ini': 3.948.0 - '@aws-sdk/credential-provider-process': 3.947.0 - '@aws-sdk/credential-provider-sso': 3.948.0 - '@aws-sdk/credential-provider-web-identity': 3.948.0 - '@aws-sdk/types': 3.936.0 - '@smithy/credential-provider-imds': 4.2.8 + '@aws-sdk/core': 3.973.8 + '@aws-sdk/nested-clients': 3.988.0 + '@aws-sdk/types': 3.973.1 '@smithy/property-provider': 4.2.8 + '@smithy/protocol-http': 5.3.8 '@smithy/shared-ini-file-loader': 4.4.3 '@smithy/types': 4.12.0 tslib: 2.8.1 @@ -9124,14 +9192,22 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-process@3.947.0': + '@aws-sdk/credential-provider-node@3.972.7': dependencies: - '@aws-sdk/core': 3.947.0 - '@aws-sdk/types': 3.936.0 + '@aws-sdk/credential-provider-env': 3.972.6 + '@aws-sdk/credential-provider-http': 3.972.8 + '@aws-sdk/credential-provider-ini': 3.972.6 + '@aws-sdk/credential-provider-process': 3.972.6 + '@aws-sdk/credential-provider-sso': 3.972.6 + '@aws-sdk/credential-provider-web-identity': 3.972.6 + '@aws-sdk/types': 3.973.1 + '@smithy/credential-provider-imds': 4.2.8 '@smithy/property-provider': 4.2.8 '@smithy/shared-ini-file-loader': 4.4.3 '@smithy/types': 4.12.0 tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt '@aws-sdk/credential-provider-process@3.970.0': dependencies: @@ -9142,18 +9218,14 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.948.0': + '@aws-sdk/credential-provider-process@3.972.6': dependencies: - '@aws-sdk/client-sso': 3.948.0 - '@aws-sdk/core': 3.947.0 - '@aws-sdk/token-providers': 3.948.0 - '@aws-sdk/types': 3.936.0 + '@aws-sdk/core': 3.973.8 + '@aws-sdk/types': 3.973.1 '@smithy/property-provider': 4.2.8 '@smithy/shared-ini-file-loader': 4.4.3 '@smithy/types': 4.12.0 tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt '@aws-sdk/credential-provider-sso@3.971.0': dependencies: @@ -9168,11 +9240,12 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-web-identity@3.948.0': + '@aws-sdk/credential-provider-sso@3.972.6': dependencies: - '@aws-sdk/core': 3.947.0 - '@aws-sdk/nested-clients': 3.948.0 - '@aws-sdk/types': 3.936.0 + '@aws-sdk/client-sso': 3.988.0 + '@aws-sdk/core': 3.973.8 + '@aws-sdk/token-providers': 3.988.0 + '@aws-sdk/types': 3.973.1 '@smithy/property-provider': 4.2.8 '@smithy/shared-ini-file-loader': 4.4.3 '@smithy/types': 4.12.0 @@ -9192,23 +9265,28 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/eventstream-handler-node@3.936.0': + '@aws-sdk/credential-provider-web-identity@3.972.6': dependencies: - '@aws-sdk/types': 3.936.0 + '@aws-sdk/core': 3.973.8 + '@aws-sdk/nested-clients': 3.988.0 + '@aws-sdk/types': 3.973.1 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/eventstream-handler-node@3.972.5': + dependencies: + '@aws-sdk/types': 3.973.1 '@smithy/eventstream-codec': 4.2.8 '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/middleware-eventstream@3.936.0': + '@aws-sdk/middleware-eventstream@3.972.3': dependencies: - '@aws-sdk/types': 3.936.0 - '@smithy/protocol-http': 5.3.8 - '@smithy/types': 4.12.0 - tslib: 2.8.1 - - '@aws-sdk/middleware-host-header@3.936.0': - dependencies: - '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.973.1 '@smithy/protocol-http': 5.3.8 '@smithy/types': 4.12.0 tslib: 2.8.1 @@ -9220,9 +9298,10 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.936.0': + '@aws-sdk/middleware-host-header@3.972.3': dependencies: - '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.973.1 + '@smithy/protocol-http': 5.3.8 '@smithy/types': 4.12.0 tslib: 2.8.1 @@ -9232,11 +9311,9 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.948.0': + '@aws-sdk/middleware-logger@3.972.3': dependencies: - '@aws-sdk/types': 3.936.0 - '@aws/lambda-invoke-store': 0.2.3 - '@smithy/protocol-http': 5.3.8 + '@aws-sdk/types': 3.973.1 '@smithy/types': 4.12.0 tslib: 2.8.1 @@ -9248,12 +9325,10 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.947.0': + '@aws-sdk/middleware-recursion-detection@3.972.3': dependencies: - '@aws-sdk/core': 3.947.0 - '@aws-sdk/types': 3.936.0 - '@aws-sdk/util-endpoints': 3.936.0 - '@smithy/core': 3.20.7 + '@aws-sdk/types': 3.973.1 + '@aws/lambda-invoke-store': 0.2.3 '@smithy/protocol-http': 5.3.8 '@smithy/types': 4.12.0 tslib: 2.8.1 @@ -9268,61 +9343,30 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/middleware-websocket@3.936.0': + '@aws-sdk/middleware-user-agent@3.972.8': dependencies: - '@aws-sdk/types': 3.936.0 - '@aws-sdk/util-format-url': 3.936.0 + '@aws-sdk/core': 3.973.8 + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-endpoints': 3.988.0 + '@smithy/core': 3.23.0 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-websocket@3.972.6': + dependencies: + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-format-url': 3.972.3 '@smithy/eventstream-codec': 4.2.8 '@smithy/eventstream-serde-browser': 4.2.8 '@smithy/fetch-http-handler': 5.3.9 '@smithy/protocol-http': 5.3.8 '@smithy/signature-v4': 5.3.8 '@smithy/types': 4.12.0 - '@smithy/util-hex-encoding': 4.2.0 - tslib: 2.8.1 - - '@aws-sdk/nested-clients@3.948.0': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.947.0 - '@aws-sdk/middleware-host-header': 3.936.0 - '@aws-sdk/middleware-logger': 3.936.0 - '@aws-sdk/middleware-recursion-detection': 3.948.0 - '@aws-sdk/middleware-user-agent': 3.947.0 - '@aws-sdk/region-config-resolver': 3.936.0 - '@aws-sdk/types': 3.936.0 - '@aws-sdk/util-endpoints': 3.936.0 - '@aws-sdk/util-user-agent-browser': 3.936.0 - '@aws-sdk/util-user-agent-node': 3.947.0 - '@smithy/config-resolver': 4.4.6 - '@smithy/core': 3.20.7 - '@smithy/fetch-http-handler': 5.3.9 - '@smithy/hash-node': 4.2.8 - '@smithy/invalid-dependency': 4.2.8 - '@smithy/middleware-content-length': 4.2.8 - '@smithy/middleware-endpoint': 4.4.8 - '@smithy/middleware-retry': 4.4.24 - '@smithy/middleware-serde': 4.2.9 - '@smithy/middleware-stack': 4.2.8 - '@smithy/node-config-provider': 4.3.8 - '@smithy/node-http-handler': 4.4.8 - '@smithy/protocol-http': 5.3.8 - '@smithy/smithy-client': 4.10.9 - '@smithy/types': 4.12.0 - '@smithy/url-parser': 4.2.8 '@smithy/util-base64': 4.3.0 - '@smithy/util-body-length-browser': 4.2.0 - '@smithy/util-body-length-node': 4.2.1 - '@smithy/util-defaults-mode-browser': 4.3.23 - '@smithy/util-defaults-mode-node': 4.2.26 - '@smithy/util-endpoints': 3.2.8 - '@smithy/util-middleware': 4.2.8 - '@smithy/util-retry': 4.2.8 + '@smithy/util-hex-encoding': 4.2.0 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt '@aws-sdk/nested-clients@3.971.0': dependencies: @@ -9367,13 +9411,48 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/region-config-resolver@3.936.0': + '@aws-sdk/nested-clients@3.988.0': dependencies: - '@aws-sdk/types': 3.936.0 + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.8 + '@aws-sdk/middleware-host-header': 3.972.3 + '@aws-sdk/middleware-logger': 3.972.3 + '@aws-sdk/middleware-recursion-detection': 3.972.3 + '@aws-sdk/middleware-user-agent': 3.972.8 + '@aws-sdk/region-config-resolver': 3.972.3 + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-endpoints': 3.988.0 + '@aws-sdk/util-user-agent-browser': 3.972.3 + '@aws-sdk/util-user-agent-node': 3.972.6 '@smithy/config-resolver': 4.4.6 + '@smithy/core': 3.23.0 + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/hash-node': 4.2.8 + '@smithy/invalid-dependency': 4.2.8 + '@smithy/middleware-content-length': 4.2.8 + '@smithy/middleware-endpoint': 4.4.14 + '@smithy/middleware-retry': 4.4.31 + '@smithy/middleware-serde': 4.2.9 + '@smithy/middleware-stack': 4.2.8 '@smithy/node-config-provider': 4.3.8 + '@smithy/node-http-handler': 4.4.10 + '@smithy/protocol-http': 5.3.8 + '@smithy/smithy-client': 4.11.3 '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.30 + '@smithy/util-defaults-mode-node': 4.2.33 + '@smithy/util-endpoints': 3.2.8 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-retry': 4.2.8 + '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt '@aws-sdk/region-config-resolver@3.969.0': dependencies: @@ -9383,17 +9462,13 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/token-providers@3.948.0': + '@aws-sdk/region-config-resolver@3.972.3': dependencies: - '@aws-sdk/core': 3.947.0 - '@aws-sdk/nested-clients': 3.948.0 - '@aws-sdk/types': 3.936.0 - '@smithy/property-provider': 4.2.8 - '@smithy/shared-ini-file-loader': 4.4.3 + '@aws-sdk/types': 3.973.1 + '@smithy/config-resolver': 4.4.6 + '@smithy/node-config-provider': 4.3.8 '@smithy/types': 4.12.0 tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt '@aws-sdk/token-providers@3.971.0': dependencies: @@ -9407,22 +9482,26 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/types@3.936.0': + '@aws-sdk/token-providers@3.988.0': dependencies: + '@aws-sdk/core': 3.973.8 + '@aws-sdk/nested-clients': 3.988.0 + '@aws-sdk/types': 3.973.1 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 '@smithy/types': 4.12.0 tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt '@aws-sdk/types@3.969.0': dependencies: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.936.0': + '@aws-sdk/types@3.973.1': dependencies: - '@aws-sdk/types': 3.936.0 '@smithy/types': 4.12.0 - '@smithy/url-parser': 4.2.8 - '@smithy/util-endpoints': 3.2.8 tslib: 2.8.1 '@aws-sdk/util-endpoints@3.970.0': @@ -9433,9 +9512,17 @@ snapshots: '@smithy/util-endpoints': 3.2.8 tslib: 2.8.1 - '@aws-sdk/util-format-url@3.936.0': + '@aws-sdk/util-endpoints@3.988.0': dependencies: - '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.973.1 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-endpoints': 3.2.8 + tslib: 2.8.1 + + '@aws-sdk/util-format-url@3.972.3': + dependencies: + '@aws-sdk/types': 3.973.1 '@smithy/querystring-builder': 4.2.8 '@smithy/types': 4.12.0 tslib: 2.8.1 @@ -9444,13 +9531,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.936.0': - dependencies: - '@aws-sdk/types': 3.936.0 - '@smithy/types': 4.12.0 - bowser: 2.13.1 - tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.969.0': dependencies: '@aws-sdk/types': 3.969.0 @@ -9458,12 +9538,11 @@ snapshots: bowser: 2.13.1 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.947.0': + '@aws-sdk/util-user-agent-browser@3.972.3': dependencies: - '@aws-sdk/middleware-user-agent': 3.947.0 - '@aws-sdk/types': 3.936.0 - '@smithy/node-config-provider': 4.3.8 + '@aws-sdk/types': 3.973.1 '@smithy/types': 4.12.0 + bowser: 2.13.1 tslib: 2.8.1 '@aws-sdk/util-user-agent-node@3.971.0': @@ -9474,16 +9553,24 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/xml-builder@3.930.0': + '@aws-sdk/util-user-agent-node@3.972.6': dependencies: + '@aws-sdk/middleware-user-agent': 3.972.8 + '@aws-sdk/types': 3.973.1 + '@smithy/node-config-provider': 4.3.8 '@smithy/types': 4.12.0 - fast-xml-parser: 5.2.5 tslib: 2.8.1 '@aws-sdk/xml-builder@3.969.0': dependencies: '@smithy/types': 4.12.0 - fast-xml-parser: 5.2.5 + fast-xml-parser: 5.3.4 + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.4': + dependencies: + '@smithy/types': 4.12.0 + fast-xml-parser: 5.3.4 tslib: 2.8.1 '@aws/lambda-invoke-store@0.2.3': {} @@ -9684,12 +9771,12 @@ snapshots: dependencies: '@chevrotain/gast': 11.0.3 '@chevrotain/types': 11.0.3 - lodash-es: 4.17.21 + lodash-es: 4.17.23 '@chevrotain/gast@11.0.3': dependencies: '@chevrotain/types': 11.0.3 - lodash-es: 4.17.21 + lodash-es: 4.17.23 '@chevrotain/regexp-to-ast@11.0.3': {} @@ -9781,7 +9868,7 @@ snapshots: dependencies: '@ndaidong/bellajs': 12.0.1 cross-fetch: 4.1.0 - fast-xml-parser: 5.2.5 + fast-xml-parser: 5.3.4 html-entities: 2.6.0 transitivePeerDependencies: - encoding @@ -9829,17 +9916,17 @@ snapshots: dependencies: tslib: 2.8.1 - '@heroui/accordion@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/accordion@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/divider': 2.2.19(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/divider': 2.2.19(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/dom-animation': 2.1.10(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) - '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-aria-accordion': 2.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -9850,23 +9937,23 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/alert@2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/alert@2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@react-stately/utils': 3.10.8(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - framer-motion - '@heroui/aria-utils@2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/aria-utils@2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/utils': 3.30.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-stately/collections': 3.12.7(react@19.2.4) '@react-types/overlays': 3.9.1(react@19.2.4) @@ -9877,20 +9964,20 @@ snapshots: - '@heroui/theme' - framer-motion - '@heroui/autocomplete@2.3.28(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(@types/react@19.2.8)(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/autocomplete@2.3.28(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(@types/react@19.2.8)(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/input': 2.4.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(@types/react@19.2.8)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/listbox': 2.3.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/popover': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/input': 2.4.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(@types/react@19.2.8)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/listbox': 2.3.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/popover': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) - '@heroui/scroll-shadow': 2.3.17(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/scroll-shadow': 2.3.17(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-safe-layout-effect': 2.1.8(react@19.2.4) '@react-aria/combobox': 3.13.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/i18n': 3.12.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -9903,48 +9990,48 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@heroui/avatar@2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/avatar@2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-image': 2.1.12(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/badge@2.2.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/badge@2.2.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/breadcrumbs@2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/breadcrumbs@2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@react-aria/breadcrumbs': 3.5.28(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-types/breadcrumbs': 3.7.16(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/button@2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/button@2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) - '@heroui/ripple': 2.2.19(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/ripple': 2.2.19(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/spinner': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/spinner': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-aria-button': 2.2.19(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -9953,16 +10040,16 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/calendar@2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/calendar@2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/dom-animation': 2.1.10(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) - '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-aria-button': 2.2.19(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@internationalized/date': 3.10.0 '@react-aria/calendar': 3.9.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -9980,13 +10067,13 @@ snapshots: react-dom: 19.2.4(react@19.2.4) scroll-into-view-if-needed: 3.0.10 - '@heroui/card@2.2.24(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/card@2.2.24(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) - '@heroui/ripple': 2.2.19(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/ripple': 2.2.19(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-aria-button': 2.2.19(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -9995,13 +10082,13 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/checkbox@2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/checkbox@2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-callback-ref': 2.1.8(react@19.2.4) '@heroui/use-safe-layout-effect': 2.1.8(react@19.2.4) '@react-aria/checkbox': 3.16.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10014,34 +10101,34 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/chip@2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/chip@2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/code@2.2.20(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/code@2.2.20(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system-rsc': 2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system-rsc': 2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/date-input@2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/date-input@2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@internationalized/date': 3.10.0 '@react-aria/datepicker': 3.15.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/i18n': 3.12.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10051,19 +10138,19 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/date-picker@2.3.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/date-picker@2.3.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/calendar': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/date-input': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/popover': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/calendar': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/date-input': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/popover': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@internationalized/date': 3.10.0 '@react-aria/datepicker': 3.15.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/i18n': 3.12.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10075,11 +10162,11 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/divider@2.2.19(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/divider@2.2.19(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-rsc-utils': 2.1.9(react@19.2.4) - '@heroui/system-rsc': 2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system-rsc': 2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@react-types/shared': 3.26.0(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) @@ -10088,28 +10175,28 @@ snapshots: dependencies: framer-motion: 11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/drawer@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/drawer@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/modal': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/modal': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - framer-motion - '@heroui/dropdown@2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/dropdown@2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/menu': 2.2.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/popover': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/menu': 2.2.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/popover': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/menu': 3.19.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-stately/menu': 3.9.7(react@19.2.4) @@ -10118,20 +10205,20 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/form@2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/form@2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@react-stately/form': 3.2.1(react@19.2.4) '@react-types/form': 3.7.15(react@19.2.4) '@react-types/shared': 3.26.0(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/framer-utils@2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/framer-utils@2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/use-measure': 2.1.8(react@19.2.4) framer-motion: 11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 @@ -10139,23 +10226,23 @@ snapshots: transitivePeerDependencies: - '@heroui/theme' - '@heroui/image@2.2.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/image@2.2.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-image': 2.1.12(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/input-otp@2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/input-otp@2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-form-reset': 2.0.1(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/form': 3.1.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10166,14 +10253,14 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/input@2.4.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(@types/react@19.2.8)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/input@2.4.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(@types/react@19.2.8)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-safe-layout-effect': 2.1.8(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10187,36 +10274,36 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@heroui/kbd@2.2.21(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/kbd@2.2.21(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system-rsc': 2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system-rsc': 2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/link@2.2.22(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/link@2.2.22(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-aria-link': 2.2.20(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-types/link': 3.6.4(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/listbox@2.3.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/listbox@2.3.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/divider': 2.2.19(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/divider': 2.2.19(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-is-mobile': 2.2.12(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10229,14 +10316,14 @@ snapshots: transitivePeerDependencies: - framer-motion - '@heroui/menu@2.2.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/menu@2.2.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/divider': 2.2.19(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/divider': 2.2.19(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-is-mobile': 2.2.12(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10249,15 +10336,15 @@ snapshots: transitivePeerDependencies: - framer-motion - '@heroui/modal@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/modal@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/dom-animation': 2.1.10(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) - '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-aria-button': 2.2.19(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/use-aria-modal-overlay': 2.2.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/use-disclosure': 2.2.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10271,14 +10358,14 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/navbar@2.2.24(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/navbar@2.2.24(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/dom-animation': 2.1.10(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) - '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-resize': 2.1.8(react@19.2.4) '@heroui/use-scroll-position': 2.1.8(react@19.2.4) '@react-aria/button': 3.14.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10291,15 +10378,15 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/number-input@2.0.17(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/number-input@2.0.17(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-safe-layout-effect': 2.1.8(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/i18n': 3.12.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10314,13 +10401,13 @@ snapshots: transitivePeerDependencies: - framer-motion - '@heroui/pagination@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/pagination@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-intersection-observer': 2.2.14(react@19.2.4) '@heroui/use-pagination': 2.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10331,16 +10418,16 @@ snapshots: react-dom: 19.2.4(react@19.2.4) scroll-into-view-if-needed: 3.0.10 - '@heroui/popover@2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/popover@2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/dom-animation': 2.1.10(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) - '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-aria-button': 2.2.19(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/use-aria-overlay': 2.0.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/use-safe-layout-effect': 2.1.8(react@19.2.4) @@ -10353,25 +10440,25 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/progress@2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/progress@2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-is-mounted': 2.1.8(react@19.2.4) '@react-aria/progress': 3.4.26(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-types/progress': 3.5.15(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/radio@2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/radio@2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/radio': 3.12.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10392,57 +10479,57 @@ snapshots: '@heroui/shared-utils': 2.1.11 react: 19.2.4 - '@heroui/react@2.8.4(@types/react@19.2.8)(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.13)': + '@heroui/react@2.8.4(@types/react@19.2.8)(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)': dependencies: - '@heroui/accordion': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/alert': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/autocomplete': 2.3.28(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(@types/react@19.2.8)(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/avatar': 2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/badge': 2.2.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/breadcrumbs': 2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/calendar': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/card': 2.2.24(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/checkbox': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/chip': 2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/code': 2.2.20(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/date-input': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/date-picker': 2.3.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/divider': 2.2.19(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/drawer': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/dropdown': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/image': 2.2.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/input': 2.4.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(@types/react@19.2.8)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/input-otp': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/kbd': 2.2.21(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/link': 2.2.22(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/listbox': 2.3.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/menu': 2.2.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/modal': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/navbar': 2.2.24(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/number-input': 2.0.17(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/pagination': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/popover': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/progress': 2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/radio': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/ripple': 2.2.19(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/scroll-shadow': 2.3.17(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/select': 2.4.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/skeleton': 2.2.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/slider': 2.4.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/snippet': 2.2.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/spacer': 2.2.20(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/spinner': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/switch': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/table': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/tabs': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) - '@heroui/toast': 2.0.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/tooltip': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/user': 2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/accordion': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/alert': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/autocomplete': 2.3.28(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(@types/react@19.2.8)(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/avatar': 2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/badge': 2.2.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/breadcrumbs': 2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/calendar': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/card': 2.2.24(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/checkbox': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/chip': 2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/code': 2.2.20(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/date-input': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/date-picker': 2.3.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/divider': 2.2.19(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/drawer': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/dropdown': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/image': 2.2.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/input': 2.4.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(@types/react@19.2.8)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/input-otp': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/kbd': 2.2.21(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/link': 2.2.22(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/listbox': 2.3.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/menu': 2.2.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/modal': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/navbar': 2.2.24(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/number-input': 2.0.17(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/pagination': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/popover': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/progress': 2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/radio': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/ripple': 2.2.19(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/scroll-shadow': 2.3.17(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/select': 2.4.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/skeleton': 2.2.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/slider': 2.4.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/snippet': 2.2.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/spacer': 2.2.20(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/spinner': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/switch': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/table': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/tabs': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) + '@heroui/toast': 2.0.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/tooltip': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/user': 2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/visually-hidden': 3.8.27(react-dom@19.2.4(react@19.2.4))(react@19.2.4) framer-motion: 11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 @@ -10451,39 +10538,39 @@ snapshots: - '@types/react' - tailwindcss - '@heroui/ripple@2.2.19(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/ripple@2.2.19(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/dom-animation': 2.1.10(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) framer-motion: 11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/scroll-shadow@2.3.17(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/scroll-shadow@2.3.17(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-data-scroll-overflow': 2.2.12(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/select@2.4.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/select@2.4.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/listbox': 2.3.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/popover': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/form': 2.1.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/listbox': 2.3.25(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/popover': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) - '@heroui/scroll-shadow': 2.3.17(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/scroll-shadow': 2.3.17(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/spinner': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/spinner': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-aria-button': 2.2.19(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/use-aria-multiselect': 2.4.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/use-form-reset': 2.0.1(react@19.2.4) @@ -10504,21 +10591,21 @@ snapshots: '@heroui/shared-utils@2.1.11': {} - '@heroui/skeleton@2.2.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/skeleton@2.2.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/slider@2.4.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/slider@2.4.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) - '@heroui/tooltip': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) + '@heroui/tooltip': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/i18n': 3.12.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10530,47 +10617,47 @@ snapshots: transitivePeerDependencies: - framer-motion - '@heroui/snippet@2.2.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/snippet@2.2.27(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/button': 2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) - '@heroui/tooltip': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) + '@heroui/tooltip': 2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/use-clipboard': 2.1.9(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) framer-motion: 11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/spacer@2.2.20(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/spacer@2.2.20(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system-rsc': 2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system-rsc': 2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/spinner@2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/spinner@2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/system-rsc': 2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/system-rsc': 2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - framer-motion - '@heroui/switch@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/switch@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-safe-layout-effect': 2.1.8(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10580,17 +10667,17 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/system-rsc@2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react@19.2.4)': + '@heroui/system-rsc@2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react@19.2.4)': dependencies: - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@react-types/shared': 3.26.0(react@19.2.4) clsx: 1.2.1 react: 19.2.4 - '@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) - '@heroui/system-rsc': 2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react@19.2.4) + '@heroui/system-rsc': 2.3.19(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react@19.2.4) '@react-aria/i18n': 3.12.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/overlays': 3.29.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/utils': 3.30.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10600,15 +10687,15 @@ snapshots: transitivePeerDependencies: - '@heroui/theme' - '@heroui/table@2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/table@2.2.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/checkbox': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/checkbox': 2.3.26(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/spacer': 2.2.20(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/spacer': 2.2.20(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/table': 3.17.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10621,13 +10708,13 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/tabs@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/tabs@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-is-mounted': 2.1.8(react@19.2.4) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10639,7 +10726,7 @@ snapshots: react-dom: 19.2.4(react@19.2.4) scroll-into-view-if-needed: 3.0.10 - '@heroui/theme@2.4.22(tailwindcss@4.1.13)': + '@heroui/theme@2.4.22(tailwindcss@4.1.18)': dependencies: '@heroui/shared-utils': 2.1.11 clsx: 1.2.1 @@ -10648,17 +10735,17 @@ snapshots: deepmerge: 4.3.1 flat: 5.0.2 tailwind-merge: 3.3.1 - tailwind-variants: 3.1.1(tailwind-merge@3.3.1)(tailwindcss@4.1.13) - tailwindcss: 4.1.13 + tailwind-variants: 3.1.1(tailwind-merge@3.3.1)(tailwindcss@4.1.18) + tailwindcss: 4.1.18 - '@heroui/toast@2.0.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/toast@2.0.16(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-icons': 2.1.10(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/spinner': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/spinner': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-is-mobile': 2.2.12(react@19.2.4) '@react-aria/interactions': 3.25.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/toast': 3.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10667,15 +10754,15 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@heroui/tooltip@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/tooltip@2.2.23(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/aria-utils': 2.2.23(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/dom-animation': 2.1.10(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) - '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/framer-utils': 2.1.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@heroui/use-aria-overlay': 2.0.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/use-safe-layout-effect': 2.1.8(react@19.2.4) '@react-aria/overlays': 3.29.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -10838,20 +10925,20 @@ snapshots: dependencies: react: 19.2.4 - '@heroui/user@2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@heroui/user@2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@heroui/avatar': 2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.13))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/avatar': 2.2.21(@heroui/system@2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@heroui/theme@2.4.22(tailwindcss@4.1.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroui/react-utils': 2.1.13(react@19.2.4) '@heroui/shared-utils': 2.1.11 - '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.13))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@heroui/theme': 2.4.22(tailwindcss@4.1.13) + '@heroui/system': 2.4.22(@heroui/theme@2.4.22(tailwindcss@4.1.18))(framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@heroui/theme': 2.4.22(tailwindcss@4.1.18) '@react-aria/focus': 3.21.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@hono/node-server@1.19.9(hono@4.11.4)': + '@hono/node-server@1.19.9(hono@4.11.7)': dependencies: - hono: 4.11.4 + hono: 4.11.7 '@hookform/resolvers@5.2.2(react-hook-form@7.62.0(react@19.2.4))': dependencies: @@ -11101,7 +11188,7 @@ snapshots: '@isaacs/balanced-match@4.0.1': {} - '@isaacs/brace-expansion@5.0.0': + '@isaacs/brace-expansion@5.0.1': dependencies: '@isaacs/balanced-match': 4.0.1 @@ -11114,10 +11201,6 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@isaacs/fs-minipass@4.0.1': - dependencies: - minipass: 7.1.2 - '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -11145,7 +11228,7 @@ snapshots: '@langchain/aws@1.1.0(@langchain/core@1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)))': dependencies: '@aws-sdk/client-bedrock-agent-runtime': 3.971.0 - '@aws-sdk/client-bedrock-runtime': 3.948.0 + '@aws-sdk/client-bedrock-runtime': 3.988.0 '@aws-sdk/client-kendra': 3.971.0 '@aws-sdk/credential-provider-node': 3.971.0 '@langchain/core': 1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)) @@ -11198,18 +11281,17 @@ snapshots: - react - react-dom - '@langchain/mcp-adapters@1.0.3(@cfworker/json-schema@4.1.1)(@langchain/core@1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)))(@langchain/langgraph@1.1.0(@langchain/core@1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@4.1.11))(zod@4.1.11))(hono@4.11.4)': + '@langchain/mcp-adapters@1.1.3(@cfworker/json-schema@4.1.1)(@langchain/core@1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)))(@langchain/langgraph@1.1.0(@langchain/core@1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@4.1.11))(zod@4.1.11))': dependencies: '@langchain/core': 1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)) '@langchain/langgraph': 1.1.0(@langchain/core@1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@4.1.11))(zod@4.1.11) - '@modelcontextprotocol/sdk': 1.25.2(@cfworker/json-schema@4.1.1)(hono@4.11.4)(zod@4.1.11) + '@modelcontextprotocol/sdk': 1.26.0(@cfworker/json-schema@4.1.1)(zod@4.1.11) debug: 4.4.3 zod: 4.1.11 optionalDependencies: extended-eventsource: 1.7.0 transitivePeerDependencies: - '@cfworker/json-schema' - - hono - supports-color '@langchain/openai@1.1.3(@langchain/core@1.1.15(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.16.0(zod@4.1.11)))': @@ -11225,9 +11307,9 @@ snapshots: dependencies: langium: 3.3.1 - '@modelcontextprotocol/sdk@1.25.2(@cfworker/json-schema@4.1.1)(hono@4.11.4)(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.26.0(@cfworker/json-schema@4.1.1)(zod@3.25.76)': dependencies: - '@hono/node-server': 1.19.9(hono@4.11.4) + '@hono/node-server': 1.19.9(hono@4.11.7) ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) content-type: 1.0.5 @@ -11236,7 +11318,8 @@ snapshots: eventsource: 3.0.7 eventsource-parser: 3.0.6 express: 5.2.1 - express-rate-limit: 7.5.1(express@5.2.1) + express-rate-limit: 8.2.1(express@5.2.1) + hono: 4.11.7 jose: 6.1.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -11246,12 +11329,11 @@ snapshots: optionalDependencies: '@cfworker/json-schema': 4.1.1 transitivePeerDependencies: - - hono - supports-color - '@modelcontextprotocol/sdk@1.25.2(@cfworker/json-schema@4.1.1)(hono@4.11.4)(zod@4.1.11)': + '@modelcontextprotocol/sdk@1.26.0(@cfworker/json-schema@4.1.1)(zod@4.1.11)': dependencies: - '@hono/node-server': 1.19.9(hono@4.11.4) + '@hono/node-server': 1.19.9(hono@4.11.7) ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) content-type: 1.0.5 @@ -11260,7 +11342,8 @@ snapshots: eventsource: 3.0.7 eventsource-parser: 3.0.6 express: 5.2.1 - express-rate-limit: 7.5.1(express@5.2.1) + express-rate-limit: 8.2.1(express@5.2.1) + hono: 4.11.7 jose: 6.1.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -11270,7 +11353,6 @@ snapshots: optionalDependencies: '@cfworker/json-schema': 4.1.1 transitivePeerDependencies: - - hono - supports-color '@mswjs/interceptors@0.40.0': @@ -14006,6 +14088,19 @@ snapshots: '@smithy/uuid': 1.1.0 tslib: 2.8.1 + '@smithy/core@3.23.0': + dependencies: + '@smithy/middleware-serde': 4.2.9 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-stream': 4.5.12 + '@smithy/util-utf8': 4.2.0 + '@smithy/uuid': 1.1.0 + tslib: 2.8.1 + '@smithy/credential-provider-imds@4.2.8': dependencies: '@smithy/node-config-provider': 4.3.8 @@ -14078,6 +14173,17 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@smithy/middleware-endpoint@4.4.14': + dependencies: + '@smithy/core': 3.23.0 + '@smithy/middleware-serde': 4.2.9 + '@smithy/node-config-provider': 4.3.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-middleware': 4.2.8 + tslib: 2.8.1 + '@smithy/middleware-endpoint@4.4.8': dependencies: '@smithy/core': 3.20.7 @@ -14101,6 +14207,18 @@ snapshots: '@smithy/uuid': 1.1.0 tslib: 2.8.1 + '@smithy/middleware-retry@4.4.31': + dependencies: + '@smithy/node-config-provider': 4.3.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/service-error-classification': 4.2.8 + '@smithy/smithy-client': 4.11.3 + '@smithy/types': 4.12.0 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-retry': 4.2.8 + '@smithy/uuid': 1.1.0 + tslib: 2.8.1 + '@smithy/middleware-serde@4.2.9': dependencies: '@smithy/protocol-http': 5.3.8 @@ -14119,6 +14237,14 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@smithy/node-http-handler@4.4.10': + dependencies: + '@smithy/abort-controller': 4.2.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/querystring-builder': 4.2.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@smithy/node-http-handler@4.4.8': dependencies: '@smithy/abort-controller': 4.2.8 @@ -14178,6 +14304,16 @@ snapshots: '@smithy/util-stream': 4.5.10 tslib: 2.8.1 + '@smithy/smithy-client@4.11.3': + dependencies: + '@smithy/core': 3.23.0 + '@smithy/middleware-endpoint': 4.4.14 + '@smithy/middleware-stack': 4.2.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + '@smithy/util-stream': 4.5.12 + tslib: 2.8.1 + '@smithy/types@4.12.0': dependencies: tslib: 2.8.1 @@ -14223,6 +14359,13 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@smithy/util-defaults-mode-browser@4.3.30': + dependencies: + '@smithy/property-provider': 4.2.8 + '@smithy/smithy-client': 4.11.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@smithy/util-defaults-mode-node@4.2.26': dependencies: '@smithy/config-resolver': 4.4.6 @@ -14233,6 +14376,16 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@smithy/util-defaults-mode-node@4.2.33': + dependencies: + '@smithy/config-resolver': 4.4.6 + '@smithy/credential-provider-imds': 4.2.8 + '@smithy/node-config-provider': 4.3.8 + '@smithy/property-provider': 4.2.8 + '@smithy/smithy-client': 4.11.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@smithy/util-endpoints@3.2.8': dependencies: '@smithy/node-config-provider': 4.3.8 @@ -14265,6 +14418,17 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@smithy/util-stream@4.5.12': + dependencies: + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/node-http-handler': 4.4.10 + '@smithy/types': 4.12.0 + '@smithy/util-base64': 4.3.0 + '@smithy/util-buffer-from': 4.2.0 + '@smithy/util-hex-encoding': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + '@smithy/util-uri-escape@4.2.0': dependencies: tslib: 2.8.1 @@ -14295,85 +14459,82 @@ snapshots: dependencies: tslib: 2.8.1 - '@tailwindcss/node@4.1.13': + '@tailwindcss/node@4.1.18': dependencies: '@jridgewell/remapping': 2.3.5 enhanced-resolve: 5.18.4 jiti: 2.6.1 - lightningcss: 1.30.1 + lightningcss: 1.30.2 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.1.13 + tailwindcss: 4.1.18 - '@tailwindcss/oxide-android-arm64@4.1.13': + '@tailwindcss/oxide-android-arm64@4.1.18': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.13': + '@tailwindcss/oxide-darwin-arm64@4.1.18': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.13': + '@tailwindcss/oxide-darwin-x64@4.1.18': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.13': + '@tailwindcss/oxide-freebsd-x64@4.1.18': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.13': + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.13': + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.13': + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.13': + '@tailwindcss/oxide-linux-x64-musl@4.1.18': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.13': + '@tailwindcss/oxide-wasm32-wasi@4.1.18': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.13': + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.13': + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': optional: true - '@tailwindcss/oxide@4.1.13': - dependencies: - detect-libc: 2.1.2 - tar: 7.5.3 + '@tailwindcss/oxide@4.1.18': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.13 - '@tailwindcss/oxide-darwin-arm64': 4.1.13 - '@tailwindcss/oxide-darwin-x64': 4.1.13 - '@tailwindcss/oxide-freebsd-x64': 4.1.13 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.13 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.13 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.13 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.13 - '@tailwindcss/oxide-linux-x64-musl': 4.1.13 - '@tailwindcss/oxide-wasm32-wasi': 4.1.13 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.13 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.13 + '@tailwindcss/oxide-android-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-x64': 4.1.18 + '@tailwindcss/oxide-freebsd-x64': 4.1.18 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-x64-musl': 4.1.18 + '@tailwindcss/oxide-wasm32-wasi': 4.1.18 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 - '@tailwindcss/postcss@4.1.13': + '@tailwindcss/postcss@4.1.18': dependencies: '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.1.13 - '@tailwindcss/oxide': 4.1.13 + '@tailwindcss/node': 4.1.18 + '@tailwindcss/oxide': 4.1.18 postcss: 8.5.6 - tailwindcss: 4.1.13 + tailwindcss: 4.1.18 - '@tailwindcss/typography@0.5.16(tailwindcss@4.1.13)': + '@tailwindcss/typography@0.5.16(tailwindcss@4.1.18)': dependencies: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 4.1.13 + tailwindcss: 4.1.18 '@tanstack/react-table@8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: @@ -14615,6 +14776,8 @@ snapshots: '@types/uuid@10.0.0': {} + '@types/validate-npm-package-name@4.0.2': {} + '@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.5.4))(eslint@9.39.2(jiti@2.6.1))(typescript@5.5.4)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -15093,6 +15256,10 @@ snapshots: buffer-from@1.1.2: {} + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + bytes@3.1.2: {} call-bind-apply-helpers@1.0.2: @@ -15138,7 +15305,7 @@ snapshots: chevrotain-allstar@0.3.1(chevrotain@11.0.3): dependencies: chevrotain: 11.0.3 - lodash-es: 4.17.22 + lodash-es: 4.17.23 chevrotain@11.0.3: dependencies: @@ -15147,7 +15314,7 @@ snapshots: '@chevrotain/regexp-to-ast': 11.0.3 '@chevrotain/types': 11.0.3 '@chevrotain/utils': 11.0.3 - lodash-es: 4.17.21 + lodash-es: 4.17.23 chokidar@3.6.0: dependencies: @@ -15161,8 +15328,6 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - chownr@3.0.0: {} - chrome-trace-event@1.0.4: {} cjs-module-lexer@1.4.3: {} @@ -15488,12 +15653,12 @@ snapshots: dagre-d3-es@7.0.13: dependencies: d3: 7.9.0 - lodash-es: 4.17.22 + lodash-es: 4.17.23 dagre@0.8.5: dependencies: graphlib: 2.1.8 - lodash: 4.17.21 + lodash: 4.17.23 damerau-levenshtein@1.0.8: {} @@ -15547,12 +15712,21 @@ snapshots: deepmerge@4.3.1: {} + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 es-errors: 1.3.0 gopd: 1.2.0 + define-lazy-prop@3.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 @@ -16070,9 +16244,10 @@ snapshots: strip-final-newline: 4.0.0 yoctocolors: 2.1.2 - express-rate-limit@7.5.1(express@5.2.1): + express-rate-limit@8.2.1(express@5.2.1): dependencies: express: 5.2.1 + ip-address: 10.0.1 express@5.2.1: dependencies: @@ -16140,7 +16315,7 @@ snapshots: fast-uri@3.1.0: {} - fast-xml-parser@5.2.5: + fast-xml-parser@5.3.4: dependencies: strnum: 2.1.2 @@ -16338,7 +16513,7 @@ snapshots: graphlib@2.1.8: dependencies: - lodash: 4.17.21 + lodash: 4.17.23 graphql@16.12.0: {} @@ -16500,7 +16675,7 @@ snapshots: dependencies: react-is: 16.13.1 - hono@4.11.4: {} + hono@4.11.7: {} html-entities@2.6.0: {} @@ -16590,6 +16765,8 @@ snapshots: '@formatjs/icu-messageformat-parser': 2.11.2 tslib: 2.8.1 + ip-address@10.0.1: {} + ipaddr.js@1.9.1: {} is-alphabetical@2.0.1: {} @@ -16653,6 +16830,8 @@ snapshots: is-decimal@2.0.1: {} + is-docker@3.0.0: {} + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -16681,6 +16860,12 @@ snapshots: is-hexadecimal@2.0.1: {} + is-in-ssh@1.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + is-interactive@2.0.0: {} is-map@2.0.3: {} @@ -16759,6 +16944,10 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-wsl@3.1.0: + dependencies: + is-inside-container: 1.0.0 + isarray@2.0.5: {} isexe@2.0.0: {} @@ -16906,50 +17095,54 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-darwin-arm64@1.30.1: + lightningcss-android-arm64@1.30.2: optional: true - lightningcss-darwin-x64@1.30.1: + lightningcss-darwin-arm64@1.30.2: optional: true - lightningcss-freebsd-x64@1.30.1: + lightningcss-darwin-x64@1.30.2: optional: true - lightningcss-linux-arm-gnueabihf@1.30.1: + lightningcss-freebsd-x64@1.30.2: optional: true - lightningcss-linux-arm64-gnu@1.30.1: + lightningcss-linux-arm-gnueabihf@1.30.2: optional: true - lightningcss-linux-arm64-musl@1.30.1: + lightningcss-linux-arm64-gnu@1.30.2: optional: true - lightningcss-linux-x64-gnu@1.30.1: + lightningcss-linux-arm64-musl@1.30.2: optional: true - lightningcss-linux-x64-musl@1.30.1: + lightningcss-linux-x64-gnu@1.30.2: optional: true - lightningcss-win32-arm64-msvc@1.30.1: + lightningcss-linux-x64-musl@1.30.2: optional: true - lightningcss-win32-x64-msvc@1.30.1: + lightningcss-win32-arm64-msvc@1.30.2: optional: true - lightningcss@1.30.1: + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-darwin-arm64: 1.30.1 - lightningcss-darwin-x64: 1.30.1 - lightningcss-freebsd-x64: 1.30.1 - lightningcss-linux-arm-gnueabihf: 1.30.1 - lightningcss-linux-arm64-gnu: 1.30.1 - lightningcss-linux-arm64-musl: 1.30.1 - lightningcss-linux-x64-gnu: 1.30.1 - lightningcss-linux-x64-musl: 1.30.1 - lightningcss-win32-arm64-msvc: 1.30.1 - lightningcss-win32-x64-msvc: 1.30.1 + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 lilconfig@3.1.3: {} @@ -16985,9 +17178,7 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash-es@4.17.21: {} - - lodash-es@4.17.22: {} + lodash-es@4.17.23: {} lodash.castarray@4.4.0: {} @@ -16995,7 +17186,7 @@ snapshots: lodash.merge@4.6.2: {} - lodash@4.17.21: {} + lodash@4.17.23: {} log-symbols@6.0.0: dependencies: @@ -17235,7 +17426,7 @@ snapshots: dompurify: 3.3.1 katex: 0.16.27 khroma: 2.1.0 - lodash-es: 4.17.22 + lodash-es: 4.17.23 marked: 16.4.2 roughjs: 4.6.6 stylis: 4.3.6 @@ -17500,7 +17691,7 @@ snapshots: minimatch@10.1.1: dependencies: - '@isaacs/brace-expansion': 5.0.0 + '@isaacs/brace-expansion': 5.0.1 minimatch@3.1.2: dependencies: @@ -17514,10 +17705,6 @@ snapshots: minipass@7.1.2: {} - minizlib@3.1.0: - dependencies: - minipass: 7.1.2 - mlly@1.8.0: dependencies: acorn: 8.15.0 @@ -17720,6 +17907,15 @@ snapshots: regex: 6.1.0 regex-recursion: 6.0.2 + open@11.0.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 + is-inside-container: 1.0.0 + powershell-utils: 0.1.0 + wsl-utils: 0.3.1 + openai@6.16.0(zod@4.1.11): optionalDependencies: zod: 4.1.11 @@ -17889,6 +18085,11 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss-value-parser@4.2.0: {} postcss@8.4.31: @@ -17919,6 +18120,8 @@ snapshots: dependencies: xtend: 4.0.2 + powershell-utils@0.1.0: {} + preact-render-to-string@6.5.11(preact@10.24.3): dependencies: preact: 10.24.3 @@ -18160,7 +18363,7 @@ snapshots: dependencies: clsx: 2.1.1 eventemitter3: 4.0.7 - lodash: 4.17.21 + lodash: 4.17.23 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) react-is: 18.3.1 @@ -18382,6 +18585,8 @@ snapshots: transitivePeerDependencies: - supports-color + run-applescript@7.1.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -18487,7 +18692,7 @@ snapshots: setprototypeof@1.2.0: {} - shadcn@3.4.1(@cfworker/json-schema@4.1.1)(@types/node@24.10.8)(hono@4.11.4)(typescript@5.5.4): + shadcn@3.8.4(@cfworker/json-schema@4.1.1)(@types/node@24.10.8)(typescript@5.5.4): dependencies: '@antfu/ni': 25.0.0 '@babel/core': 7.28.6 @@ -18495,7 +18700,8 @@ snapshots: '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.28.6) '@babel/preset-typescript': 7.28.5(@babel/core@7.28.6) '@dotenvx/dotenvx': 1.51.4 - '@modelcontextprotocol/sdk': 1.25.2(@cfworker/json-schema@4.1.1)(hono@4.11.4)(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.26.0(@cfworker/json-schema@4.1.1)(zod@3.25.76) + '@types/validate-npm-package-name': 4.0.2 browserslist: 4.28.1 commander: 14.0.2 cosmiconfig: 9.0.0(typescript@5.5.4) @@ -18510,20 +18716,23 @@ snapshots: kleur: 4.1.5 msw: 2.12.7(@types/node@24.10.8)(typescript@5.5.4) node-fetch: 3.3.2 + open: 11.0.0 ora: 8.2.0 postcss: 8.5.6 + postcss-selector-parser: 7.1.1 prompts: 2.4.2 recast: 0.23.11 stringify-object: 5.0.0 + tailwind-merge: 3.3.1 ts-morph: 26.0.0 tsconfig-paths: 4.2.0 + validate-npm-package-name: 7.0.2 zod: 3.25.76 zod-to-json-schema: 3.25.1(zod@3.25.76) transitivePeerDependencies: - '@cfworker/json-schema' - '@types/node' - babel-plugin-macros - - hono - supports-color - typescript @@ -18855,33 +19064,25 @@ snapshots: tailwind-merge@3.3.1: {} - tailwind-variants@0.1.20(tailwindcss@4.1.13): + tailwind-variants@0.1.20(tailwindcss@4.1.18): dependencies: tailwind-merge: 1.14.0 - tailwindcss: 4.1.13 + tailwindcss: 4.1.18 - tailwind-variants@3.1.1(tailwind-merge@3.3.1)(tailwindcss@4.1.13): + tailwind-variants@3.1.1(tailwind-merge@3.3.1)(tailwindcss@4.1.18): dependencies: - tailwindcss: 4.1.13 + tailwindcss: 4.1.18 optionalDependencies: tailwind-merge: 3.3.1 - tailwindcss-animate@1.0.7(tailwindcss@4.1.13): + tailwindcss-animate@1.0.7(tailwindcss@4.1.18): dependencies: - tailwindcss: 4.1.13 + tailwindcss: 4.1.18 - tailwindcss@4.1.13: {} + tailwindcss@4.1.18: {} tapable@2.3.0: {} - tar@7.5.3: - dependencies: - '@isaacs/fs-minipass': 4.0.1 - chownr: 3.0.0 - minipass: 7.1.2 - minizlib: 3.1.0 - yallist: 5.0.0 - terser-webpack-plugin@5.3.16(webpack@5.104.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -19182,6 +19383,8 @@ snapshots: uuid@9.0.1: {} + validate-npm-package-name@7.0.2: {} + vary@1.1.2: {} vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): @@ -19373,14 +19576,17 @@ snapshots: wrappy@1.0.2: {} + wsl-utils@0.3.1: + dependencies: + is-wsl: 3.1.0 + powershell-utils: 0.1.0 + xtend@4.0.2: {} y18n@5.0.8: {} yallist@3.1.1: {} - yallist@5.0.0: {} - yaml@2.8.2: {} yargs-parser@21.1.1: {} From 5b038e631a7bac15ecfb4a1e53b5ce9fcaf5d853 Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:12:37 +0100 Subject: [PATCH 06/12] refactor(ui): centralize provider type filter sanitization in server actions (#10043) --- ui/actions/findings/findings.ts | 41 ++--- .../overview/attack-surface/attack-surface.ts | 8 +- .../compliance-watchlist.ts | 7 +- ui/actions/overview/findings/findings.ts | 25 +-- ui/actions/overview/providers/providers.ts | 7 +- ui/actions/overview/regions/regions.ts | 8 +- .../resources-inventory.ts | 8 +- ui/actions/overview/risk-radar/risk-radar.ts | 8 +- ui/actions/overview/services/services.ts | 7 +- .../severity-trends/severity-trends.ts | 7 +- .../overview/threat-score/threat-score.ts | 8 +- ui/actions/providers/providers.ts | 22 ++- ui/actions/resources/resources.ts | 29 ++-- ui/actions/scans/scans.ts | 16 +- ui/app/(prowler)/providers/page.tsx | 25 ++- ui/lib/provider-filters.ts | 144 ++++++++++++++++++ 16 files changed, 219 insertions(+), 151 deletions(-) create mode 100644 ui/lib/provider-filters.ts diff --git a/ui/actions/findings/findings.ts b/ui/actions/findings/findings.ts index d226795483..7ce7f931ad 100644 --- a/ui/actions/findings/findings.ts +++ b/ui/actions/findings/findings.ts @@ -3,6 +3,7 @@ import { redirect } from "next/navigation"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; export const getFindings = async ({ page = 1, @@ -24,12 +25,7 @@ export const getFindings = async ({ if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); - Object.entries(filters).forEach(([key, value]) => { - // Skip filter[search] since it's already added via the `query` param above - if (key !== "filter[search]") { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderTypeFilters(url, filters); try { const findings = await fetch(url.toString(), { @@ -65,12 +61,7 @@ export const getLatestFindings = async ({ if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); - Object.entries(filters).forEach(([key, value]) => { - // Skip filter[search] since it's already added via the `query` param above - if (key !== "filter[search]") { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderTypeFilters(url, filters); try { const findings = await fetch(url.toString(), { @@ -96,20 +87,13 @@ export const getMetadataInfo = async ({ if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); - Object.entries(filters).forEach(([key, value]) => { - // Define filters to exclude - const excludedFilters = [ + appendSanitizedProviderTypeFilters(url, filters, { + excludedKeyIncludes: [ "region__in", "service__in", "resource_type__in", "resource_groups__in", - ]; - if ( - key !== "filter[search]" && - !excludedFilters.some((filter) => key.includes(filter)) - ) { - url.searchParams.append(key, String(value)); - } + ], }); try { @@ -136,20 +120,13 @@ export const getLatestMetadataInfo = async ({ if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); - Object.entries(filters).forEach(([key, value]) => { - // Define filters to exclude - const excludedFilters = [ + appendSanitizedProviderTypeFilters(url, filters, { + excludedKeyIncludes: [ "region__in", "service__in", "resource_type__in", "resource_groups__in", - ]; - if ( - key !== "filter[search]" && - !excludedFilters.some((filter) => key.includes(filter)) - ) { - url.searchParams.append(key, String(value)); - } + ], }); try { diff --git a/ui/actions/overview/attack-surface/attack-surface.ts b/ui/actions/overview/attack-surface/attack-surface.ts index 342e958bc3..4a97a406d4 100644 --- a/ui/actions/overview/attack-surface/attack-surface.ts +++ b/ui/actions/overview/attack-surface/attack-surface.ts @@ -1,6 +1,7 @@ "use server"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { AttackSurfaceOverviewResponse } from "./types"; @@ -14,12 +15,7 @@ export const getAttackSurfaceOverview = async ({ const url = new URL(`${apiBaseUrl}/overviews/attack-surfaces`); - // Handle multiple filters - Object.entries(filters).forEach(([key, value]) => { - if (key !== "filter[search]" && value !== undefined) { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/overview/compliance-watchlist/compliance-watchlist.ts b/ui/actions/overview/compliance-watchlist/compliance-watchlist.ts index 647ee99e45..026a1b426b 100644 --- a/ui/actions/overview/compliance-watchlist/compliance-watchlist.ts +++ b/ui/actions/overview/compliance-watchlist/compliance-watchlist.ts @@ -1,6 +1,7 @@ "use server"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { ComplianceWatchlistResponse } from "./compliance-watchlist.types"; @@ -15,11 +16,7 @@ export const getComplianceWatchlist = async ({ // Append filter parameters (provider_id, provider_type, etc.) // Exclude filter[search] as this endpoint doesn't support text search - Object.entries(filters).forEach(([key, value]) => { - if (key !== "filter[search]" && value !== undefined) { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { headers }); diff --git a/ui/actions/overview/findings/findings.ts b/ui/actions/overview/findings/findings.ts index 28dbbfbe8d..2aa771fb26 100644 --- a/ui/actions/overview/findings/findings.ts +++ b/ui/actions/overview/findings/findings.ts @@ -3,6 +3,7 @@ import { redirect } from "next/navigation"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { FindingsSeverityOverviewResponse } from "./types"; @@ -28,17 +29,8 @@ export const getFindingsByStatus = async ({ if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); - // Handle multiple filters, but exclude muted filter as overviews endpoint doesn't support it - Object.entries(filters).forEach(([key, value]) => { - // The overviews/findings endpoint does not support status or muted filters - // (allowed filters include date, region, provider fields). Exclude unsupported ones. - if ( - key !== "filter[search]" && - key !== "filter[muted]" && - key !== "filter[status]" - ) { - url.searchParams.append(key, String(value)); - } + appendSanitizedProviderTypeFilters(url, filters, { + excludedKeys: ["filter[search]", "filter[muted]", "filter[status]"], }); try { @@ -62,15 +54,8 @@ export const getFindingsBySeverity = async ({ const url = new URL(`${apiBaseUrl}/overviews/findings_severity`); - // Handle multiple filters, but exclude unsupported filters - Object.entries(filters).forEach(([key, value]) => { - if ( - key !== "filter[search]" && - key !== "filter[muted]" && - value !== undefined - ) { - url.searchParams.append(key, String(value)); - } + appendSanitizedProviderTypeFilters(url, filters, { + excludedKeys: ["filter[search]", "filter[muted]"], }); try { diff --git a/ui/actions/overview/providers/providers.ts b/ui/actions/overview/providers/providers.ts index 5222856ff5..9aaec5df8c 100644 --- a/ui/actions/overview/providers/providers.ts +++ b/ui/actions/overview/providers/providers.ts @@ -3,6 +3,7 @@ import { redirect } from "next/navigation"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { ProvidersOverviewResponse } from "./types"; @@ -28,11 +29,7 @@ export const getProvidersOverview = async ({ if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); - Object.entries(filters).forEach(([key, value]) => { - if (key !== "filter[search]" && value !== undefined) { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/overview/regions/regions.ts b/ui/actions/overview/regions/regions.ts index f32632208c..31610892ef 100644 --- a/ui/actions/overview/regions/regions.ts +++ b/ui/actions/overview/regions/regions.ts @@ -1,6 +1,7 @@ "use server"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { RegionsOverviewResponse } from "./types"; @@ -14,12 +15,7 @@ export const getRegionsOverview = async ({ const url = new URL(`${apiBaseUrl}/overviews/regions`); - // Handle multiple filters - Object.entries(filters).forEach(([key, value]) => { - if (key !== "filter[search]" && value !== undefined) { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/overview/resources-inventory/resources-inventory.ts b/ui/actions/overview/resources-inventory/resources-inventory.ts index 7cd353df39..264da6e375 100644 --- a/ui/actions/overview/resources-inventory/resources-inventory.ts +++ b/ui/actions/overview/resources-inventory/resources-inventory.ts @@ -1,6 +1,7 @@ "use server"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { ResourceGroupOverviewResponse } from "./types"; @@ -14,12 +15,7 @@ export const getResourceGroupOverview = async ({ const url = new URL(`${apiBaseUrl}/overviews/resource-groups`); - // Handle multiple filters - Object.entries(filters).forEach(([key, value]) => { - if (key !== "filter[search]" && value !== undefined) { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/overview/risk-radar/risk-radar.ts b/ui/actions/overview/risk-radar/risk-radar.ts index 44c04ad87e..419330dc18 100644 --- a/ui/actions/overview/risk-radar/risk-radar.ts +++ b/ui/actions/overview/risk-radar/risk-radar.ts @@ -1,6 +1,7 @@ "use server"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { CategoryOverviewResponse } from "./types"; @@ -14,12 +15,7 @@ export const getCategoryOverview = async ({ const url = new URL(`${apiBaseUrl}/overviews/categories`); - // Handle multiple filters - Object.entries(filters).forEach(([key, value]) => { - if (key !== "filter[search]" && value !== undefined) { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/overview/services/services.ts b/ui/actions/overview/services/services.ts index 3e73776dd2..1e55c04531 100644 --- a/ui/actions/overview/services/services.ts +++ b/ui/actions/overview/services/services.ts @@ -1,6 +1,7 @@ "use server"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { ServicesOverviewResponse } from "./types"; @@ -14,11 +15,7 @@ export const getServicesOverview = async ({ const url = new URL(`${apiBaseUrl}/overviews/services`); - Object.entries(filters).forEach(([key, value]) => { - if (key !== "filter[search]" && value !== undefined) { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/overview/severity-trends/severity-trends.ts b/ui/actions/overview/severity-trends/severity-trends.ts index 70701a41a8..e90efa15b7 100644 --- a/ui/actions/overview/severity-trends/severity-trends.ts +++ b/ui/actions/overview/severity-trends/severity-trends.ts @@ -5,6 +5,7 @@ import { type TimeRange, } from "@/app/(prowler)/_overview/severity-over-time/_constants/time-range.constants"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; import { adaptSeverityTrendsResponse } from "./severity-trends.adapter"; @@ -27,11 +28,7 @@ const getFindingsSeverityTrends = async ({ const url = new URL(`${apiBaseUrl}/overviews/findings_severity/timeseries`); - Object.entries(filters).forEach(([key, value]) => { - if (value !== undefined) { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/overview/threat-score/threat-score.ts b/ui/actions/overview/threat-score/threat-score.ts index 3a78d1ecda..0a1d7505d1 100644 --- a/ui/actions/overview/threat-score/threat-score.ts +++ b/ui/actions/overview/threat-score/threat-score.ts @@ -1,6 +1,7 @@ "use server"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; export const getThreatScore = async ({ @@ -12,12 +13,7 @@ export const getThreatScore = async ({ const url = new URL(`${apiBaseUrl}/overviews/threatscore`); - // Handle multiple filters - Object.entries(filters).forEach(([key, value]) => { - if (key !== "filter[search]") { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/providers/providers.ts b/ui/actions/providers/providers.ts index 4665e9db39..63c01332b1 100644 --- a/ui/actions/providers/providers.ts +++ b/ui/actions/providers/providers.ts @@ -6,6 +6,7 @@ import { redirect } from "next/navigation"; import { apiBaseUrl, getAuthHeaders, getFormValue, wait } from "@/lib"; import { buildSecretConfig } from "@/lib/provider-credentials/build-crendentials"; import { ProviderCredentialFields } from "@/lib/provider-credentials/provider-credential-fields"; +import { appendSanitizedProviderInFilters } from "@/lib/provider-filters"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; import { ProvidersApiResponse, ProviderType } from "@/types/providers"; @@ -15,6 +16,12 @@ export const getProviders = async ({ sort = "", filters = {}, pageSize = 10, +}: { + page?: number; + query?: string; + sort?: string; + filters?: Record; + pageSize?: number; }): Promise => { const headers = await getAuthHeaders({ contentType: false }); @@ -27,12 +34,7 @@ export const getProviders = async ({ if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); - // Handle multiple filters - Object.entries(filters).forEach(([key, value]) => { - if (key !== "filter[search]") { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderInFilters(url, filters); try { const response = await fetch(url.toString(), { @@ -60,7 +62,7 @@ export const getAllProviders = async ({ }: { query?: string; sort?: string; - filters?: Record; + filters?: Record; } = {}): Promise => { const headers = await getAuthHeaders({ contentType: false }); const pageSize = 100; // Use larger page size to minimize API calls @@ -79,11 +81,7 @@ export const getAllProviders = async ({ if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); - Object.entries(filters).forEach(([key, value]) => { - if (key !== "filter[search]") { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderInFilters(url, filters); const response = await fetch(url.toString(), { headers }); const data = (await handleApiResponse(response)) as diff --git a/ui/actions/resources/resources.ts b/ui/actions/resources/resources.ts index f7b0a1b002..d65505704f 100644 --- a/ui/actions/resources/resources.ts +++ b/ui/actions/resources/resources.ts @@ -3,6 +3,7 @@ import { redirect } from "next/navigation"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; +import { appendSanitizedProviderTypeFilters } from "@/lib/provider-filters"; import { handleApiResponse } from "@/lib/server-actions-helper"; export const getResources = async ({ @@ -17,7 +18,7 @@ export const getResources = async ({ page?: number; query?: string; sort?: string; - filters?: Record; + filters?: Record; pageSize?: number; include?: string; fields?: string[]; @@ -38,9 +39,7 @@ export const getResources = async ({ if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); - Object.entries(filters).forEach(([key, value]) => { - url.searchParams.append(key, String(value)); - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { @@ -66,7 +65,7 @@ export const getLatestResources = async ({ page?: number; query?: string; sort?: string; - filters?: Record; + filters?: Record; pageSize?: number; include?: string; fields?: string[]; @@ -87,9 +86,7 @@ export const getLatestResources = async ({ if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); - Object.entries(filters).forEach(([key, value]) => { - url.searchParams.append(key, String(value)); - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { @@ -107,6 +104,10 @@ export const getMetadataInfo = async ({ query = "", sort = "", filters = {}, +}: { + query?: string; + sort?: string; + filters?: Record; }) => { const headers = await getAuthHeaders({ contentType: false }); @@ -115,9 +116,7 @@ export const getMetadataInfo = async ({ if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); - Object.entries(filters).forEach(([key, value]) => { - url.searchParams.append(key, String(value)); - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { @@ -135,6 +134,10 @@ export const getLatestMetadataInfo = async ({ query = "", sort = "", filters = {}, +}: { + query?: string; + sort?: string; + filters?: Record; }) => { const headers = await getAuthHeaders({ contentType: false }); @@ -143,9 +146,7 @@ export const getLatestMetadataInfo = async ({ if (query) url.searchParams.append("filter[search]", query); if (sort) url.searchParams.append("sort", sort); - Object.entries(filters).forEach(([key, value]) => { - url.searchParams.append(key, String(value)); - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { diff --git a/ui/actions/scans/scans.ts b/ui/actions/scans/scans.ts index a5f615bfe4..52da71bb3b 100644 --- a/ui/actions/scans/scans.ts +++ b/ui/actions/scans/scans.ts @@ -7,6 +7,10 @@ import { COMPLIANCE_REPORT_DISPLAY_NAMES, type ComplianceReportType, } from "@/lib/compliance/compliance-report-types"; +import { + appendSanitizedProviderTypeFilters, + sanitizeProviderTypesCsv, +} from "@/lib/provider-filters"; import { addScanOperation } from "@/lib/sentry-breadcrumbs"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; export const getScans = async ({ @@ -35,13 +39,7 @@ export const getScans = async ({ url.searchParams.append(`fields[${key}]`, String(value)); }); - // Add dynamic filters (e.g., "filter[state]", "fields[scans]") - Object.entries(filters).forEach(([key, value]) => { - // Skip filter[search] since it's already added via the `query` param above - if (key !== "filter[search]") { - url.searchParams.append(key, String(value)); - } - }); + appendSanitizedProviderTypeFilters(url, filters); try { const response = await fetch(url.toString(), { headers }); @@ -58,6 +56,10 @@ export const getScansByState = async () => { const url = new URL(`${apiBaseUrl}/scans`); // Request only the necessary fields to optimize the response url.searchParams.append("fields[scans]", "state"); + url.searchParams.append( + "filter[provider_type__in]", + sanitizeProviderTypesCsv(), + ); try { const response = await fetch(url.toString(), { diff --git a/ui/app/(prowler)/providers/page.tsx b/ui/app/(prowler)/providers/page.tsx index 5cc1582364..6e52449c04 100644 --- a/ui/app/(prowler)/providers/page.tsx +++ b/ui/app/(prowler)/providers/page.tsx @@ -13,7 +13,7 @@ import { } from "@/components/providers/table"; import { ContentLayout } from "@/components/ui"; import { DataTable } from "@/components/ui/table"; -import { PROVIDER_TYPES, ProviderProps, SearchParamsProps } from "@/types"; +import { ProviderProps, SearchParamsProps } from "@/types"; export default async function Providers({ searchParams, @@ -89,22 +89,15 @@ const ProvidersTable = async ({ return acc; }, {}) || {}; - // Exclude provider types not yet supported in the UI const enrichedProviders = - providersData?.data - ?.filter((provider: ProviderProps) => - (PROVIDER_TYPES as readonly string[]).includes( - provider.attributes.provider, - ), - ) - .map((provider: ProviderProps) => { - const groupNames = - provider.relationships?.provider_groups?.data?.map( - (group: { id: string }) => - providerGroupDict[group.id] || "Unknown Group", - ) || []; - return { ...provider, groupNames }; - }) || []; + providersData?.data?.map((provider: ProviderProps) => { + const groupNames = + provider.relationships?.provider_groups?.data?.map( + (group: { id: string }) => + providerGroupDict[group.id] || "Unknown Group", + ) || []; + return { ...provider, groupNames }; + }) || []; return ( <> diff --git a/ui/lib/provider-filters.ts b/ui/lib/provider-filters.ts new file mode 100644 index 0000000000..62edc5bb64 --- /dev/null +++ b/ui/lib/provider-filters.ts @@ -0,0 +1,144 @@ +import { PROVIDER_TYPES, type ProviderType } from "@/types/providers"; + +export type ProviderFilterValue = string | string[] | undefined; +export type ProviderFilters = Record; + +interface AppendProviderFiltersOptions { + ensuredInFilterKey?: string; + excludedKeys?: string[]; + excludedKeyIncludes?: string[]; +} + +type AppendSanitizedProviderTypeFiltersOptions = Omit< + AppendProviderFiltersOptions, + "ensuredInFilterKey" +>; + +const SUPPORTED_PROVIDER_TYPES_CSV = PROVIDER_TYPES.join(","); +export const PROVIDER_IN_FILTER_KEY = "filter[provider__in]"; +export const PROVIDER_TYPE_IN_FILTER_KEY = "filter[provider_type__in]"; + +const PROVIDER_TYPE_IN_KEYS = new Set([ + PROVIDER_TYPE_IN_FILTER_KEY, + "provider_type__in", +]); + +const PROVIDER_SINGLE_KEYS = new Set([ + "filter[provider_type]", + "provider_type", +]); + +const toCsvString = (value: unknown): string => { + if (Array.isArray(value)) return value.join(","); + if (typeof value === "string") return value; + return ""; +}; + +const isSupportedProviderType = (value: string): value is ProviderType => + (PROVIDER_TYPES as readonly string[]).includes(value); + +export const sanitizeProviderTypesCsv = (value?: unknown): string => { + const rawValue = toCsvString(value); + if (!rawValue.trim()) return SUPPORTED_PROVIDER_TYPES_CSV; + + const supportedProviderTypes = Array.from( + new Set( + rawValue + .split(",") + .map((providerType) => providerType.trim()) + .filter(isSupportedProviderType), + ), + ); + + return supportedProviderTypes.length > 0 + ? supportedProviderTypes.join(",") + : SUPPORTED_PROVIDER_TYPES_CSV; +}; + +export const sanitizeProviderType = ( + value?: unknown, +): ProviderType | undefined => { + const rawValue = toCsvString(value); + if (!rawValue.trim()) return undefined; + + return rawValue + .split(",") + .map((providerType) => providerType.trim()) + .find(isSupportedProviderType); +}; + +export const sanitizeProviderFilters = ( + filters: ProviderFilters = {}, + ensuredInFilterKey?: string, +): ProviderFilters => { + const sanitizedFilters: ProviderFilters = { ...filters }; + + Object.keys(sanitizedFilters).forEach((key) => { + if (PROVIDER_TYPE_IN_KEYS.has(key)) { + sanitizedFilters[key] = sanitizeProviderTypesCsv(sanitizedFilters[key]); + return; + } + + if (PROVIDER_SINGLE_KEYS.has(key)) { + const providerType = sanitizeProviderType(sanitizedFilters[key]); + if (providerType) { + sanitizedFilters[key] = providerType; + } else { + delete sanitizedFilters[key]; + } + } + }); + + if (ensuredInFilterKey) { + sanitizedFilters[ensuredInFilterKey] = sanitizeProviderTypesCsv( + sanitizedFilters[ensuredInFilterKey], + ); + } + + return sanitizedFilters; +}; + +export const appendSanitizedProviderFilters = ( + url: URL, + filters: ProviderFilters = {}, + { + ensuredInFilterKey, + excludedKeys = ["filter[search]"], + excludedKeyIncludes = [], + }: AppendProviderFiltersOptions = {}, +): void => { + const sanitizedFilters = sanitizeProviderFilters(filters, ensuredInFilterKey); + const excludedKeysSet = new Set(excludedKeys); + + Object.entries(sanitizedFilters).forEach(([key, value]) => { + if ( + value === undefined || + excludedKeysSet.has(key) || + excludedKeyIncludes.some((excludedKey) => key.includes(excludedKey)) + ) { + return; + } + + url.searchParams.append(key, String(value)); + }); +}; + +export const appendSanitizedProviderTypeFilters = ( + url: URL, + filters: ProviderFilters = {}, + options: AppendSanitizedProviderTypeFiltersOptions = {}, +): void => + appendSanitizedProviderFilters(url, filters, { + ...options, + ensuredInFilterKey: PROVIDER_TYPE_IN_FILTER_KEY, + }); + +export const appendSanitizedProviderInFilters = ( + url: URL, + filters: ProviderFilters = {}, + options: AppendSanitizedProviderTypeFiltersOptions = {}, +): void => + appendSanitizedProviderFilters(url, filters, { + ...options, + ensuredInFilterKey: PROVIDER_IN_FILTER_KEY, + }); From 4d569d5b795d17367d32b5e4cb6b1b9c9f5a55be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Thu, 12 Feb 2026 14:13:24 +0100 Subject: [PATCH 07/12] feat(compliance): add csa ccm for the gcp provider (#10042) --- api/CHANGELOG.md | 1 + api/src/backend/tasks/jobs/export.py | 2 + dashboard/compliance/csa_ccm_4_0_gcp.py | 31 + prowler/CHANGELOG.md | 1 + prowler/__main__.py | 13 + prowler/compliance/gcp/csa_ccm_4.0_gcp.json | 7386 +++++++++++++++++ prowler/lib/outputs/compliance/csa/csa_gcp.py | 96 + prowler/lib/outputs/compliance/csa/models.py | 29 + 8 files changed, 7559 insertions(+) create mode 100644 dashboard/compliance/csa_ccm_4_0_gcp.py create mode 100644 prowler/compliance/gcp/csa_ccm_4.0_gcp.json create mode 100644 prowler/lib/outputs/compliance/csa/csa_gcp.py diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 4ff37ae274..04931d628e 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to the **Prowler API** are documented in this file. - Attack Paths: Queries definition now has short description and attribution [(#9983)](https://github.com/prowler-cloud/prowler/pull/9983) - Attack Paths: Internet node is created while scan [(#9992)](https://github.com/prowler-cloud/prowler/pull/9992) - Support CSA CCM for the AWS provider [(#10018)](https://github.com/prowler-cloud/prowler/pull/10018) +- Support CSA CCM 4.0 for the GCP provider [(#10042)](https://github.com/prowler-cloud/prowler/pull/10042) - Support CSA CCM for the Azure provider [(#10039)](https://github.com/prowler-cloud/prowler/pull/10039) --- diff --git a/api/src/backend/tasks/jobs/export.py b/api/src/backend/tasks/jobs/export.py index 494e48a12a..3bf02e12f6 100644 --- a/api/src/backend/tasks/jobs/export.py +++ b/api/src/backend/tasks/jobs/export.py @@ -36,6 +36,7 @@ from prowler.lib.outputs.compliance.cis.cis_kubernetes import KubernetesCIS from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS from prowler.lib.outputs.compliance.cis.cis_oraclecloud import OracleCloudCIS from prowler.lib.outputs.compliance.csa.csa_aws import AWSCSA +from prowler.lib.outputs.compliance.csa.csa_gcp import GCPCSA from prowler.lib.outputs.compliance.csa.csa_azure import AzureCSA from prowler.lib.outputs.compliance.ens.ens_aws import AWSENS from prowler.lib.outputs.compliance.ens.ens_azure import AzureENS @@ -112,6 +113,7 @@ COMPLIANCE_CLASS_MAP = { (lambda name: name == "prowler_threatscore_gcp", ProwlerThreatScoreGCP), (lambda name: name == "ccc_gcp", CCC_GCP), (lambda name: name == "c5_gcp", GCPC5), + (lambda name: name.startswith("csa_"), GCPCSA), ], "kubernetes": [ (lambda name: name.startswith("cis_"), KubernetesCIS), diff --git a/dashboard/compliance/csa_ccm_4_0_gcp.py b/dashboard/compliance/csa_ccm_4_0_gcp.py new file mode 100644 index 0000000000..346576729d --- /dev/null +++ b/dashboard/compliance/csa_ccm_4_0_gcp.py @@ -0,0 +1,31 @@ +import warnings + +from dashboard.common_methods import get_section_containers_kisa_ismsp + +warnings.filterwarnings("ignore") + + +def get_table(data): + data["REQUIREMENTS_ID"] = ( + data["REQUIREMENTS_ID"] + " - " + data["REQUIREMENTS_DESCRIPTION"] + ) + + data["REQUIREMENTS_ID"] = data["REQUIREMENTS_ID"].apply( + lambda x: x[:150] + "..." if len(str(x)) > 150 else x + ) + + aux = data[ + [ + "REQUIREMENTS_ID", + "REQUIREMENTS_ATTRIBUTES_SECTION", + "CHECKID", + "STATUS", + "REGION", + "ACCOUNTID", + "RESOURCEID", + ] + ].copy() + + return get_section_containers_kisa_ismsp( + aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID" + ) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index e2ade79ce4..47258ca87c 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - `defender_safelinks_policy_enabled` check for M365 provider [(#9832)](https://github.com/prowler-cloud/prowler/pull/9832) - AI Skills: Added a skill for creating new Attack Paths queries in openCypher, compatible with Neo4j and Neptune [(#9975)](https://github.com/prowler-cloud/prowler/pull/9975) - CSA CCM 4.0 for the AWS provider [(#10018)](https://github.com/prowler-cloud/prowler/pull/10018) +- CSA CCM 4.0 for the GCP provider [(#10042)](https://github.com/prowler-cloud/prowler/pull/10042) - CSA CCM for the Azure provider [(#10039)](https://github.com/prowler-cloud/prowler/pull/10039) ### 🔄 Changed diff --git a/prowler/__main__.py b/prowler/__main__.py index ac3c587e65..121642c675 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -66,6 +66,7 @@ from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS from prowler.lib.outputs.compliance.cis.cis_oraclecloud import OracleCloudCIS from prowler.lib.outputs.compliance.compliance import display_compliance_table from prowler.lib.outputs.compliance.csa.csa_aws import AWSCSA +from prowler.lib.outputs.compliance.csa.csa_gcp import GCPCSA from prowler.lib.outputs.compliance.csa.csa_azure import AzureCSA from prowler.lib.outputs.compliance.ens.ens_aws import AWSENS from prowler.lib.outputs.compliance.ens.ens_azure import AzureENS @@ -858,6 +859,18 @@ def prowler(): ) generated_outputs["compliance"].append(c5_gcp) c5_gcp.batch_write_data_to_file() + elif compliance_name == "csa_ccm_4.0_gcp": + filename = ( + f"{output_options.output_directory}/compliance/" + f"{output_options.output_filename}_{compliance_name}.csv" + ) + csa_ccm_4_0_gcp = GCPCSA( + findings=finding_outputs, + compliance=bulk_compliance_frameworks[compliance_name], + file_path=filename, + ) + generated_outputs["compliance"].append(csa_ccm_4_0_gcp) + csa_ccm_4_0_gcp.batch_write_data_to_file() else: filename = ( f"{output_options.output_directory}/compliance/" diff --git a/prowler/compliance/gcp/csa_ccm_4.0_gcp.json b/prowler/compliance/gcp/csa_ccm_4.0_gcp.json new file mode 100644 index 0000000000..6623fe5eca --- /dev/null +++ b/prowler/compliance/gcp/csa_ccm_4.0_gcp.json @@ -0,0 +1,7386 @@ +{ + "Framework": "CSA-CCM", + "Name": "CSA Cloud Controls Matrix (CCM) v4.0.13", + "Version": "4.0", + "Provider": "GCP", + "Description": "The Cloud Security Alliance (CSA) Cloud Controls Matrix (CCM) is a cybersecurity control framework for cloud computing, composed of 197 control objectives structured in 17 domains covering all key aspects of cloud technology. The CCM can be used as a tool for the systematic assessment of a cloud implementation, and provides guidance on which security controls should be implemented by which actor within the cloud supply chain.", + "Requirements": [ + { + "Id": "A&A-02", + "Description": "Conduct independent audit and assurance assessments according to relevant standards at least annually.", + "Name": "Independent Assessments", + "Attributes": [ + { + "Section": "Audit & Assurance", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC4.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "AAC-02" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.5.2", + "5.2.6" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "AS1.1", + "AS2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.2.1", + "27002: 18.2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.35", + "27001: A.5.36" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CA-2", + "CA-2(1)", + "CA-2(2)", + "CA-7", + "CA-7(1)" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.IM-01" + ] + } + ] + } + ], + "Checks": [ + "iam_audit_logs_enabled" + ] + }, + { + "Id": "A&A-04", + "Description": "Verify compliance with all relevant standards, regulations, legal/contractual, and statutory requirements applicable to the audit.", + "Name": "Requirements Compliance", + "Attributes": [ + { + "Section": "Audit & Assurance", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC3.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-01", + "GRM-03" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "7.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "AS1.1", + "AS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 9.3.2", + "27001: A.18.2.2", + "27002: 18.2.2", + "27001: A.18.2.3", + "27002: 18.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 9.3.2", + "27001: A.5.31", + "27001: A.5.32", + "27001: A.5.33", + "27001: A.5.34", + "27001: A.5.36" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CA-1" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-3", + "DE.DP-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.IM-01" + ] + } + ] + } + ], + "Checks": [ + "iam_audit_logs_enabled", + "iam_cloud_asset_inventory_enabled" + ] + }, + { + "Id": "AIS-04", + "Description": "Define and implement a SDLC process for application design, development, deployment, and operation in accordance with security requirements defined by the organization.", + "Name": "Secure Application Design and Development", + "Attributes": [ + { + "Section": "Application & Interface Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.8", + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "AIS-01", + "AIS-03" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.3.4", + "5.3.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SD1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.14.1.1", + "27002: 14.1.1", + "27017: 14.1.1", + "27001: A.14.1.2", + "27002: 14.1.2", + "27017: 14.1.2", + "27001: A.14.2.1", + "27002: 14.2.1", + "27017: 14.2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.8", + "27001: A.8.25", + "27001: A.8.26", + "27001: A.8.28" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PL-2", + "PL-8", + "PL-8(1)", + "SA-3", + "SA-3(1)", + "SA-4", + "SA-4(2)", + "SA-4(3)", + "SA-4(8)", + "SA-4(9)", + "SA-5", + "SA-8", + "SA-8(1)-(7)", + "SA-8(9)-(13)", + "SA-8(15)-(20)", + "SA-8(22)", + "SA-8(24)-(28)", + "SA-8(30)-(33)", + "SA-17", + "SA-17(1)-(9)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-6", + "PR.DS-7", + "PR.IP-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "PR.IR-01", + "PR.PS-01", + "PR.PS-02", + "PR.PS-06" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.3" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.2.1", + "6.2.3", + "6.5.2" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "AIS-05", + "Description": "Implement a testing strategy, including criteria for acceptance of new information systems, upgrades and new versions, which provides application security assurance and maintains compliance while enabling organizational speed of delivery goals. Automate when applicable and possible.", + "Name": "Automated Application Security Testing", + "Attributes": [ + { + "Section": "Application & Interface Security", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.8", + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "AIS-01", + "AIS-03" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.12", + "16.13" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SD2.3", + "SD2.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.14.2.8", + "27001: A.14.2.9", + "27001: A.12.1.2", + "27002: 12.1.2", + "27001: A.14.1.1", + "27002: 14.1.1", + "27001: A.14.2.2", + "27002: 14.2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.25", + "27001: A.8.29", + "27001: A.8.32", + "27002: 8.25 (e)", + "27002: 8.32 (d)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SA-11", + "SA-11(1)-(9)", + "SI-6", + "SI-6(2)", + "SI-6(3)", + "SI-10", + "SI-10(1)-(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-2", + "PR.PT-3", + "PR.IP-12", + "DE.CM-8" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "ID.RA-01", + "PR.PS-01", + "PR.PS-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "A.3.2.2", + "A.3.2.2.1", + "6.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.2.4", + "6.4.1", + "6.4.2", + "6.5.1" + ] + } + ] + } + ], + "Checks": [ + "gcr_container_scanning_enabled", + "artifacts_container_analysis_enabled" + ] + }, + { + "Id": "AIS-07", + "Description": "Define and implement a process to remediate application security vulnerabilities, automating remediation when possible.", + "Name": "Application Vulnerability Remediation", + "Attributes": [ + { + "Section": "Application & Interface Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.1", + "CC7.4", + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "TVM-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.2", + "16.6" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.16.1.5", + "27002: 16.1.5", + "27017: 16.1.5", + "27001: A.12.6.1", + "27002: 12.6.1", + "27017: 12.6.1", + "27018: 12.6.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.26", + "27001: A.8.8", + "27002: 5.26 (j)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SI-2", + "SI-2(2)-(6)", + "SA-11", + "SA-11(2)", + "SA-15", + "SA-15(1)-(3)", + "SA-15(5)-(8)", + "SA-15(10)-(12)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-2", + "PR.IP-12", + "DE.CM-8", + "RS.AN-5", + "RS.MI-3", + "PR.DS-6" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "ID.RA-01", + "ID.RA-06", + "ID.RA-08", + "PR.PS-02", + "PR.PS-06" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.2", + "6.5", + "6.5.1-10" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.3.1", + "11.3.1", + "11.3.1.1" + ] + } + ] + } + ], + "Checks": [ + "gcr_container_scanning_enabled", + "artifacts_container_analysis_enabled" + ] + }, + { + "Id": "BCR-08", + "Description": "Periodically backup data stored in the cloud. Ensure the confidentiality, integrity and availability of the backup, and verify data restoration from backup for resiliency.", + "Name": "Backup", + "Attributes": [ + { + "Section": "Business Continuity Management and Operational Resilience", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "A1.2", + "A1.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "BCR-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "11.1", + "11.2", + "11.3", + "11.4", + "11.5" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.8", + "5.2.9" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.3", + "27017: 12.3", + "27018: 12.3.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.13", + "27001: A.5.23", + "27001: A.5.30", + "27002: 8.13", + "27002: 5.23 2nd (i)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-4", + "CP-4(4)", + "CP-6", + "CP-6(1)-(3)", + "CP-9", + "CP-9(1)", + "CP-9(2)", + "CP-10", + "CP-10(2)", + "CP-10(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-4", + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01", + "PR.DS-11", + "RC.RP-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "9.5.1", + "12.10.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.10.1", + "10.3.3" + ] + } + ] + } + ], + "Checks": [ + "cloudsql_instance_automated_backups", + "cloudstorage_bucket_versioning_enabled", + "cloudstorage_bucket_soft_delete_enabled" + ] + }, + { + "Id": "BCR-09", + "Description": "Establish, document, approve, communicate, apply, evaluate and maintain a disaster response plan to recover from natural and man-made disasters. Update the plan at least annually or upon significant changes.", + "Name": "Disaster Response Plan", + "Attributes": [ + { + "Section": "Business Continuity Management and Operational Resilience", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "A1.2", + "CC3.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.8", + "5.2.9", + "1.6.1", + "1.6.2", + "1.6.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "BC1.4", + "BC2.1", + "BC2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.29", + "27001: A.5.30", + "27002: 5.29", + "27002: 5.30" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-2(1)", + "CP-2(2)", + "CP-2(3)", + "CP-2(5)", + "CP-2(6)", + "CP-2(7)", + "CP-2(8)", + "PE-13", + "PE-13(1)", + "PE-13(2)", + "PE-13(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-9", + "PR.IP-10", + "RC.IM-1", + "RC.IM-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.IM-04" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "BCR-11", + "Description": "Supplement business-critical equipment with redundant equipment independently located at a reasonable minimum distance in accordance with applicable industry standards.", + "Name": "Equipment Redundancy", + "Attributes": [ + { + "Section": "Business Continuity Management and Operational Resilience", + "CCMLite": "No", + "IaaS": "CSP-Owned", + "PaaS": "CSP-Owned", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "A1.2", + "CC3.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "BCR-06" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.8" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "BC1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.20", + "27001: A.7.11", + "27001: A.8.14", + "27002: 5.20 (t)", + "27002: 8.14 (c)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-2", + "CP-2(2)", + "CP-4(3)", + "CP-6", + "CP-6(1)", + "CP-7", + "CP-8", + "CP-8(1)-(3)", + "CP-9", + "CP-9(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.BE-4", + "ID.BE-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.OC-04", + "GV.OC-05", + "PR.IR-03" + ] + } + ] + } + ], + "Checks": [ + "compute_instance_automatic_restart_enabled", + "compute_instance_group_autohealing_enabled", + "compute_instance_group_load_balancer_attached", + "compute_instance_group_multiple_zones", + "compute_instance_on_host_maintenance_migrate" + ] + }, + { + "Id": "CCC-04", + "Description": "Restrict the unauthorized addition, removal, update, and management of organization assets.", + "Name": "Unauthorized Change Protection", + "Attributes": [ + { + "Section": "Change Control and Configuration Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "CCC-04" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.1", + "1.3.4", + "5.3.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY2.4", + "SM2.6" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.1.4", + "27002: 12.1.4", + "27001: A.12.4.2", + "27002: 12.4.2", + "27001: A.14.2.2", + "27017: 14.2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.3", + "27001: A.8.4", + "27001: A.8.15", + "27001: A.8.31", + "27001: A.8.32" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CA-7", + "CA-7(4)", + "CM-3", + "CM-3(1)", + "CM-3(5)", + "CM-3(7)", + "CM-3(8)", + "CM-5", + "CM-5(1)", + "CM-5(4)", + "CM-5(5)", + "CM-6", + "CM-6(1)", + "CM-6(2)", + "CM-7", + "CM-7(1)", + "CM-7(4)", + "CM-7(5)", + "CM-7(9)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.AM-1", + "ID.AM-2", + "ID.AM-4", + "PR.MA-1", + "PR.MA-2", + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-01", + "ID.AM-02", + "ID.AM-04", + "ID.AM-08", + "PR.PS-02", + "PR.PS-03", + "PR.PS-05", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.4.5.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.5.1", + "6.5.2" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock", + "iam_audit_logs_enabled", + "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", + "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled" + ] + }, + { + "Id": "CCC-07", + "Description": "Implement detection measures with proactive notification in case of changes deviating from the established baseline.", + "Name": "Detection of Baseline Deviation", + "Attributes": [ + { + "Section": "Change Control and Configuration Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC8.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-01" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.5.1", + "1.5.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY2.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.14.2.2", + "27001: A.14.2.4", + "27001: A.12.4.1", + "27002: 12.4.1 (g)", + "27001: A.5.1.1", + "27017: 5.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.9", + "27001: A.8.15", + "27002: 8.9" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-6", + "CM-6(2)", + "SI-2", + "SI-2(2)-(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.MA-1", + "PR.IP-1", + "DE.DP-4", + "PR.IP-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-01", + "DE.CM-09", + "DE.AE-06" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.4.5.3", + "6.4.5.4", + "11.5", + "11.5.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "11.5.2", + "11.6.1" + ] + } + ] + } + ], + "Checks": [ + "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", + "logging_log_metric_filter_and_alert_for_compute_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", + "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled", + "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", + "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", + "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled" + ] + }, + { + "Id": "CEK-03", + "Description": "Provide cryptographic protection to data at-rest and in-transit, using cryptographic libraries certified to approved standards.", + "Name": "Data Encryption", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-03", + "EKM-04" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.6", + "3.1", + "3.11", + "11.3", + "16.11" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1.1", + "27001: A.18.1.2", + "27001: A.18.1.3", + "27001: A.18.1.4", + "27001: A.18.1.5", + "27001: A.10.1", + "27002: 10.1", + "27001: A.13.2.1", + "27002: 13.2.1", + "27001: A.18", + "27002: 18", + "27001: A.14.1.2", + "27002: 14.1.2", + "27001: A.14.1.3", + "27002 14.1.3 c)", + "27001 - A.10.1.1", + "27017 - 10.1.1", + "27001 - A.10.1.2", + "27017 - 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.14", + "27001: A.8.24", + "27002: 8.24 Other Information (a)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-19", + "AC-19(5)", + "SC-8", + "SC-8(1)", + "SC-8(3)", + "SC-8(4)", + "SC-12", + "SC-12(2)", + "SC-12(3)", + "SC-28", + "SC-28(1)-(3)", + "SI-4", + "SI-4(10)", + "SI-7", + "SI-7(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-1", + "PR.DS-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01", + "PR.DS-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "Requirement 3", + "2.2.3", + "2.3", + "3.4", + "3.5.3", + "4.1", + "8.2.1", + "PCI Glossary - Strong Cryptography" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "2.2.7", + "3.5.1", + "4.2.1", + "4.2.1.2", + "4.2.2" + ] + } + ] + } + ], + "Checks": [ + "compute_instance_encryption_with_csek_enabled", + "compute_instance_confidential_computing_enabled", + "bigquery_dataset_cmk_encryption", + "bigquery_table_cmk_encryption", + "cloudsql_instance_ssl_connections", + "dataproc_encrypted_with_cmks_disabled" + ] + }, + { + "Id": "CEK-04", + "Description": "Use encryption algorithms that are appropriate for data protection, considering the classification of data, associated risks, and usability of the encryption technology.", + "Name": "Encryption Algorithm", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-04" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.11" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1.2", + "27001: 6.1.3", + "27001: A.8.2", + "27002: 8.2", + "27001: A.8.3", + "27001: A.10.1.1", + "27002: 10.1.1 (b)", + "27001: A.10.1.2", + "27002: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1.2", + "27001: 6.1.3", + "27001: A.8.24", + "27001: A.5.12", + "27001: A.5.13", + "27002: 8.24 General (b)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-12", + "SC-12(2)", + "SC-12(3)", + "SC-28", + "SC-28(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-1", + "PR.DS-2", + "ID.AM-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01", + "PR.DS-02", + "ID.AM-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "A2", + "Requirement 3", + "2.3", + "2.2.3", + "3.4", + "3.5.3", + "4.1", + "8.2.1", + "PCI Glossary - Strong Cryptography" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "2.2.7", + "3.5.1", + "4.2.1", + "4.2.1.2", + "4.2.2" + ] + } + ] + } + ], + "Checks": [ + "dns_rsasha1_in_use_to_key_sign_in_dnssec", + "dns_rsasha1_in_use_to_zone_sign_in_dnssec" + ] + }, + { + "Id": "CEK-08", + "Description": "CSPs must provide the capability for CSCs to manage their own data encryption keys.", + "Name": "CSC Key Management Capability", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2", + "SC2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1", + "27017: 10.1", + "27001: A.10.1.1", + "27017: 10.1.1", + "27001: A.10.1.2", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.23", + "27001: A.8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-9", + "CP-9(8)", + "SA-9", + "SA-9(6)", + "SC-12", + "SC-12(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.SC-3", + "ID.AM-6", + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.SC-05" + ] + } + ] + } + ], + "Checks": [ + "bigquery_dataset_cmk_encryption", + "bigquery_table_cmk_encryption", + "compute_instance_encryption_with_csek_enabled", + "dataproc_encrypted_with_cmks_disabled", + "kms_key_not_publicly_accessible", + "kms_key_rotation_enabled" + ] + }, + { + "Id": "CEK-10", + "Description": "Generate Cryptographic keys using industry accepted cryptographic libraries specifying the algorithm strength and the random number generator used.", + "Name": "Key Generation", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-04" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.11" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2", + "TS2.3", + "SY1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1.1", + "27002: 10.1.1 (e)", + "27017: 10.1.1", + "27001: A.10.1.2", + "27002: 10.1.2", + "27002: 10.1.2 (a)", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.24", + "27002: 8.24 (d), Key management (a)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-12", + "SC-12(2)", + "SC-12(3)", + "SC-13" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.2.3", + "3.6.1", + "PCI Glossary - Cryptographic Key Generation" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.6.1", + "3.6.1.1", + "3.7.1" + ] + } + ] + } + ], + "Checks": [ + "bigquery_dataset_cmk_encryption", + "bigquery_table_cmk_encryption", + "dataproc_encrypted_with_cmks_disabled" + ] + }, + { + "Id": "CEK-12", + "Description": "Rotate cryptographic keys in accordance with the calculated cryptoperiod, which includes provisions for considering the risk of information disclosure and legal and regulatory requirements.", + "Name": "Key Rotation", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1.1", + "27017: 10.1.1", + "27001: A.10.1.2", + "27002: 10.1.2 e)", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.31", + "27001: A.8.24", + "27002: 5.31 Cryptography", + "27002: 8.24 Key management (e,m)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-12", + "SC-12(2)", + "SC-12(3)", + "SC-13" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "ID.GV-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-05", + "GV.OC-03" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.7.4", + "3.7.5" + ] + } + ] + } + ], + "Checks": [ + "kms_key_rotation_enabled", + "iam_sa_user_managed_key_rotate_90_days", + "apikeys_key_rotated_in_90_days" + ] + }, + { + "Id": "CEK-14", + "Description": "Define, implement and evaluate processes, procedures and technical measures to destroy keys stored outside a secure environment and revoke keys stored in Hardware Security Modules (HSMs) when they are no longer needed, which include provisions for legal and regulatory requirements.", + "Name": "Key Destruction", + "Attributes": [ + { + "Section": "Cryptography, Encryption & Key Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1.1", + "27017: 10.1.1", + "27017: 10.1.2", + "27001: A.10.1.2", + "27002: 10.1.2 (j)", + "27001: A.18.1.3", + "27002: 18.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.31", + "27001: A.8.24", + "27002: 5.31 Cryptography", + "27002: 8.24 Key management (j,m)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-12", + "SC-12(2)", + "SC-12(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.IP-6", + "ID.GV-3", + "PR.DS-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-05", + "ID.AM-08", + "GV.OC-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.6.4", + "3.6.5" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.7.4", + "3.7.5" + ] + } + ] + } + ], + "Checks": [ + "iam_role_kms_enforce_separation_of_duties" + ] + }, + { + "Id": "DCS-06", + "Description": "Catalogue and track all relevant physical and logical assets located at all of the CSP's sites within a secured system.", + "Name": "Assets Cataloguing and Tracking", + "Attributes": [ + { + "Section": "Datacenter Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "DCS - 01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "1.1", + "2.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.3.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SM2.6" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.8.1.1", + "27002: 8.1.1", + "27017: 8.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.9" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-8", + "CM-8(1)", + "CM-8(2)", + "CM-8(4)", + "CM-8(7)", + "CM-8(8)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.AM-1", + "ID.AM-2", + "ID.AM-4", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-01", + "ID.AM-02", + "ID.AM-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.4", + "9.7.1", + "9.9.1", + "9.9.1.a", + "9.9.1.b", + "9.9.1.c", + "12.3.3", + "12.3.4" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.6.1.1", + "6.3.2", + "9.4.2", + "9.4.3", + "12.5.1" + ] + } + ] + } + ], + "Checks": [ + "iam_cloud_asset_inventory_enabled" + ] + }, + { + "Id": "DSP-02", + "Description": "Apply industry accepted methods for the secure disposal of data from storage media such that data is not recoverable by any forensic means.", + "Name": "Secure Disposal", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2", + "CC6.3", + "CC6.4", + "CC6.5", + "CC6.7", + "P4.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "DSI-07" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.5" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.3.3", + "7.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.1", + "IM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.8.3.2", + "27002: 8.3.2", + "27001: A.11.2.7", + "27002: 11.2.7" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.7.10", + "27001: A.7.14", + "27001: A.8.10", + "27002: 7.10 (Secure reuse or disposal)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PM-22", + "SI-12", + "SI-12(3)", + "SI-18", + "SI-18(1)", + "SI-18(4)", + "SI-18(5)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-6" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.SC-10", + "PR.PS-02", + "PR.PS-03", + "ID.AM-08" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.1", + "9.8", + "9.8.1", + "9.8.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.2.1", + "3.7.5", + "9.4.7" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_lifecycle_management_enabled" + ] + }, + { + "Id": "DSP-03", + "Description": "Create and maintain a data inventory, at least for any sensitive data and personal data.", + "Name": "Data Inventory", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.3.1", + "1.3.2", + "1.3.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.1", + "IM2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.8.1.1", + "27002: 8.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.9", + "27001: A.8.12" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-12", + "CM-12(1)", + "PM-5", + "PM-5(1)", + "SI-12", + "SI-12(1)", + "SI-19", + "SI-19(1)", + "SI-19(2)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.AM-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-07" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.2.1", + "9.4.5" + ] + } + ] + } + ], + "Checks": [ + "iam_cloud_asset_inventory_enabled", + "iam_audit_logs_enabled" + ] + }, + { + "Id": "DSP-04", + "Description": "Classify data according to its type and sensitivity level.", + "Name": "Data Classification", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "C1.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "DSI-01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.7" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.3.1", + "1.3.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.8.2.1", + "27002: 8.2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.12" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-16", + "AC-16(9)", + "PM-22", + "PM-23", + "PT-2", + "PT-2(1)", + "SI-18", + "SI-18(2)", + "SI-19", + "SI-19(6)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.AM-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-05", + "ID.AM-07" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "9.6.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "9.4.2", + "9.4.3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "DSP-07", + "Description": "Develop systems, products, and business practices based upon a principle of security by design and industry best practices.", + "Name": "Data Protection by Design and Default", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "PI1.2", + "PI1.3" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "16.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.3.1", + "5.3.2", + "5.3.3", + "5.3.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SD2.2", + "IM1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.14.1.1", + "27002:14.1.1", + "27001: A.14.2.5", + "27002:14.2.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.27", + "27001: A.8.28", + "27001: A.8.29", + "27002: 5.8 (Information security requirements a-i)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PM-17", + "PM-24", + "PM-25", + "PT-2", + "PT-2(2)", + "SA-3", + "SA-4", + "SA-5", + "SA-8", + "SA-8(9)", + "SA-8(13)", + "SA-8(18)", + "SA-8(20)", + "SA-8(22)", + "SA-8(23)", + "SA-8(33)", + "SA-15", + "SA-15(12)", + "SC-3", + "SC-3(3)", + "SC-7", + "SC-7(24)", + "SC-8", + "SC-8(1)-(4)", + "SC-28", + "SC-28(1)", + "SI-12", + "SI-12(1)-(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-2", + "PR.PT-3", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "PR.PS-06" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.2.1" + ] + } + ] + } + ], + "Checks": [ + "bigquery_dataset_public_access", + "cloudsql_instance_public_access", + "cloudsql_instance_public_ip", + "cloudstorage_bucket_public_access", + "compute_image_not_publicly_shared", + "compute_instance_public_ip", + "kms_key_not_publicly_accessible" + ] + }, + { + "Id": "DSP-10", + "Description": "Define, implement and evaluate processes, procedures and technical measures that ensure any transfer of personal or sensitive data is protected from unauthorized access and only processed within scope as permitted by the respective laws and regulations.", + "Name": "Sensitive Data Transfer", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-02", + "EKM-03" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.1", + "3.12", + "3.13" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.2", + "9.5.1", + "9.5.2", + "9.5.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.4", + "IM2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.13.2.1", + "27002: 13.2.1", + "27001: A.8.3.3", + "27002: 8.3.3", + "27001: A.13.2.3", + "27002: 13.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.14", + "27001: A.7.10" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-4", + "AC-4(23)-(25)", + "CA-3", + "CA-3(6)", + "CA-6", + "CA-6(1)", + "CA-6(2)", + "SC-4", + "SC-4(2)", + "SC-7", + "SC-7(10)", + "SC-7(24)", + "SC-8", + "SC-8(1)-(5)", + "SC-16", + "SC-16(1)-(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-2", + "PR.DS-5", + "PR.PT-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-02", + "PR.IR-01", + "ID.AM-03", + "GV.OC-03", + "ID.AM-07" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "4.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "4.1.1", + "4.2.1", + "4.2.2" + ] + } + ] + } + ], + "Checks": [ + "cloudsql_instance_ssl_connections" + ] + }, + { + "Id": "DSP-16", + "Description": "Data retention, archiving and deletion is managed in accordance with business requirements, applicable laws and regulations.", + "Name": "Data Retention and Deletion", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "C1.1", + "C1.2", + "CC3.1", + "P4.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-02", + "BCR-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.4", + "3.5" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.3.1", + "7.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.1", + "IM2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.33", + "27001: A.8.10", + "27002: 5.33 (b)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SI-12", + "SI-12(1)-(3)", + "SI-18", + "SI-18(1)", + "SI-18(4)", + "SI-18(5)", + "SI-19", + "SI-19(2)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-3", + "PR.IP-6", + "ID.GV-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-08", + "GV.OC-03", + "GV.SC-10", + "PR.DS-11" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.2.1" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_lifecycle_management_enabled", + "cloudstorage_bucket_sufficient_retention_period" + ] + }, + { + "Id": "DSP-17", + "Description": "Define and implement, processes, procedures and technical measures to protect sensitive data throughout it's lifecycle.", + "Name": "Sensitive Data Protection", + "Attributes": [ + { + "Section": "Data Security and Privacy Lifecycle Management", + "CCMLite": "Yes", + "IaaS": "CSP-Owned", + "PaaS": "CSP-Owned", + "SaaS": "CSC-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC2.1", + "CC6.1", + "CC6.3", + "CC6.7", + "CC8.1", + "C1.1", + "P2.0", + "P3.0", + "P4.0", + "P5.0", + "P6.0" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.1", + "3.1", + "3.14" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.3.3", + "9.1.1", + "9.2.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.1", + "IM2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1.3", + "27002: 18.1.3", + "27001:A.18.1.4", + "27002:18.1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.11", + "27001: A.8.12" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PL-2", + "PM-22", + "PM-24", + "PT-7", + "PT-7(1)", + "PT-7(2)", + "PT-8", + "SC-8", + "SC-8(1)-(5)", + "SC-28", + "SC-28(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-1", + "PR.DS-2", + "PR.DS-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01", + "PR.DS-02", + "PR.DS-10" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.0 (including all subsections)", + "4.0 (including all subsections)" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.1.1", + "4.1.1" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_public_access", + "bigquery_dataset_public_access", + "cloudsql_instance_public_access", + "cloudsql_instance_public_ip", + "compute_instance_public_ip", + "compute_image_not_publicly_shared", + "kms_key_not_publicly_accessible" + ] + }, + { + "Id": "GRC-05", + "Description": "Develop and implement an Information Security Program, which includes programs for all the relevant domains of the CCM.", + "Name": "Information Security Program", + "Attributes": [ + { + "Section": "Governance, Risk and Compliance", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-04" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "14.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SG2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 4.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 4.3" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PM-1", + "PM-3", + "PM-14", + "PL-2", + "PM-18", + "PM-31" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "12.4.1", + "A.3.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.4.1", + "A3.1.1" + ] + } + ] + } + ], + "Checks": [ + "iam_account_access_approval_enabled", + "iam_audit_logs_enabled", + "iam_organization_essential_contacts_configured" + ] + }, + { + "Id": "IAM-02", + "Description": "Establish, document, approve, communicate, implement, apply, evaluate and maintain strong password policies and procedures. Review and update the policies and procedures at least annually.", + "Name": "Strong Password Policy and Procedures", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-02", + "IAM-12", + "GRM-06", + "GRM-09" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.1.1", + "1.5.1", + "4.1.2", + "4.1.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.1", + "SA1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 5.1", + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: 9.1", + "27001: 9.3", + "27001: A.5", + "27002: 5", + "27001: A.9.4.3", + "27002: 9.4.3", + "27017: 9.4.3", + "27018: 9.4.3", + "27001: A.9.2.4", + "27002: 9.2.4", + "27017: 9.2.4", + "27001: A.7.2.2", + "27002: 7.2.2", + "27001: A.9.2.6", + "27002: 9.2.6", + "27001: A.9.2.3", + "27002: 9.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 5.1", + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: 9.1", + "27001: 9.3", + "27001: A.5.1", + "27001: A.5.4", + "27001: A.5.17", + "27001: A.6.3", + "27001: A.8.5", + "27001: A.5.37" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(3)", + "AC-2(11)", + "AC-3", + "AC-3(3)", + "AC-12", + "AC-12(1)", + "IA-2", + "IA-2(10)", + "IA-5", + "IA-5(1)", + "IA-5(18)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-1", + "PR.AC-1", + "PR.AC-7" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.PO-01", + "GV.PO-02", + "ID.IM-03", + "PR.AA-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.4", + "12.1", + "12.1.1", + "12.11" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "8.1.1", + "8.3.8" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "IAM-03", + "Description": "Manage, store, and review the information of system identities, and level of access.", + "Name": "Identity Inventory", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-04", + "IAM-08", + "IAM-10" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.1", + "5.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.3", + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 9.2 (c)", + "27001: A.8.1.1", + "27002: 8.1.1", + "27001: A.9.4.1", + "27002: 9.4.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 9.2 (c)", + "27001: A.5.15", + "27001: A.5.16", + "27001: A.5.18", + "27001: A.7.4", + "27001: A.8.15", + "27001: A.8.2", + "27001: A.8.3" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-10", + "AU-10(1)", + "AU-10(2)", + "AU-16", + "AU-16(1)", + "IA-4", + "IA-4(8)", + "IA-4(9)", + "IA-5", + "IA-5(5)", + "IA-8", + "IA-8(4)", + "PM-5(1)", + "SA-8", + "SA-8(22)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-6", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-02", + "PR.AA-04", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.4.a" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.5", + "7.2.5.1" + ] + } + ] + } + ], + "Checks": [ + "iam_sa_user_managed_key_unused", + "iam_service_account_unused" + ] + }, + { + "Id": "IAM-04", + "Description": "Employ the separation of duties principle when implementing information system access.", + "Name": "Separation of Duties", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC1.3", + "CC5.1", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-05" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "6.8" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.2.2", + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.6.1.2", + "27002: 6.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.15", + "27001: A.5.18", + "27001: A.5.3", + "27001: A.8.2" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(3)", + "AC-2(11)", + "AC-6", + "AC-6(1)-(10)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.4", + "6.4.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.5.3", + "6.5.4", + "7.2.1", + "7.2.2" + ] + } + ] + } + ], + "Checks": [ + "iam_role_sa_enforce_separation_of_duties", + "iam_role_kms_enforce_separation_of_duties", + "iam_no_service_roles_at_project_level" + ] + }, + { + "Id": "IAM-05", + "Description": "Employ the least privilege principle when implementing information system access.", + "Name": "Least Privilege", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-02", + "IAM-06", + "IVS-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "6.8" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.1.1", + "27002: 9.1.1", + "27001: A.9.1.2", + "27002: 9.1.2", + "27001: A.9.2.3", + "27002: 9.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.15", + "27001: A.8.2", + "27002: 5.15 (Other information 2nd (a))" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-6", + "AC-6(4)", + "IA-12", + "IA-12(2)", + "IA-12(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "7.1", + "7.1.1", + "7.1.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.1", + "7.2.2", + "7.2.5", + "7.2.6" + ] + } + ] + } + ], + "Checks": [ + "apikeys_api_restrictions_configured", + "compute_instance_default_service_account_in_use", + "compute_instance_default_service_account_in_use_with_full_api_access", + "gke_cluster_no_default_service_account", + "iam_no_service_roles_at_project_level", + "iam_sa_no_administrative_privileges" + ] + }, + { + "Id": "IAM-07", + "Description": "De-provision or respectively modify access of movers / leavers or system identity changes in a timely manner in order to effectively adopt and communicate identity and access management policies.", + "Name": "User Access Changes and Revocation", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC5.3", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.3", + "6.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.15", + "27001: A.5.18" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(1)", + "AC-2(2)", + "AC-2(6)", + "AC-2(8)", + "AC-3", + "AC-3(8)", + "AC-6", + "AC-6(7)", + "AU-10", + "AU-10(4)", + "AU-16", + "AU-16(1)", + "CM-7", + "CM-7(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-4", + "PR.IP-11" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.RR-04", + "GV.SC-10", + "PR.AA-01", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.1.2", + "8.1.3" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "8.2.5", + "8.2.6" + ] + } + ] + } + ], + "Checks": [ + "iam_sa_user_managed_key_unused", + "iam_service_account_unused" + ] + }, + { + "Id": "IAM-08", + "Description": "Review and revalidate user access for least privilege and separation of duties with a frequency that is commensurate with organizational risk tolerance.", + "Name": "User Access Review", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.2", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-10" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.5", + "27001: A.9.2.6", + "27001: A.9.4.1", + "27017: 9.4.1", + "27001: A.6.1.2", + "27001: A 9.2.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.3", + "27001: A.5.18", + "27001: A.8.3" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-6", + "AC-6(4)", + "AC-6(8)", + "IA-8", + "IA-8(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "12.5.5" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.5.1", + "7.2.5", + "7.2.4" + ] + } + ] + } + ], + "Checks": [ + "iam_sa_user_managed_key_unused", + "iam_service_account_unused", + "iam_sa_user_managed_key_rotate_90_days" + ] + }, + { + "Id": "IAM-09", + "Description": "Define, implement and evaluate processes, procedures and technical measures for the segregation of privileged access roles such that administrative access to data, encryption and key management capabilities and logging capabilities are distinct and separated.", + "Name": "Segregation of Privileged Access Roles", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC5.1", + "CC6.1", + "CC6.3" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.3", + "27002: 9.2.3", + "27017: 9.2.3", + "27018: 9.2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.2", + "27001: A.8.18", + "27002: 8.2 (j)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-6", + "AC-3(7)", + "AC-6(4)", + "AC-6(8)", + "IA-5", + "IA-5(6)", + "IA-8", + "IA-8(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.3", + "3.5.2", + "7.1.2", + "7.1.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.6.1", + "3.7.6", + "6.5.3", + "6.5.4", + "7.2.1", + "7.2.2", + "10.3.1" + ] + } + ] + } + ], + "Checks": [ + "iam_role_kms_enforce_separation_of_duties", + "iam_role_sa_enforce_separation_of_duties", + "iam_sa_no_administrative_privileges" + ] + }, + { + "Id": "IAM-10", + "Description": "Define and implement an access process to ensure privileged access roles and rights are granted for a time limited period, and implement procedures to prevent the culmination of segregated privileged access.", + "Name": "Management of Privileged Access Roles", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2", + "CC6.3" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.1", + "6.5" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.3", + "27002: 9.2.3", + "27017: 9.2.3", + "27018: 9.2.3", + "27001: A.9.4.4", + "27002: 9.4.4", + "27017: 9.4.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.2", + "27001: A.8.18", + "27002: 8.2 (i)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(7)", + "AC-3", + "AC-3(4)", + "AC-3(11)", + "AC-3(13)", + "AC-3(14)", + "AC-6", + "AC-6(4)", + "AC-6(5)", + "AC-6(8)", + "AC-12", + "AC-12(3)", + "AC-17", + "AC-17(4)", + "IA-8", + "IA-8(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "7.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.1", + "7.2.2" + ] + } + ] + } + ], + "Checks": [ + "iam_no_service_roles_at_project_level", + "iam_role_kms_enforce_separation_of_duties", + "iam_role_sa_enforce_separation_of_duties", + "iam_sa_no_administrative_privileges" + ] + }, + { + "Id": "IAM-12", + "Description": "Define, implement and evaluate processes, procedures and technical measures to ensure the logging infrastructure is read-only for all with write access, including privileged access roles, and that the ability to disable it is controlled through a procedure that ensures the segregation of duties and break glass procedures.", + "Name": "Safeguard Logs Integrity", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.3" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.1", + "27002: 12.4.1", + "27017: 12.4.1", + "27018: 12.4.1", + "27001: A.12.4.2", + "27002: 12.4.2", + "27017: 12.4.2", + "27018: 12.4.2", + "27001: A.12.4.3", + "27002: 12.4.3", + "27017: 12.4.3", + "27018: 12.4.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.15", + "27001: A.8.18", + "27002: 8.15 Protection of Logs" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-2", + "AC-2(11)", + "AC-2(12)", + "IA-8", + "IA-8(4)", + "SA-8", + "SA-8(22)", + "SC-34", + "SC-34(1)", + "SC-34(2)", + "SC-36", + "SI-4", + "SI-4(5)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.5" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.3.1", + "10.3.2", + "10.3.3", + "10.3.4" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock", + "cloudstorage_bucket_logging_enabled", + "logging_sink_created" + ] + }, + { + "Id": "IAM-13", + "Description": "Define, implement and evaluate processes, procedures and technical measures that ensure users are identifiable through unique IDs or which can associate individuals to the usage of user IDs.", + "Name": "Uniquely Identifiable Users", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.1", + "27002: 9.2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.16" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-3", + "AC-3(14)", + "AC-24", + "AC-24(2)", + "AU-10", + "AU-10(1)", + "IA-2", + "IA-2(1)", + "IA-2(2)", + "IA-2(12)", + "IA-4", + "IA-4(1)", + "SA-8", + "SA-8(22)", + "SC-23", + "SC-23(3)", + "SC-40(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-6" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.1", + "8.2", + "8.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "8.2.1", + "8.2.2", + "8.2.4" + ] + } + ] + } + ], + "Checks": [ + "compute_project_os_login_enabled" + ] + }, + { + "Id": "IAM-14", + "Description": "Define, implement and evaluate processes, procedures and technical measures for authenticating access to systems, application and data assets, including multifactor authentication for at least privileged user and sensitive data access. Adopt digital certificates or alternatives which achieve an equivalent level of security for system identities.", + "Name": "Strong Authentication", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-02", + "IAM-05" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "6.3", + "6.5", + "12.5", + "12.7" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3", + "SA1.4", + "SA1.8" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.1.2", + "27002: 9.1.2", + "27017: 9.1.2", + "27001: A.9.2.4", + "27002: 9.2.4", + "27017: 9.2.4", + "27001: A.9.4.2", + "27002: 9.4.2", + "27017: 9.4.2", + "27018: 9.4.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.15", + "27001: A.5.17", + "27001: A.8.5", + "27001: A.8.24", + "27002: 8.5", + "27002: 8.24 other information (d)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-6", + "AC-6(5)", + "AC-7", + "AC-7(4)", + "AU-10", + "AU-10(2)", + "IA-2", + "IA-2(1)", + "IA-2(2)", + "IA-2(8)", + "IA-2(12)", + "IA-3", + "IA-3(1)", + "IA-5", + "IA-5(2)", + "IA-5(7)", + "IA-5(9)", + "IA-5(10)", + "IA-5(12)", + "IA-5(14)-(16)", + "IA-8", + "IA-8(1)", + "IA-8(6)", + "SC-23", + "SC-23(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-6", + "PR.AC-7" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-02", + "PR.AA-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.1.2", + "8.1.3", + "8.1.6", + "8.2", + "8.3", + "8.3.2", + "12.3.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.1", + "8.3.1", + "8.3.2", + "8.4.1", + "8.4.2", + "8.4.3" + ] + } + ] + } + ], + "Checks": [ + "compute_project_os_login_2fa_enabled", + "compute_project_os_login_enabled" + ] + }, + { + "Id": "IAM-15", + "Description": "Define, implement and evaluate processes, procedures and technical measures for the secure management of passwords.", + "Name": "Passwords Management", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.4", + "27002: 9.2.4", + "27017: 9.2.4", + "27018: 9.2.4", + "27001: A.9.3.1", + "27002: 9.3.1", + "27017: 9.3.1", + "27018: 9.3.1", + "27001: A.9.4.3", + "27002: 9.4.3", + "27017: 9.4.3", + "27018: 9.4.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.17" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "IA-4", + "IA-4(8)", + "IA-5", + "IA-5(1)", + "IA-5(8)", + "IA-5(18)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "8.2", + "8.2.1-6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "2.2.2", + "2.3.1", + "8.3.5", + "8.3.6", + "8.3.7", + "8.3.8", + "8.3.9", + "8.3.10", + "8.3.10.1", + "8.6.2" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "IAM-16", + "Description": "Define, implement and evaluate processes, procedures and technical measures to verify access to data and system functions is authorized.", + "Name": "Authorization Mechanisms", + "Attributes": [ + { + "Section": "Identity & Access Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.2", + "CC6.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IAM-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "5.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SA1.3", + "SA1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.9.2.5", + "27002: 9.2.5", + "27017: 9.2.5", + "27018: 9.2.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.18" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-3", + "AC-3(5)", + "AC-4", + "AC-4(17)", + "AC-4(21)", + "AC-4(22)", + "AC-6", + "AC-6(8)", + "AC-6(9)", + "AC-12", + "AC-12(1)", + "AC-20", + "AC-20(1)", + "AU-10", + "AU-10(1)", + "AU-10(2)", + "IA-2", + "IA-2(1)", + "IA-2(2)", + "IA-2(12)", + "IA-3", + "IA-3(1)", + "IA-5(1)", + "IA-5(2)", + "IA-5(5)", + "IA-5(8)", + "IA-5(10)", + "IA-5(12)", + "IA-8", + "IA-8(1)", + "IA-8(2)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-4", + "PR.AC-6", + "PR.AC-7", + "PR.PT-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-01", + "PR.AA-02", + "PR.AA-03", + "PR.AA-04", + "PR.AA-05", + "PR.PS-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "5.3", + "7.1.4" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "7.2.4", + "7.2.3", + "7.2.5.1" + ] + } + ] + } + ], + "Checks": [ + "apikeys_api_restrictions_configured", + "cloudstorage_bucket_uniform_bucket_level_access", + "compute_instance_default_service_account_in_use_with_full_api_access", + "iam_sa_no_administrative_privileges" + ] + }, + { + "Id": "IPY-03", + "Description": "Implement cryptographically secure and standardized network protocols for the management, import and export of data.", + "Name": "Secure Interoperability and Portability Management", + "Attributes": [ + { + "Section": "Interoperability & Portability", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IPY-04" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1", + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY1.1", + "SY1.2", + "NC1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1", + "27001: A.15.1.1", + "27002: 15.1.1", + "27017: 15.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.19", + "27001: A.5.23", + "27001: A.5.31", + "27001: A.5.32", + "27001: A.5.33", + "27001: A.5.34" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PT-2", + "PT-2(2)", + "SA-4", + "SC-16", + "SC-16(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-02" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "1.2.1", + "1.2.5", + "1.2.6", + "2.2.4", + "2.2.5", + "2.2.7", + "4.2.1" + ] + } + ] + } + ], + "Checks": [ + "cloudsql_instance_ssl_connections" + ] + }, + { + "Id": "IVS-02", + "Description": "Plan and monitor the availability, quality, and adequate capacity of resources in order to deliver the required system performance as determined by the business.", + "Name": "Capacity and Resource Planning", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "No", + "IaaS": "CSP-Owned", + "PaaS": "CSP-Owned", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "A1.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-04" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 5.3", + "27001: 6.1", + "27001: 9.1", + "27001: A.12.1.3", + "27002: 12.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 5.3 (b)", + "27001: 6.1", + "27001: 9.1", + "27001: A.8.6", + "27001: A.8.14" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CP-2", + "CP-2(2)", + "SC-5", + "SC-5(2)", + "SC-4", + "SI-4" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-4", + "ID.BE-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.IR-04", + "GV.OC-04" + ] + } + ] + } + ], + "Checks": [ + "compute_instance_group_autohealing_enabled", + "compute_instance_group_load_balancer_attached", + "compute_instance_group_multiple_zones" + ] + }, + { + "Id": "IVS-03", + "Description": "Monitor, encrypt and restrict communications between environments to only authenticated and authorized connections, as justified by the business. Review these configurations at least annually, and support them by a documented justification of all allowed services, protocols, ports, and compensating controls.", + "Name": "Network Security", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-06" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.8", + "3.1", + "12.2", + "13.6", + "13.9" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.2", + "5.2.7" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "NC1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 7.5", + "27001: 9.1", + "27001: A.13.1.1", + "27002: 13.1.1", + "27001: A.13.1.2", + "27002: 13.1.2", + "27001: A.13.1.3", + "27002: 13.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 7.5", + "27001: 9.1", + "27001: A.5.15", + "27001: A.5.37", + "27001: A.8.5", + "27001: A.8.9", + "27001: A.8.16", + "27001: A.8.20", + "27001: A.8.21", + "27001: A.8.22", + "27001: A.8.24", + "27002: A.5.15 2nd c)", + "27002: 8.20", + "27002: 8.21", + "27002: 8.22", + "27002: 8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-1", + "SC-4", + "SC-7", + "SC-7(4)", + "SC-7(5)", + "SC-7(8)", + "SC-7(9)", + "SC-7(11)", + "SC-8", + "SC-8(1)", + "SC-11", + "SC-12", + "SC-16", + "SC-23", + "SC-29", + "SC-29(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-5", + "PR.AC-7", + "PR.PT-4", + "DE.CM-1", + "DE.CM-7", + "PR.DS-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.IR-01", + "PR.AA-03", + "PR.AA-05", + "DE.CM-01", + "PR.DS-02", + "ID.AM-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "1.1.6", + "1.2", + "1.2.3", + "2.2", + "4.1.1", + "10.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "1.2.5", + "1.2.6", + "1.2.7", + "1.4.2", + "2.2.4", + "2.2.5", + "2.2.7", + "4.2.1", + "10.1.1" + ] + } + ] + } + ], + "Checks": [ + "compute_firewall_rdp_access_from_the_internet_allowed", + "compute_firewall_ssh_access_from_the_internet_allowed", + "compute_instance_ip_forwarding_is_enabled", + "compute_network_default_in_use", + "compute_network_dns_logging_enabled", + "compute_network_not_legacy", + "compute_subnet_flow_logs_enabled" + ] + }, + { + "Id": "IVS-04", + "Description": "Harden host and guest OS, hypervisor or infrastructure control plane according to their respective best practices, and supported by technical controls, as part of a security baseline.", + "Name": "OS Hardening and Base Controls", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "CSP-Owned", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.8", + "CC7.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-07", + "IVS-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "4.1", + "4.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.1.3", + "5.2.5" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SY1.1", + "SY1.3", + "SY1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 7.5", + "27001: 9.1", + "27001: A.14.2.2", + "27002: 14.2.2", + "27001: A.14.2.3", + "27001 A.14.2.4", + "27018: 12.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 7.5", + "27001: 9.1", + "27001: A.5.37", + "27001: A.8.5", + "27001: A.8.9", + "27001: A.8.16", + "27001: A.8.20", + "27001: A.8.22", + "27001: A.8.24", + "27002: 8.20", + "27002: 8.22", + "27002: 8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-6", + "CM-6(1)", + "SC-29", + "SC-29(1)", + "SC-2", + "SC-7", + "SC-7(12)", + "SC-30", + "SC-34", + "SC-35", + "SC-39", + "SC-44" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.IP-1", + "PR.PT-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "2.2.1" + ] + } + ] + } + ], + "Checks": [ + "compute_instance_shielded_vm_enabled", + "compute_project_os_login_enabled", + "compute_instance_serial_ports_in_use", + "compute_instance_block_project_wide_ssh_keys_disabled" + ] + }, + { + "Id": "IVS-06", + "Description": "Design, develop, deploy and configure applications and infrastructures such that CSP and CSC (tenant) user access and intra-tenant access is appropriately segmented and segregated, monitored and restricted from other tenants.", + "Name": "Segmentation and Segregation", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-09" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1", + "5.3.4", + "5.2.7" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SC2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 9.1", + "27001: A.13.1.3", + "27002: 13.1.3", + "27017: 13.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 9.1", + "27001: A.5.15", + "27001: A.5.20", + "27001: A.8.3", + "27001: A.8.9", + "27001: A.8.16", + "27001: A.8.22", + "27002: 5.15 (b)", + "27002: 8.3 (b)", + "27002: 8.16 (b)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-3", + "SC-7", + "SC-7(20)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4", + "PR.AC-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05", + "PR.IR-01", + "PR.PS-01", + "PR.PS-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "2.6", + "8.3.1", + "10.8", + "11.3", + "A3.2.1", + "A3.3.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "A1.1.1", + "A1.1.2", + "A1.1.3" + ] + } + ] + } + ], + "Checks": [ + "cloudsql_instance_private_ip_assignment", + "cloudstorage_uses_vpc_service_controls", + "compute_instance_public_ip", + "compute_network_default_in_use", + "compute_network_not_legacy" + ] + }, + { + "Id": "IVS-07", + "Description": "Use secure and encrypted communication channels when migrating servers, services, applications, or data to cloud environments. Such channels must include only up-to-date and approved protocols.", + "Name": "Migration to Cloud Environments", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-10" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.4", + "IM1.4", + "NC1.4", + "SC2.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.13.1.1", + "27002: 13.1.1", + "27017: 13.1.1", + "27018: 13.1.1", + "27001: A.13.1.2", + "27002: 13.1.2", + "27017: 13.1.2", + "27018: 13.1.2", + "27001: A.13.1.3", + "27002: 13.1.3", + "27017: 13.1.3", + "27018: 13.1.3", + "27001: A.13.2.1", + "27002: 13.2.1", + "27017: 13.2.1", + "27018: 13.2.1", + "27001: A.13.2.2", + "27002: 13.2.2", + "27017: 13.2.2", + "27018: 13.2.2", + "27001: A.13.2.3", + "27002: 13.2.3", + "27017: 13.2.3", + "27018: 13.2.3", + "27001: A.13.2.4", + "27002: 13.2.4", + "27017: 13.2.4", + "27018: 13.2.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.14", + "27001: A.8.20", + "27001: A.8.24", + "27002: 8.20 (e)", + "27002: 8.24 Guidance (b,f), other information (a)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-17", + "AC-20", + "SC-7", + "SC-7(28)", + "SC-8", + "SC-8(1)", + "SC-12", + "SC-23", + "SC-29", + "SI-7", + "SI-7(1)-(3)", + "SI-7(5)-(10)", + "SI-7(12)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-2", + "PR.PT-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-02" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "4.2.1" + ] + } + ] + } + ], + "Checks": [ + "cloudsql_instance_ssl_connections" + ] + }, + { + "Id": "IVS-09", + "Description": "Define, implement and evaluate processes, procedures and defense-in-depth techniques for protection, detection, and timely response to network-based attacks.", + "Name": "Network Defense", + "Attributes": [ + { + "Section": "Infrastructure & Virtualization Security", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.6", + "CC6.8", + "CC7.1", + "CC7.2", + "CC7.5" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-13" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "13.3", + "13.8" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.3", + "5.2.4", + "5.2.5", + "5.2.7", + "5.3.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "NC1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1", + "27001: 6.2", + "27001: A.14.1.2", + "27002: 14.1.2", + "27017: 14.1.2", + "27001: A.11.1.4", + "27002: 11.1.4", + "27017: 11.1.4", + "27018: 16.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1", + "27001: 6.2", + "27001: A.5.24", + "27001: A.5.26", + "27001: A.8.8", + "27001: A.8.16", + "27001: A.8.20", + "27001: A.8.21", + "27001: A.8.22", + "27001: A.8.26", + "27002: 8.8 (i)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PL-8", + "PL-8(1)", + "SC-5", + "SC-5(1)", + "SC-5(3)", + "SC-7", + "SC-7(13)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.AE-1", + "DE.DP-1", + "DE.CM-1", + "DE.CM-7", + "PR.AC-5", + "RS.MI-2", + "PR.DS-2", + "RS.RP-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-03", + "DE.CM-01", + "PR.IR-01", + "RS.MA-01", + "RS.MI-01", + "RS.MI-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.6", + "1.1", + "1.2", + "1.3", + "1.5", + "12.10.5" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "1.1.1", + "1.3.1", + "1.3.2", + "1.3.3", + "1.4.1", + "1.4.2", + "1.4.3", + "1.4.4", + "1.4.5", + "1.5.1", + "12.10.1" + ] + } + ] + } + ], + "Checks": [ + "compute_firewall_rdp_access_from_the_internet_allowed", + "compute_firewall_ssh_access_from_the_internet_allowed", + "compute_loadbalancer_logging_enabled", + "compute_public_address_shodan", + "dns_dnssec_disabled" + ] + }, + { + "Id": "LOG-02", + "Description": "Define, implement and evaluate processes, procedures and technical measures to ensure the security and retention of audit logs.", + "Name": "Audit Logs Protection", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.1", + "8.9", + "8.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "3.1.3", + "5.1.2", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.18.1.3", + "27002: 18.1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.28", + "27001: A.5.33", + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-4", + "AU-11" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4", + "PR.IP-4", + "PR.IP-6", + "PR.PT-1", + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05", + "PR.DS-01", + "PR.DS-02", + "ID.AM-08", + "PR.DS-11", + "PR.PS-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.5", + "10.7" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.3.1", + "10.3.2", + "10.3.3", + "10.3.4", + "10.5.1" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock", + "cloudstorage_bucket_logging_enabled", + "logging_sink_created" + ] + }, + { + "Id": "LOG-03", + "Description": "Identify and monitor security-related events within applications and the underlying infrastructure. Define and implement a system to generate alerts to responsible stakeholders based on such events and corresponding metrics.", + "Name": "Security Monitoring and Alerting", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.8", + "CC7.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "SEF-03", + "SEF-05" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.5" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.4", + "5.2.7", + "1.6.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2", + "TM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.1", + "27002: 12.4.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.28", + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-5", + "AU-5(2)", + "AU-13" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.AE-1", + "DE.AE-2", + "DE.AE-3", + "DE.AE-5", + "DE.CM-1", + "DE.CM-2", + "DE.CM-3", + "DE.CM-4", + "DE.CM-5", + "DE.CM-6", + "DE.CM-7", + "DE.DP-1", + "DE.DP-4", + "DE.AE-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.AE-02", + "DE.AE-03", + "DE.AE-04", + "DE.AE-06", + "DE.AE-07", + "DE.AE-08", + "DE.CM-01", + "DE.CM-02", + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.2.1", + "10.2.2", + "10.4.1.1", + "10.4.2.1", + "10.4.3" + ] + } + ] + } + ], + "Checks": [ + "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", + "logging_log_metric_filter_and_alert_for_compute_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", + "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled", + "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", + "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", + "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled" + ] + }, + { + "Id": "LOG-04", + "Description": "Restrict audit logs access to authorized personnel and maintain records that provide unique access accountability.", + "Name": "Audit Logs Access and Accountability", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "IVS-01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.14" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "3.1.1", + "4.1.2", + "4.1.3", + "4.2.1", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.2", + "27001: A.12.4.1", + "27002: 12.4.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.33", + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-9", + "AU-9(4)", + "AU-9(6)", + "AU-10" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-1", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05", + "PR.PS-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.1", + "10.2.1", + "10.2.3", + "10.5.1", + "10.5.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.2.1.3", + "10.3.1" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_public_access", + "cloudstorage_bucket_uniform_bucket_level_access", + "iam_audit_logs_enabled", + "kms_key_not_publicly_accessible" + ] + }, + { + "Id": "LOG-05", + "Description": "Monitor security audit logs to detect activity outside of typical or expected patterns. Establish and follow a defined process to review and take appropriate and timely actions on detected anomalies.", + "Name": "Audit Logs Monitoring and Response", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.8", + "8.11" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.1", + "1.6.2", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.3", + "27002: 12.4.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.15", + "27001: A.8.16" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-6", + "AU-6(1)", + "AU-6(5)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.AE-3", + "PR.PT-1", + "RS.AN-1", + "RS.CO-1.", + "DE.AE-1", + "DE.AE-5", + "DE.DP-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.AM-03", + "PR.PS-04", + "DE.AE-02", + "DE.AE-03", + "DE.AE-06", + "DE.AE-07", + "DE.AE-08", + "DE.CM-01", + "DE.CM-02", + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.6", + "10.6.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.4.1.1", + "10.4.2.1" + ] + } + ] + } + ], + "Checks": [ + "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled", + "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", + "logging_log_metric_filter_and_alert_for_compute_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", + "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", + "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", + "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled" + ] + }, + { + "Id": "LOG-07", + "Description": "Establish, document and implement which information meta/data system events should be logged. Review and update the scope at least annually or whenever there is a change in the threat environment.", + "Name": "Logging Scope", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 7.5.3", + "27001: A.12.4.1", + "27002: 12.4.1", + "27017: 12.4.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 7.5.3", + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-1", + "AU-14", + "AU-16" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.SC-3", + "ID.SC-4", + "PR.PT-1", + "ID.GV-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.3" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.2.1", + "10.2.2" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_audit_logs_enabled", + "cloudstorage_bucket_logging_enabled", + "compute_network_dns_logging_enabled", + "compute_subnet_flow_logs_enabled", + "iam_audit_logs_enabled" + ] + }, + { + "Id": "LOG-08", + "Description": "Generate audit records containing relevant security information.", + "Name": "Log Records", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "8.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.1", + "27002: 12.4.1", + "27017: 12.4.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-3", + "AU-3(1)", + "AU-3(3)", + "AU-6", + "AU-6(8)", + "AU-12", + "AU-12(1)", + "AU-12(2)", + "AU-12(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.PT-1", + "DE.AE-3", + "DE.CM-1", + "DE.CM-2", + "DE.CM-3", + "DE.CM-6", + "DE.CM-7" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.CM-01", + "DE.CM-02", + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.3" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.2.2" + ] + } + ] + } + ], + "Checks": [ + "iam_audit_logs_enabled", + "compute_subnet_flow_logs_enabled", + "compute_loadbalancer_logging_enabled", + "compute_network_dns_logging_enabled", + "cloudstorage_audit_logs_enabled", + "cloudstorage_bucket_logging_enabled", + "logging_sink_created", + "cloudsql_instance_postgres_log_connections_flag", + "cloudsql_instance_postgres_log_disconnections_flag", + "cloudsql_instance_postgres_log_statement_flag", + "cloudsql_instance_postgres_enable_pgaudit_flag" + ] + }, + { + "Id": "LOG-09", + "Description": "The information system protects audit records from unauthorized access, modification, and deletion.", + "Name": "Log Protection", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "GRM-04", + "IVS-01" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.4", + "4.2.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.4.2", + "27002: 12.4.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.15" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-9", + "AU-9(2)", + "AU-9(3)", + "AU-9(4)", + "AU-12(3)", + "AU-12(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.AC-4", + "PR.IP-4", + "PR.IP-6", + "PR.PT-1", + "PR.DS-1", + "PR.DS-6" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AA-05", + "PR.DS-01", + "PR.DS-02", + "PR.DS-11" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.5", + "10.5.1", + "10.5.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.3.1", + "10.3.2", + "10.3.3", + "10.3.4" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock", + "cloudstorage_bucket_uniform_bucket_level_access" + ] + }, + { + "Id": "LOG-10", + "Description": "Establish and maintain a monitoring and internal reporting capability over the operations of cryptographic, encryption and key management policies, processes, procedures, and controls.", + "Name": "Encryption Monitoring and Reporting", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC7.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-02", + "EKM-03" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "4.2.1", + "5.1.1", + "5.1.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1", + "27002: 10.1", + "27001: A.10.1.2", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-1", + "AU-9", + "AU-9(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-1", + "PR.PT-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.1.1", + "10.2.1", + "10.4.1" + ] + } + ] + } + ], + "Checks": [ + "kms_key_rotation_enabled" + ] + }, + { + "Id": "LOG-11", + "Description": "Log and monitor key lifecycle management events to enable auditing and reporting on usage of cryptographic keys.", + "Name": "Transaction/Activity Logging", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC7.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "EKM-02" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.1" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.10.1.2", + "27017: 10.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.24" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-9", + "AU-9(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.PT-1", + "DE.AE-3" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.CM-09" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_audit_logs_enabled", + "iam_audit_logs_enabled", + "logging_sink_created" + ] + }, + { + "Id": "LOG-13", + "Description": "Define, implement and evaluate processes, procedures and technical measures for the reporting of anomalies and failures of the monitoring system and provide immediate notification to the accountable party.", + "Name": "Failures and Anomalies Reporting", + "Attributes": [ + { + "Section": "Logging and Monitoring", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC2.3", + "CC7.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "SEF-03" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.1", + "5.2.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.16.1.1", + "27002: 16.1.1", + "27001: A.16.1.2", + "27017: 16.1.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.24", + "27001: A.6.8", + "27002: 6.8 (g)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AU-5", + "AU-5(2)", + "AU-6", + "AU-6(3)", + "AU-6(4)", + "AU-6(5)", + "AU-16" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.DP-3", + "DE.DP-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-04", + "DE.AE-06" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "10.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "10.4.3", + "10.7.1", + "10.7.2", + "10.7.3" + ] + } + ] + } + ], + "Checks": [ + "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", + "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled" + ] + }, + { + "Id": "SEF-03", + "Description": "'Establish, document, approve, communicate, apply, evaluate and maintain a security incident response plan, which includes but is not limited to: relevant internal departments, impacted CSCs, and other business critical relationships (such as supply-chain) that may be impacted.'", + "Name": "Incident Response Plans", + "Attributes": [ + { + "Section": "Security Incident Management, E-Discovery, & Cloud Forensics", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2", + "CC7.3", + "CC7.4" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "BCR-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "17.2", + "17.4" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.2", + "1.6.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: A.16.1.5", + "27002: 16.1.5", + "27017: 16.1.5", + "27017: CLD.12.1.5", + "27018: 16.1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: A.5.26", + "27002: 5.26 (e,f)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "IR-1", + "IR-2", + "IR-2(1)-(3)", + "IR-3", + "IR-3(1)-(3)", + "IR-4", + "IR-4(1)-(15)", + "IR-5", + "IR-5(1)", + "IR-6", + "IR-6(1)-(3)", + "IR-7", + "IR-7(1)", + "IR-7(2)", + "IR-8", + "IR-8(1)", + "IR-9", + "IR-9(1)-(4)", + "PM-12" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "RS.CO-1", + "RS.CO-4", + "ID.AM-6", + "ID.GV-2", + "ID.SC-5", + "PR.IP-9", + "PR.IP10" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.AT-01", + "PR.AT-02", + "RS.MA-01", + "GV.SC-08", + "ID.IM-02", + "ID.IM-04", + "RC.RP-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "12.1", + "12.10.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.10.1", + "12.10.5" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "SEF-06", + "Description": "Define, implement and evaluate processes, procedures and technical measures supporting business processes to triage security-related events.", + "Name": "Event Triage Processes", + "Attributes": [ + { + "Section": "Security Incident Management, E-Discovery, & Cloud Forensics", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "SEF-02" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.2" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.16.1.4", + "27002: 16.1.4", + "27017: 16.1.4", + "27018: 16.1.4", + "27001: A.16.1.5", + "27002: 16.1.5", + "27017: 16.1.5", + "27018: 16.1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.25" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CA-7", + "CA-7(3)", + "CA-7(4)", + "CA-7(5)", + "CA-7(6)", + "IR-4", + "IR-4(1)", + "IR-4(3)", + "IR-4(4)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.AE-1", + "DE.AE-2", + "DE.AE-4", + "RS.RP-1", + "RS.AN-2" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "RS.MA-02", + "RS.MA-03", + "RS.AN-03", + "DE.AE-02", + "DE.AE-04", + "DE.AE-06", + "DE.AE-07", + "DE.AE-08", + "RS.MI-02", + "RC.RP-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "12.5.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.10.1" + ] + } + ] + } + ], + "Checks": [ + "iam_audit_logs_enabled", + "logging_sink_created" + ] + }, + { + "Id": "SEF-08", + "Description": "Maintain points of contact for applicable regulation authorities, national and local law enforcement, and other legal jurisdictional authorities.", + "Name": "Points of Contact Maintenance", + "Attributes": [ + { + "Section": "Security Incident Management, E-Discovery, & Cloud Forensics", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC2.3" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "SEF-01" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "17.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.6.2", + "1.6.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "SM2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 4.2", + "27001: A.6.1.3", + "27002: 6.1.3", + "27017: 6.1.3", + "27018: 6.1.3", + "27001: A.16.1.1", + "27002: 16.1.1", + "27001: A.18.1.1", + "27002: 18.1.1", + "27017: 18.1.1", + "27018: 18.1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.5", + "27001: A.5.24", + "27002: 5.24 Incident management procedure (d)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "IR-4", + "IR-4(8)", + "IR-6", + "IR-6(3)", + "IR-7", + "IR-7(2)", + "PM-21", + "PM-23", + "PM-26" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-2", + "RS.CO-3", + "RS.CO-4" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.RR-02", + "RS.CO-02", + "RS.CO-03" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.10.1" + ] + } + ] + } + ], + "Checks": [ + "iam_organization_essential_contacts_configured" + ] + }, + { + "Id": "TVM-02", + "Description": "Establish, document, approve, communicate, apply, evaluate and maintain policies and procedures to protect against malware on managed assets. Review and update the policies and procedures at least annually.", + "Name": "Malware Protection Policy and Procedures", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC5.3", + "CC6.8" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "TVM-01", + "GRM-06", + "GRM-09" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "9.7", + "10.1" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "1.1.1", + "1.5.1", + "5.2.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS1.2", + "TS1.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 5.1", + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: 9.1", + "27001: 9.3", + "27001: A.5", + "27002: 5", + "27001: A.12.2.1", + "27001: A.6.2.1", + "27002: 6.2.1 (h)", + "27001: A.6.2.2", + "27002: 6.2.2 (j)", + "27001: A.7.2.2", + "27002: 7.2.2 (d)", + "27001: A.10.1.1", + "27002: 10.1.1 (g)", + "27001: A.13.2.1", + "27002: 13.2.1 (b)", + "27001: A.15.1.2", + "27017: 15.1.2", + "27001: A.12.2.1", + "27002: 12.2.1 (a),(d)", + "27017: CLD.9.5.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 5.1", + "27001: 5.2", + "27001: 7.3", + "27001: 7.4", + "27001: 7.5", + "27001: 9.1", + "27001: 9.3", + "27001: A.5.1", + "27001: A.5.4", + "27001: A.5.7", + "27001: A.5.37", + "27001: A.8.7", + "27002: 5.7 (b)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "RA-3", + "RA-3(3)", + "RA-5", + "RA-5(3)", + "RA-5(5)", + "SI-3", + "SI-3(4)", + "SI-3(10)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.GV-1", + "DE.CM-4", + "DE.CM-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "GV.PO-01", + "GV.PO-02", + "ID.IM-03", + "DE.CM-01", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "5.4", + "12.1", + "12.1.1", + "12.3.1", + "12.5.1", + "12.11" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "12.1.1", + "12.1.2", + "5.1.1", + "5.3.2.1" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "TVM-03", + "Description": "Define, implement and evaluate processes, procedures and technical measures to enable both scheduled and emergency responses to vulnerability identifications, based on the identified risk.", + "Name": "Vulnerability Remediation Schedule", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC5.3", + "CC7.1", + "CC7.4" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "TVM-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "7.2", + "7.7", + "17.9" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.5" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.1", + "TM2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.12.2.1", + "27001: A.12.6.1", + "27002: 12.6.1(c)(d)(j)", + "27018: 12.6.1(k)(i)" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.8.7", + "27001: A.8.8", + "27001: A.8.32", + "27002: 8.7", + "27002: 8.8", + "27002: 8.32" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "PM-31", + "RA-3", + "RA-3(1)", + "RA-5", + "RA-5(2)-(4)", + "RA-5(6)", + "SI-3", + "SI-3(10)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "RS.AN-5", + "PR.IP-12" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.RA-01", + "ID.RA-06", + "ID.RA-08", + "PR.PS-02", + "PR.PS-03" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.1", + "6.1.a", + "6.1.b" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.1.1", + "6.3.1", + "6.3.2", + "6.3.3", + "12.10.1" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "TVM-04", + "Description": "Define, implement and evaluate processes, procedures and technical measures to update detection tools, threat signatures, and indicators of compromise on a weekly, or more frequent basis.", + "Name": "Detection Updates", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "No mapping" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "10.2" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.3" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TS1.3", + "TS1.4", + "TM1.3", + "TM1.4", + "IM1.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.5.1.1", + "27002: 5.1.1 (h)", + "27001: A.12.6.1", + "27002: 12.6.1 (b),(c)" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.5.1", + "27001: A.8.8", + "27001: A.8.15", + "27001: A.8.16", + "27002: 5.1", + "27002: 5.37", + "27002: 8.8", + "27002: 8.15 (d)", + "27002: 8.16 (d,e)", + "27002: 8.31 2nd (a)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "CM-7", + "CM-7(4)", + "RA-3", + "RA-3(3)", + "RA-5(2)", + "SA-10", + "SA-10(5)", + "SA-11", + "SA-11(2)", + "SI-2", + "SI-2(4)", + "SI-3", + "SI-3(4)", + "SI-4", + "SI-4(9)", + "SI-4(24)", + "SI-8", + "SI-8(2)", + "SI-8(3)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.DP-5", + "PR.IP-12" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.PS-02", + "ID.RA-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "5.2", + "5.2a", + "5.2b", + "5.2c" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "5.3.1" + ] + } + ] + } + ], + "Checks": [ + "artifacts_container_analysis_enabled", + "gcr_container_scanning_enabled" + ] + }, + { + "Id": "TVM-05", + "Description": "Define, implement and evaluate processes, procedures and technical measures to identify updates for applications which use third party or open source libraries according to the organization's vulnerability management policy.", + "Name": "External Library Vulnerabilities", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "CSP-Owned", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC3.2" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "No mapping" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "2.6" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.1", + "SD2.3" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: 6.1.3", + "27001: A.12.6.2", + "27002: 12.6.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: 6.1.3", + "27001: A 5.6", + "27001: A.8.19", + "27001: A.8.8", + "27001: A.8.28", + "27001: A.8.31", + "27002: 5.6 (c)", + "27001: 8.19", + "27001: 8.8", + "27001: 8.28", + "27001: 8.31" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "RA-5", + "RA-5(3)", + "SA-11", + "SA-11(2)", + "SA-11(5)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "DE.DP-5", + "PR.IP-12" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.RA-01", + "ID.RA-03", + "PR.PS-02" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.1", + "6.2", + "6.3.2" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.3.1", + "6.3.2", + "6.3.3" + ] + } + ] + } + ], + "Checks": [ + "artifacts_container_analysis_enabled", + "gcr_container_scanning_enabled" + ] + }, + { + "Id": "TVM-07", + "Description": "Define, implement and evaluate processes, procedures and technical measures for the detection of vulnerabilities on organizationally managed assets at least monthly.", + "Name": "Vulnerability Identification", + "Attributes": [ + { + "Section": "Threat & Vulnerability Management", + "CCMLite": "Yes", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC7.1" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "TVM-02" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "7.1", + "7.5", + "7.6" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.5", + "5.2.6" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "TM1.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.6", + "27001: A.12.6.1", + "27002: 12.6.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.8", + "27002: 8.8" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "RA-5", + "RA-5(4)", + "RA-5(5)", + "SA-11", + "SA-11(5)", + "SA-15(5)", + "SC-7", + "SC-7(10)", + "SI-3(8)", + "SI-3(10)", + "SI-7", + "SI-7(9)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "ID.RA-1", + "DE.CM-8", + "PR.IP-12" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "ID.RA-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "6.1", + "11.2", + "11.2.1" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "6.3.1", + "6.3.2", + "6.3.3", + "11.3.2", + "11.3.2.1" + ] + } + ] + } + ], + "Checks": [ + "artifacts_container_analysis_enabled", + "compute_public_address_shodan", + "gcr_container_scanning_enabled" + ] + }, + { + "Id": "UEM-08", + "Description": "Protect information from unauthorized disclosure on managed endpoint devices with storage encryption.", + "Name": "Storage Encryption", + "Attributes": [ + { + "Section": "Universal Endpoint Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.1", + "CC6.7" + ] + }, + { + "ReferenceId": "CCM v3.0.1", + "Identifiers": [ + "MOS-11" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.6" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.1.2", + "3.1.4" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "PA1.2", + "PA1.3", + "PA1.5", + "PA2.2", + "PM1.4" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.11.2.7", + "27002: 11.2.7", + "27001: A.18.1.1", + "27017: 18.1.1", + "27001: A.12.3.1", + "27017: 12.3.1", + "27018: A.11.4", + "27018: A.11.5" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.8.1", + "27002: 8.1 (h)" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "AC-19(5)", + "SC-28", + "SC-28(1)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-01" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "3.4", + "3.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "3.5.1", + "3.6" + ] + } + ] + } + ], + "Checks": [ + "bigquery_dataset_cmk_encryption", + "bigquery_table_cmk_encryption", + "compute_instance_confidential_computing_enabled", + "compute_instance_encryption_with_csek_enabled", + "dataproc_encrypted_with_cmks_disabled" + ] + }, + { + "Id": "UEM-11", + "Description": "Configure managed endpoints with Data Loss Prevention (DLP) technologies and rules in accordance with a risk assessment.", + "Name": "Data Loss Prevention", + "Attributes": [ + { + "Section": "Universal Endpoint Management", + "CCMLite": "No", + "IaaS": "Shared", + "PaaS": "Shared", + "SaaS": "Shared", + "ScopeApplicability": [ + { + "ReferenceId": "AICPA TSC 2017", + "Identifiers": [ + "CC6.7" + ] + }, + { + "ReferenceId": "CIS v8.0", + "Identifiers": [ + "3.13" + ] + }, + { + "ReferenceId": "ENX ISA v6.0", + "Identifiers": [ + "5.2.7" + ] + }, + { + "ReferenceId": "ISF SOGP 2022", + "Identifiers": [ + "IM1.5", + "PA2.2" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2013,27002:2013,27017:2015,27018:2019", + "Identifiers": [ + "27001: A.12.3", + "27002: 12.3", + "27001: A.8.3.1", + "27002: 8.3.1", + "27001: A.12.2", + "27002: 12.2", + "27001: A.18.1.3", + "27002: 18.1.3", + "27001: A.6.1.1", + "27017: 6.1.1", + "27018: 12.3.1", + "27018: 10.1" + ] + }, + { + "ReferenceId": "ISO/IEC 27001:2022, 27002:2022", + "Identifiers": [ + "27001: A.5.12", + "27001: A.8.3" + ] + }, + { + "ReferenceId": "NIST 800-53 rev 5", + "Identifiers": [ + "SC-7", + "SC-7(10)" + ] + }, + { + "ReferenceId": "NIST CSF v1.1", + "Identifiers": [ + "PR.DS-5" + ] + }, + { + "ReferenceId": "NIST CSF v2.0", + "Identifiers": [ + "PR.DS-02", + "PR.DS-10", + "PR.PS-01", + "ID.AM-08", + "DE.CM-09" + ] + }, + { + "ReferenceId": "PCI DSS v3.2.1", + "Identifiers": [ + "A3.2.6" + ] + }, + { + "ReferenceId": "PCI DSS v4.0", + "Identifiers": [ + "A3.2.6" + ] + } + ] + } + ], + "Checks": [] + } + ] +} diff --git a/prowler/lib/outputs/compliance/csa/csa_gcp.py b/prowler/lib/outputs/compliance/csa/csa_gcp.py new file mode 100644 index 0000000000..5c1b400525 --- /dev/null +++ b/prowler/lib/outputs/compliance/csa/csa_gcp.py @@ -0,0 +1,96 @@ +from prowler.config.config import timestamp +from prowler.lib.check.compliance_models import Compliance +from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput +from prowler.lib.outputs.compliance.csa.models import GCPCSAModel +from prowler.lib.outputs.finding import Finding + + +class GCPCSA(ComplianceOutput): + """ + This class represents the GCP CSA compliance output. + + Attributes: + - _data (list): A list to store transformed data from findings. + - _file_descriptor (TextIOWrapper): A file descriptor to write data to a file. + + Methods: + - transform: Transforms findings into GCP CSA compliance format. + """ + + def transform( + self, + findings: list[Finding], + compliance: Compliance, + compliance_name: str, + ) -> None: + """ + Transforms a list of findings into GCP CSA compliance format. + + Parameters: + - findings (list): A list of findings. + - compliance (Compliance): A compliance model. + - compliance_name (str): The name of the compliance model. + + Returns: + - None + """ + for finding in findings: + # Get the compliance requirements for the finding + finding_requirements = finding.compliance.get(compliance_name, []) + for requirement in compliance.Requirements: + if requirement.Id in finding_requirements: + for attribute in requirement.Attributes: + compliance_row = GCPCSAModel( + Provider=finding.provider, + Description=compliance.Description, + ProjectId=finding.account_uid, + Location=finding.region, + AssessmentDate=str(timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Name=requirement.Name, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_CCMLite=attribute.CCMLite, + Requirements_Attributes_IaaS=attribute.IaaS, + Requirements_Attributes_PaaS=attribute.PaaS, + Requirements_Attributes_SaaS=attribute.SaaS, + Requirements_Attributes_ScopeApplicability=attribute.ScopeApplicability, + Status=finding.status, + StatusExtended=finding.status_extended, + ResourceId=finding.resource_uid, + ResourceName=finding.resource_name, + CheckId=finding.check_id, + Muted=finding.muted, + Framework=compliance.Framework, + Name=compliance.Name, + ) + self._data.append(compliance_row) + # Add manual requirements to the compliance output + for requirement in compliance.Requirements: + if not requirement.Checks: + for attribute in requirement.Attributes: + compliance_row = GCPCSAModel( + Provider=compliance.Provider.lower(), + Description=compliance.Description, + ProjectId="", + Location="", + AssessmentDate=str(timestamp), + Requirements_Id=requirement.Id, + Requirements_Description=requirement.Description, + Requirements_Name=requirement.Name, + Requirements_Attributes_Section=attribute.Section, + Requirements_Attributes_CCMLite=attribute.CCMLite, + Requirements_Attributes_IaaS=attribute.IaaS, + Requirements_Attributes_PaaS=attribute.PaaS, + Requirements_Attributes_SaaS=attribute.SaaS, + Requirements_Attributes_ScopeApplicability=attribute.ScopeApplicability, + Status="MANUAL", + StatusExtended="Manual check", + ResourceId="manual_check", + ResourceName="Manual check", + CheckId="manual", + Muted=False, + Framework=compliance.Framework, + Name=compliance.Name, + ) + self._data.append(compliance_row) diff --git a/prowler/lib/outputs/compliance/csa/models.py b/prowler/lib/outputs/compliance/csa/models.py index e981671d38..7d3acefcc6 100644 --- a/prowler/lib/outputs/compliance/csa/models.py +++ b/prowler/lib/outputs/compliance/csa/models.py @@ -30,6 +30,35 @@ class AWSCSAModel(BaseModel): Name: str +class GCPCSAModel(BaseModel): + """ + GCPCSAModel generates a finding's output in CSV CSA format for GCP. + """ + + Provider: str + Description: str + ProjectId: str + Location: str + AssessmentDate: str + Requirements_Id: str + Requirements_Description: str + Requirements_Name: str + Requirements_Attributes_Section: str + Requirements_Attributes_CCMLite: str + Requirements_Attributes_IaaS: str + Requirements_Attributes_PaaS: str + Requirements_Attributes_SaaS: str + Requirements_Attributes_ScopeApplicability: list[dict] + Status: str + StatusExtended: str + ResourceId: str + CheckId: str + Muted: bool + ResourceName: str + Framework: str + Name: str + + class AzureCSAModel(BaseModel): """ AzureCSAModel generates a finding's output in CSV CSA format for Azure. From 1f4e308374dae093f8ac25740b7b2e30f5a38138 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:26:03 +0100 Subject: [PATCH 08/12] build(deps): bump pillow from 12.1.0 to 12.1.1 in /api (#10027) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Josema Camacho --- api/CHANGELOG.md | 4 + api/poetry.lock | 186 +++++++++++++++++++++++------------------------ 2 files changed, 97 insertions(+), 93 deletions(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 04931d628e..5d7fd45567 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -12,6 +12,10 @@ All notable changes to the **Prowler API** are documented in this file. - Support CSA CCM 4.0 for the GCP provider [(#10042)](https://github.com/prowler-cloud/prowler/pull/10042) - Support CSA CCM for the Azure provider [(#10039)](https://github.com/prowler-cloud/prowler/pull/10039) +### 🔐 Security + +- Pillow 12.1.1 (CVE-2021-25289) [(#10027)](https://github.com/prowler-cloud/prowler/pull/10027) + --- ## [1.19.2] (Prowler v5.18.2) diff --git a/api/poetry.lock b/api/poetry.lock index 8ab49cf6bf..e6563f4e76 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "about-time" @@ -6258,103 +6258,103 @@ urllib3 = "*" [[package]] name = "pillow" -version = "12.1.0" +version = "12.1.1" description = "Python Imaging Library (fork)" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "pillow-12.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:fb125d860738a09d363a88daa0f59c4533529a90e564785e20fe875b200b6dbd"}, - {file = "pillow-12.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cad302dc10fac357d3467a74a9561c90609768a6f73a1923b0fd851b6486f8b0"}, - {file = "pillow-12.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a40905599d8079e09f25027423aed94f2823adaf2868940de991e53a449e14a8"}, - {file = "pillow-12.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:92a7fe4225365c5e3a8e598982269c6d6698d3e783b3b1ae979e7819f9cd55c1"}, - {file = "pillow-12.1.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f10c98f49227ed8383d28174ee95155a675c4ed7f85e2e573b04414f7e371bda"}, - {file = "pillow-12.1.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8637e29d13f478bc4f153d8daa9ffb16455f0a6cb287da1b432fdad2bfbd66c7"}, - {file = "pillow-12.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:21e686a21078b0f9cb8c8a961d99e6a4ddb88e0fc5ea6e130172ddddc2e5221a"}, - {file = "pillow-12.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2415373395a831f53933c23ce051021e79c8cd7979822d8cc478547a3f4da8ef"}, - {file = "pillow-12.1.0-cp310-cp310-win32.whl", hash = "sha256:e75d3dba8fc1ddfec0cd752108f93b83b4f8d6ab40e524a95d35f016b9683b09"}, - {file = "pillow-12.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:64efdf00c09e31efd754448a383ea241f55a994fd079866b92d2bbff598aad91"}, - {file = "pillow-12.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:f188028b5af6b8fb2e9a76ac0f841a575bd1bd396e46ef0840d9b88a48fdbcea"}, - {file = "pillow-12.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:a83e0850cb8f5ac975291ebfc4170ba481f41a28065277f7f735c202cd8e0af3"}, - {file = "pillow-12.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b6e53e82ec2db0717eabb276aa56cf4e500c9a7cec2c2e189b55c24f65a3e8c0"}, - {file = "pillow-12.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:40a8e3b9e8773876d6e30daed22f016509e3987bab61b3b7fe309d7019a87451"}, - {file = "pillow-12.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:800429ac32c9b72909c671aaf17ecd13110f823ddb7db4dfef412a5587c2c24e"}, - {file = "pillow-12.1.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b022eaaf709541b391ee069f0022ee5b36c709df71986e3f7be312e46f42c84"}, - {file = "pillow-12.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f345e7bc9d7f368887c712aa5054558bad44d2a301ddf9248599f4161abc7c0"}, - {file = "pillow-12.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d70347c8a5b7ccd803ec0c85c8709f036e6348f1e6a5bf048ecd9c64d3550b8b"}, - {file = "pillow-12.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1fcc52d86ce7a34fd17cb04e87cfdb164648a3662a6f20565910a99653d66c18"}, - {file = "pillow-12.1.0-cp311-cp311-win32.whl", hash = "sha256:3ffaa2f0659e2f740473bcf03c702c39a8d4b2b7ffc629052028764324842c64"}, - {file = "pillow-12.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:806f3987ffe10e867bab0ddad45df1148a2b98221798457fa097ad85d6e8bc75"}, - {file = "pillow-12.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:9f5fefaca968e700ad1a4a9de98bf0869a94e397fe3524c4c9450c1445252304"}, - {file = "pillow-12.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a332ac4ccb84b6dde65dbace8431f3af08874bf9770719d32a635c4ef411b18b"}, - {file = "pillow-12.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:907bfa8a9cb790748a9aa4513e37c88c59660da3bcfffbd24a7d9e6abf224551"}, - {file = "pillow-12.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efdc140e7b63b8f739d09a99033aa430accce485ff78e6d311973a67b6bf3208"}, - {file = "pillow-12.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bef9768cab184e7ae6e559c032e95ba8d07b3023c289f79a2bd36e8bf85605a5"}, - {file = "pillow-12.1.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:742aea052cf5ab5034a53c3846165bc3ce88d7c38e954120db0ab867ca242661"}, - {file = "pillow-12.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6dfc2af5b082b635af6e08e0d1f9f1c4e04d17d4e2ca0ef96131e85eda6eb17"}, - {file = "pillow-12.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:609e89d9f90b581c8d16358c9087df76024cf058fa693dd3e1e1620823f39670"}, - {file = "pillow-12.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43b4899cfd091a9693a1278c4982f3e50f7fb7cff5153b05174b4afc9593b616"}, - {file = "pillow-12.1.0-cp312-cp312-win32.whl", hash = "sha256:aa0c9cc0b82b14766a99fbe6084409972266e82f459821cd26997a488a7261a7"}, - {file = "pillow-12.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:d70534cea9e7966169ad29a903b99fc507e932069a881d0965a1a84bb57f6c6d"}, - {file = "pillow-12.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:65b80c1ee7e14a87d6a068dd3b0aea268ffcabfe0498d38661b00c5b4b22e74c"}, - {file = "pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1"}, - {file = "pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179"}, - {file = "pillow-12.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0"}, - {file = "pillow-12.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587"}, - {file = "pillow-12.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac"}, - {file = "pillow-12.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b"}, - {file = "pillow-12.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea"}, - {file = "pillow-12.1.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c"}, - {file = "pillow-12.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc"}, - {file = "pillow-12.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644"}, - {file = "pillow-12.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c"}, - {file = "pillow-12.1.0-cp313-cp313-win32.whl", hash = "sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171"}, - {file = "pillow-12.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a"}, - {file = "pillow-12.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45"}, - {file = "pillow-12.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d"}, - {file = "pillow-12.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0"}, - {file = "pillow-12.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554"}, - {file = "pillow-12.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e"}, - {file = "pillow-12.1.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82"}, - {file = "pillow-12.1.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4"}, - {file = "pillow-12.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0"}, - {file = "pillow-12.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b"}, - {file = "pillow-12.1.0-cp313-cp313t-win32.whl", hash = "sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65"}, - {file = "pillow-12.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0"}, - {file = "pillow-12.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8"}, - {file = "pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:5cb7bc1966d031aec37ddb9dcf15c2da5b2e9f7cc3ca7c54473a20a927e1eb91"}, - {file = "pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:97e9993d5ed946aba26baf9c1e8cf18adbab584b99f452ee72f7ee8acb882796"}, - {file = "pillow-12.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:414b9a78e14ffeb98128863314e62c3f24b8a86081066625700b7985b3f529bd"}, - {file = "pillow-12.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e6bdb408f7c9dd2a5ff2b14a3b0bb6d4deb29fb9961e6eb3ae2031ae9a5cec13"}, - {file = "pillow-12.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3413c2ae377550f5487991d444428f1a8ae92784aac79caa8b1e3b89b175f77e"}, - {file = "pillow-12.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e5dcbe95016e88437ecf33544ba5db21ef1b8dd6e1b434a2cb2a3d605299e643"}, - {file = "pillow-12.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d0a7735df32ccbcc98b98a1ac785cc4b19b580be1bdf0aeb5c03223220ea09d5"}, - {file = "pillow-12.1.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c27407a2d1b96774cbc4a7594129cc027339fd800cd081e44497722ea1179de"}, - {file = "pillow-12.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15c794d74303828eaa957ff8070846d0efe8c630901a1c753fdc63850e19ecd9"}, - {file = "pillow-12.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c990547452ee2800d8506c4150280757f88532f3de2a58e3022e9b179107862a"}, - {file = "pillow-12.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b63e13dd27da389ed9475b3d28510f0f954bca0041e8e551b2a4eb1eab56a39a"}, - {file = "pillow-12.1.0-cp314-cp314-win32.whl", hash = "sha256:1a949604f73eb07a8adab38c4fe50791f9919344398bdc8ac6b307f755fc7030"}, - {file = "pillow-12.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:4f9f6a650743f0ddee5593ac9e954ba1bdbc5e150bc066586d4f26127853ab94"}, - {file = "pillow-12.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:808b99604f7873c800c4840f55ff389936ef1948e4e87645eaf3fccbc8477ac4"}, - {file = "pillow-12.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc11908616c8a283cf7d664f77411a5ed2a02009b0097ff8abbba5e79128ccf2"}, - {file = "pillow-12.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:896866d2d436563fa2a43a9d72f417874f16b5545955c54a64941e87c1376c61"}, - {file = "pillow-12.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8e178e3e99d3c0ea8fc64b88447f7cac8ccf058af422a6cedc690d0eadd98c51"}, - {file = "pillow-12.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:079af2fb0c599c2ec144ba2c02766d1b55498e373b3ac64687e43849fbbef5bc"}, - {file = "pillow-12.1.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdec5e43377761c5dbca620efb69a77f6855c5a379e32ac5b158f54c84212b14"}, - {file = "pillow-12.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:565c986f4b45c020f5421a4cea13ef294dde9509a8577f29b2fc5edc7587fff8"}, - {file = "pillow-12.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:43aca0a55ce1eefc0aefa6253661cb54571857b1a7b2964bd8a1e3ef4b729924"}, - {file = "pillow-12.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0deedf2ea233722476b3a81e8cdfbad786f7adbed5d848469fa59fe52396e4ef"}, - {file = "pillow-12.1.0-cp314-cp314t-win32.whl", hash = "sha256:b17fbdbe01c196e7e159aacb889e091f28e61020a8abeac07b68079b6e626988"}, - {file = "pillow-12.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27b9baecb428899db6c0de572d6d305cfaf38ca1596b5c0542a5182e3e74e8c6"}, - {file = "pillow-12.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f61333d817698bdcdd0f9d7793e365ac3d2a21c1f1eb02b32ad6aefb8d8ea831"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ca94b6aac0d7af2a10ba08c0f888b3d5114439b6b3ef39968378723622fed377"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:351889afef0f485b84078ea40fe33727a0492b9af3904661b0abbafee0355b72"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb0984b30e973f7e2884362b7d23d0a348c7143ee559f38ef3eaab640144204c"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:84cabc7095dd535ca934d57e9ce2a72ffd216e435a84acb06b2277b1de2689bd"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53d8b764726d3af1a138dd353116f774e3862ec7e3794e0c8781e30db0f35dfc"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5da841d81b1a05ef940a8567da92decaa15bc4d7dedb540a8c219ad83d91808a"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:75af0b4c229ac519b155028fa1be632d812a519abba9b46b20e50c6caa184f19"}, - {file = "pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9"}, + {file = "pillow-12.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f1625b72740fdda5d77b4def688eb8fd6490975d06b909fd19f13f391e077e0"}, + {file = "pillow-12.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:178aa072084bd88ec759052feca8e56cbb14a60b39322b99a049e58090479713"}, + {file = "pillow-12.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b66e95d05ba806247aaa1561f080abc7975daf715c30780ff92a20e4ec546e1b"}, + {file = "pillow-12.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89c7e895002bbe49cdc5426150377cbbc04767d7547ed145473f496dfa40408b"}, + {file = "pillow-12.1.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a5cbdcddad0af3da87cb16b60d23648bc3b51967eb07223e9fed77a82b457c4"}, + {file = "pillow-12.1.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9f51079765661884a486727f0729d29054242f74b46186026582b4e4769918e4"}, + {file = "pillow-12.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:99c1506ea77c11531d75e3a412832a13a71c7ebc8192ab9e4b2e355555920e3e"}, + {file = "pillow-12.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36341d06738a9f66c8287cf8b876d24b18db9bd8740fa0672c74e259ad408cff"}, + {file = "pillow-12.1.1-cp310-cp310-win32.whl", hash = "sha256:6c52f062424c523d6c4db85518774cc3d50f5539dd6eed32b8f6229b26f24d40"}, + {file = "pillow-12.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6008de247150668a705a6338156efb92334113421ceecf7438a12c9a12dab23"}, + {file = "pillow-12.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:1a9b0ee305220b392e1124a764ee4265bd063e54a751a6b62eff69992f457fa9"}, + {file = "pillow-12.1.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e879bb6cd5c73848ef3b2b48b8af9ff08c5b71ecda8048b7dd22d8a33f60be32"}, + {file = "pillow-12.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:365b10bb9417dd4498c0e3b128018c4a624dc11c7b97d8cc54effe3b096f4c38"}, + {file = "pillow-12.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d4ce8e329c93845720cd2014659ca67eac35f6433fd3050393d85f3ecef0dad5"}, + {file = "pillow-12.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc354a04072b765eccf2204f588a7a532c9511e8b9c7f900e1b64e3e33487090"}, + {file = "pillow-12.1.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e7976bf1910a8116b523b9f9f58bf410f3e8aa330cd9a2bb2953f9266ab49af"}, + {file = "pillow-12.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:597bd9c8419bc7c6af5604e55847789b69123bbe25d65cc6ad3012b4f3c98d8b"}, + {file = "pillow-12.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2c1fc0f2ca5f96a3c8407e41cca26a16e46b21060fe6d5b099d2cb01412222f5"}, + {file = "pillow-12.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:578510d88c6229d735855e1f278aa305270438d36a05031dfaae5067cc8eb04d"}, + {file = "pillow-12.1.1-cp311-cp311-win32.whl", hash = "sha256:7311c0a0dcadb89b36b7025dfd8326ecfa36964e29913074d47382706e516a7c"}, + {file = "pillow-12.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:fbfa2a7c10cc2623f412753cddf391c7f971c52ca40a3f65dc5039b2939e8563"}, + {file = "pillow-12.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:b81b5e3511211631b3f672a595e3221252c90af017e399056d0faabb9538aa80"}, + {file = "pillow-12.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052"}, + {file = "pillow-12.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984"}, + {file = "pillow-12.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79"}, + {file = "pillow-12.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293"}, + {file = "pillow-12.1.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397"}, + {file = "pillow-12.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0"}, + {file = "pillow-12.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3"}, + {file = "pillow-12.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35"}, + {file = "pillow-12.1.1-cp312-cp312-win32.whl", hash = "sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a"}, + {file = "pillow-12.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6"}, + {file = "pillow-12.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523"}, + {file = "pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e"}, + {file = "pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9"}, + {file = "pillow-12.1.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6"}, + {file = "pillow-12.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60"}, + {file = "pillow-12.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2"}, + {file = "pillow-12.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850"}, + {file = "pillow-12.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289"}, + {file = "pillow-12.1.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e"}, + {file = "pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717"}, + {file = "pillow-12.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a"}, + {file = "pillow-12.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029"}, + {file = "pillow-12.1.1-cp313-cp313-win32.whl", hash = "sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b"}, + {file = "pillow-12.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1"}, + {file = "pillow-12.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a"}, + {file = "pillow-12.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da"}, + {file = "pillow-12.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc"}, + {file = "pillow-12.1.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c"}, + {file = "pillow-12.1.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8"}, + {file = "pillow-12.1.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20"}, + {file = "pillow-12.1.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13"}, + {file = "pillow-12.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf"}, + {file = "pillow-12.1.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524"}, + {file = "pillow-12.1.1-cp313-cp313t-win32.whl", hash = "sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986"}, + {file = "pillow-12.1.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c"}, + {file = "pillow-12.1.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3"}, + {file = "pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af"}, + {file = "pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f"}, + {file = "pillow-12.1.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642"}, + {file = "pillow-12.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd"}, + {file = "pillow-12.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202"}, + {file = "pillow-12.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f"}, + {file = "pillow-12.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f"}, + {file = "pillow-12.1.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f"}, + {file = "pillow-12.1.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e"}, + {file = "pillow-12.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0"}, + {file = "pillow-12.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb"}, + {file = "pillow-12.1.1-cp314-cp314-win32.whl", hash = "sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f"}, + {file = "pillow-12.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15"}, + {file = "pillow-12.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f"}, + {file = "pillow-12.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8"}, + {file = "pillow-12.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9"}, + {file = "pillow-12.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60"}, + {file = "pillow-12.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7"}, + {file = "pillow-12.1.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f"}, + {file = "pillow-12.1.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586"}, + {file = "pillow-12.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce"}, + {file = "pillow-12.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8"}, + {file = "pillow-12.1.1-cp314-cp314t-win32.whl", hash = "sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36"}, + {file = "pillow-12.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b"}, + {file = "pillow-12.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334"}, + {file = "pillow-12.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:600fd103672b925fe62ed08e0d874ea34d692474df6f4bf7ebe148b30f89f39f"}, + {file = "pillow-12.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:665e1b916b043cef294bc54d47bf02d87e13f769bc4bc5fa225a24b3a6c5aca9"}, + {file = "pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:495c302af3aad1ca67420ddd5c7bd480c8867ad173528767d906428057a11f0e"}, + {file = "pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8fd420ef0c52c88b5a035a0886f367748c72147b2b8f384c9d12656678dfdfa9"}, + {file = "pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f975aa7ef9684ce7e2c18a3aa8f8e2106ce1e46b94ab713d156b2898811651d3"}, + {file = "pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8089c852a56c2966cf18835db62d9b34fef7ba74c726ad943928d494fa7f4735"}, + {file = "pillow-12.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:cb9bb857b2d057c6dfc72ac5f3b44836924ba15721882ef103cecb40d002d80e"}, + {file = "pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4"}, ] [package.extras] From e6bea9f25aeb9b9f8039688cc3effb9f40c569a3 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:35:43 +0100 Subject: [PATCH 09/12] feat(oraclecloud): add automated OCI regions updater script and CI workflow (#10020) Co-authored-by: Pepe Fagoaga --- .github/workflows/sdk-refresh-oci-regions.yml | 95 ++++++++ prowler/CHANGELOG.md | 1 + util/update_oci_regions.py | 205 ++++++++++++++++++ 3 files changed, 301 insertions(+) create mode 100644 .github/workflows/sdk-refresh-oci-regions.yml create mode 100644 util/update_oci_regions.py diff --git a/.github/workflows/sdk-refresh-oci-regions.yml b/.github/workflows/sdk-refresh-oci-regions.yml new file mode 100644 index 0000000000..337e3e2cda --- /dev/null +++ b/.github/workflows/sdk-refresh-oci-regions.yml @@ -0,0 +1,95 @@ +name: 'SDK: Refresh OCI Regions' + +on: + schedule: + - cron: '0 9 * * 1' # Every Monday at 09:00 UTC + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + +env: + PYTHON_VERSION: '3.12' + +jobs: + refresh-oci-regions: + if: github.repository == 'prowler-cloud/prowler' + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + pull-requests: write + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + ref: 'master' + + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + + - name: Install dependencies + run: pip install oci + + - name: Update OCI regions + env: + OCI_CLI_USER: ${{ secrets.E2E_OCI_USER_ID }} + OCI_CLI_FINGERPRINT: ${{ secrets.E2E_OCI_FINGERPRINT }} + OCI_CLI_TENANCY: ${{ secrets.E2E_OCI_TENANCY_ID }} + OCI_CLI_KEY_CONTENT: ${{ secrets.E2E_OCI_KEY_CONTENT }} + OCI_CLI_REGION: ${{ secrets.E2E_OCI_REGION }} + run: python util/update_oci_regions.py + + - name: Create pull request + id: create-pr + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 + with: + token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} + author: 'prowler-bot <179230569+prowler-bot@users.noreply.github.com>' + committer: 'github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>' + commit-message: 'feat(oraclecloud): update commercial regions' + branch: 'oci-regions-update-${{ github.run_number }}' + title: 'feat(oraclecloud): Update commercial regions' + labels: | + status/waiting-for-revision + severity/low + provider/oraclecloud + no-changelog + body: | + ### Description + + Automated update of OCI commercial regions from the official Oracle Cloud Infrastructure Identity service. + + **Trigger:** ${{ github.event_name == 'schedule' && 'Scheduled (weekly)' || github.event_name == 'workflow_dispatch' && 'Manual' || 'Workflow update' }} + **Run:** [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) + + ### Changes + + This PR updates the `OCI_COMMERCIAL_REGIONS` dictionary in `prowler/providers/oraclecloud/config.py` with the latest regions fetched from the OCI Identity API (`list_regions()`). + + - Government regions (`OCI_GOVERNMENT_REGIONS`) are preserved unchanged + - Region display names are mapped from Oracle's official documentation + + ### Checklist + + - [x] This is an automated update from OCI official sources + - [x] Government regions (us-langley-1, us-luke-1) preserved + - [x] No manual review of region data required + + ### License + + By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. + + - name: PR creation result + run: | + if [[ "${{ steps.create-pr.outputs.pull-request-number }}" ]]; then + echo "✓ Pull request #${{ steps.create-pr.outputs.pull-request-number }} created successfully" + echo "URL: ${{ steps.create-pr.outputs.pull-request-url }}" + else + echo "✓ No changes detected - OCI regions are up to date" + fi diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 47258ca87c..a0128d64fe 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - CSA CCM 4.0 for the AWS provider [(#10018)](https://github.com/prowler-cloud/prowler/pull/10018) - CSA CCM 4.0 for the GCP provider [(#10042)](https://github.com/prowler-cloud/prowler/pull/10042) - CSA CCM for the Azure provider [(#10039)](https://github.com/prowler-cloud/prowler/pull/10039) +- OCI regions updater script and CI workflow [(#10020)](https://github.com/prowler-cloud/prowler/pull/10020) ### 🔄 Changed diff --git a/util/update_oci_regions.py b/util/update_oci_regions.py new file mode 100644 index 0000000000..3dbfe07668 --- /dev/null +++ b/util/update_oci_regions.py @@ -0,0 +1,205 @@ +import base64 +import logging +import os +import re +import sys + +import oci + +# Logging config +logging.basicConfig( + stream=sys.stdout, + format="%(asctime)s [File: %(filename)s:%(lineno)d] \t[Module: %(module)s]\t %(levelname)s: %(message)s", + datefmt="%m/%d/%Y %I:%M:%S %p", + level=logging.INFO, +) + +# OCI regions are fetched dynamically from the Identity API +# No hardcoded display names - following AWS regions updater pattern +# This ensures full automation without manual maintenance + + +def setup_oci_client(): + """ + Set up OCI Identity client using credentials from environment variables. + + Returns: + oci.identity.IdentityClient: Authenticated OCI Identity client + + Raises: + ValueError: If required environment variables are missing + Exception: If authentication fails + """ + logging.info("Setting up OCI client authentication") + + # Validate required environment variables + required_vars = [ + "OCI_CLI_USER", + "OCI_CLI_FINGERPRINT", + "OCI_CLI_TENANCY", + "OCI_CLI_KEY_CONTENT", + ] + + missing_vars = [var for var in required_vars if not os.getenv(var)] + if missing_vars: + raise ValueError( + f"Missing required environment variables: {', '.join(missing_vars)}" + ) + + # Get credentials from environment + user_ocid = os.getenv("OCI_CLI_USER") + fingerprint = os.getenv("OCI_CLI_FINGERPRINT") + tenancy_ocid = os.getenv("OCI_CLI_TENANCY") + key_content_b64 = os.getenv("OCI_CLI_KEY_CONTENT") + region = os.getenv("OCI_CLI_REGION", "us-ashburn-1") + + # Decode base64 private key + try: + key_content = base64.b64decode(key_content_b64).decode("utf-8") + except Exception as e: + raise ValueError(f"Failed to decode OCI_CLI_KEY_CONTENT: {e}") + + # Create OCI config dictionary + config = { + "user": user_ocid, + "fingerprint": fingerprint, + "tenancy": tenancy_ocid, + "key_content": key_content, + "region": region, + } + + # Initialize Identity client + try: + identity_client = oci.identity.IdentityClient(config) + logging.info(f"Successfully authenticated to OCI region: {region}") + return identity_client + except Exception as e: + raise Exception(f"Failed to create OCI Identity client: {e}") + + +def fetch_oci_regions(identity_client): + """ + Fetch all OCI commercial regions using the Identity service API. + + Args: + identity_client (oci.identity.IdentityClient): Authenticated OCI client + + Returns: + dict: Dictionary mapping region identifiers to themselves (for consistency) + + Raises: + Exception: If API call fails + """ + logging.info("Fetching OCI commercial regions from Identity service") + + try: + # Call list_regions() API - returns all OC1 commercial regions + response = identity_client.list_regions() + regions = response.data + + logging.info(f"Successfully fetched {len(regions)} regions from OCI API") + + # Build region dictionary (region_id -> region_id) + # Following AWS pattern: no display names, fully automated + region_dict = {} + for region in regions: + region_id = region.name + region_dict[region_id] = region_id + logging.debug(f"Added region: {region_id}") + + # Sort regions alphabetically by key + region_dict = dict(sorted(region_dict.items())) + + logging.info(f"Processed {len(region_dict)} commercial regions") + return region_dict + + except Exception as e: + raise Exception(f"Failed to fetch OCI regions: {e}") + + +def update_config_file(regions, config_file_path): + """ + Update the OCI config file with new commercial regions while preserving government regions. + + Args: + regions (dict): Dictionary of region identifiers to region identifiers + config_file_path (str): Path to the config.py file + + Raises: + Exception: If file operations fail or validation fails + """ + logging.info(f"Updating config file: {config_file_path}") + + # Read current config file + try: + with open(config_file_path, "r") as f: + config_content = f.read() + except Exception as e: + raise Exception(f"Failed to read config file: {e}") + + # Generate new OCI_COMMERCIAL_REGIONS dictionary + new_regions_dict = "OCI_COMMERCIAL_REGIONS = {\n" + for region_id in regions.keys(): + new_regions_dict += f' "{region_id}": "{region_id}",\n' + new_regions_dict += "}" + + # Replace OCI_COMMERCIAL_REGIONS using regex + pattern = r"OCI_COMMERCIAL_REGIONS\s*=\s*\{[^}]*\}" + updated_content = re.sub(pattern, new_regions_dict, config_content) + + # Validate that government regions still exist + if "OCI_GOVERNMENT_REGIONS" not in updated_content: + raise Exception( + "Validation failed: OCI_GOVERNMENT_REGIONS section missing after update. Aborting to prevent data loss." + ) + + # Verify the replacement was successful + if updated_content == config_content: + logging.warning("No changes detected in config file") + return + + # Write updated content back to file + try: + with open(config_file_path, "w") as f: + f.write(updated_content) + logging.info("Successfully updated config file") + except Exception as e: + raise Exception(f"Failed to write updated config file: {e}") + + # Log summary of changes + logging.info(f"Updated OCI_COMMERCIAL_REGIONS with {len(regions)} regions") + + +def main(): + """ + Main execution function for OCI regions updater. + """ + try: + # Setup OCI client with authentication + identity_client = setup_oci_client() + + # Fetch all commercial regions from OCI API + commercial_regions = fetch_oci_regions(identity_client) + + # Update config.py file + config_file_path = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "..", + "prowler", + "providers", + "oraclecloud", + "config.py", + ) + + update_config_file(commercial_regions, config_file_path) + + logging.info("OCI regions update completed successfully") + return 0 + + except Exception as e: + logging.error(f"Error during OCI regions update: {e}") + return 1 + + +if __name__ == "__main__": + sys.exit(main()) From b94c8a5e5e7620893af3de2023d6efa79cdc8f50 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:40:19 +0100 Subject: [PATCH 10/12] feat(api): add OpenStack provider support (#10003) --- api/CHANGELOG.md | 4 + .../api/migrations/0076_openstack_provider.py | 39 +++ api/src/backend/api/models.py | 10 + api/src/backend/api/specs/v1.yaml | 266 ++++++++++++++++++ api/src/backend/api/tests/test_utils.py | 6 + api/src/backend/api/tests/test_views.py | 42 ++- api/src/backend/api/utils.py | 25 +- .../api/v1/serializer_utils/providers.py | 15 + api/src/backend/api/v1/serializers.py | 10 + api/src/backend/config/django/testing.py | 4 + api/src/backend/conftest.py | 7 + prowler/CHANGELOG.md | 1 + prowler/providers/common/provider.py | 3 + .../providers/openstack/openstack_provider.py | 82 +++++- 14 files changed, 507 insertions(+), 7 deletions(-) create mode 100644 api/src/backend/api/migrations/0076_openstack_provider.py diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 5d7fd45567..226056afea 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to the **Prowler API** are documented in this file. ## [1.20.0] (Prowler UNRELEASED) +### 🚀 Added + +- OpenStack provider support [(#10003)](https://github.com/prowler-cloud/prowler/pull/10003) + ### 🔄 Changed - Attack Paths: Queries definition now has short description and attribution [(#9983)](https://github.com/prowler-cloud/prowler/pull/9983) diff --git a/api/src/backend/api/migrations/0076_openstack_provider.py b/api/src/backend/api/migrations/0076_openstack_provider.py new file mode 100644 index 0000000000..9cc80707ea --- /dev/null +++ b/api/src/backend/api/migrations/0076_openstack_provider.py @@ -0,0 +1,39 @@ +# Generated by Django migration for OpenStack provider support + +from django.db import migrations + +import api.db_utils + + +class Migration(migrations.Migration): + dependencies = [ + ("api", "0075_cloudflare_provider"), + ] + + operations = [ + migrations.AlterField( + model_name="provider", + name="provider", + field=api.db_utils.ProviderEnumField( + choices=[ + ("aws", "AWS"), + ("azure", "Azure"), + ("gcp", "GCP"), + ("kubernetes", "Kubernetes"), + ("m365", "M365"), + ("github", "GitHub"), + ("mongodbatlas", "MongoDB Atlas"), + ("iac", "IaC"), + ("oraclecloud", "Oracle Cloud Infrastructure"), + ("alibabacloud", "Alibaba Cloud"), + ("cloudflare", "Cloudflare"), + ("openstack", "OpenStack"), + ], + default="aws", + ), + ), + migrations.RunSQL( + "ALTER TYPE provider ADD VALUE IF NOT EXISTS 'openstack';", + reverse_sql=migrations.RunSQL.noop, + ), + ] diff --git a/api/src/backend/api/models.py b/api/src/backend/api/models.py index 4bda51761c..eb09bba683 100644 --- a/api/src/backend/api/models.py +++ b/api/src/backend/api/models.py @@ -288,6 +288,7 @@ class Provider(RowLevelSecurityProtectedModel): ORACLECLOUD = "oraclecloud", _("Oracle Cloud Infrastructure") ALIBABACLOUD = "alibabacloud", _("Alibaba Cloud") CLOUDFLARE = "cloudflare", _("Cloudflare") + OPENSTACK = "openstack", _("OpenStack") @staticmethod def validate_aws_uid(value): @@ -410,6 +411,15 @@ class Provider(RowLevelSecurityProtectedModel): pointer="/data/attributes/uid", ) + @staticmethod + def validate_openstack_uid(value): + if not re.match(r"^[a-zA-Z0-9][a-zA-Z0-9._-]{0,254}$", value): + raise ModelValidationError( + detail="OpenStack provider ID must be a valid project ID (UUID or project name).", + code="openstack-uid", + pointer="/data/attributes/uid", + ) + id = models.UUIDField(primary_key=True, default=uuid4, editable=False) inserted_at = models.DateTimeField(auto_now_add=True, editable=False) updated_at = models.DateTimeField(auto_now=True, editable=False) diff --git a/api/src/backend/api/specs/v1.yaml b/api/src/backend/api/specs/v1.yaml index ec5f9e6ec5..88d67c01c1 100644 --- a/api/src/backend/api/specs/v1.yaml +++ b/api/src/backend/api/specs/v1.yaml @@ -367,6 +367,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -380,6 +381,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -398,6 +400,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -413,6 +416,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -1348,6 +1352,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -1361,6 +1366,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -1379,6 +1385,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -1394,6 +1401,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -1938,6 +1946,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -1951,6 +1960,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -1969,6 +1979,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -1984,6 +1995,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -2436,6 +2448,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -2449,6 +2462,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -2467,6 +2481,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -2482,6 +2497,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -2932,6 +2948,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -2945,6 +2962,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -2963,6 +2981,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -2978,6 +2997,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -3416,6 +3436,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -3429,6 +3450,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -3447,6 +3469,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -3462,6 +3485,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -5241,6 +5265,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -5254,6 +5279,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -5272,6 +5298,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -5287,6 +5314,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - name: filter[search] @@ -5404,6 +5432,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -5417,6 +5446,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -5435,6 +5465,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -5450,6 +5481,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - name: filter[search] @@ -5556,6 +5588,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -5569,6 +5602,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -5586,6 +5620,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -5601,6 +5636,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - name: filter[search] @@ -5739,6 +5775,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -5752,6 +5789,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -5770,6 +5808,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -5785,6 +5824,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -5936,6 +5976,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -5949,6 +5990,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -5967,6 +6009,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -5982,6 +6025,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -6127,6 +6171,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -6140,6 +6185,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -6157,6 +6203,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -6172,6 +6219,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - name: filter[search] @@ -6359,6 +6407,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -6372,6 +6421,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -6390,6 +6440,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -6405,6 +6456,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -6521,6 +6573,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -6534,6 +6587,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -6552,6 +6606,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -6567,6 +6622,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -6707,6 +6763,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -6720,6 +6777,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -6738,6 +6796,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -6753,6 +6812,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -7534,6 +7594,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -7547,6 +7608,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider__in] schema: @@ -7565,6 +7627,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -7580,6 +7643,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -7598,6 +7662,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -7611,6 +7676,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -7629,6 +7695,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -7644,6 +7711,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - name: filter[search] @@ -8285,6 +8353,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -8298,6 +8367,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -8316,6 +8386,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -8331,6 +8402,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -8787,6 +8859,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -8800,6 +8873,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -8818,6 +8892,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -8833,6 +8908,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -9102,6 +9178,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -9115,6 +9192,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -9133,6 +9211,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -9148,6 +9227,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -9423,6 +9503,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -9436,6 +9517,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -9454,6 +9536,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -9469,6 +9552,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -10278,6 +10362,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- * `aws` - AWS @@ -10291,6 +10376,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack - in: query name: filter[provider_type__in] schema: @@ -10309,6 +10395,7 @@ paths: - kubernetes - m365 - mongodbatlas + - openstack - oraclecloud description: |- Multiple values may be separated by commas. @@ -10324,6 +10411,7 @@ paths: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack explode: false style: form - in: query @@ -17348,6 +17436,50 @@ components: required: - api_key - api_email + - type: object + title: OpenStack clouds.yaml Credentials + properties: + clouds_yaml_content: + type: string + description: The full content of a clouds.yaml configuration + file. + clouds_yaml_cloud: + type: string + description: The name of the cloud to use from the clouds.yaml + file. + required: + - clouds_yaml_content + - clouds_yaml_cloud + - type: object + title: OpenStack Explicit Credentials + properties: + auth_url: + type: string + description: OpenStack Keystone authentication URL (e.g., + https://openstack.example.com:5000/v3). + username: + type: string + description: OpenStack username for authentication. + password: + type: string + description: OpenStack password for authentication. + region_name: + type: string + description: OpenStack region name (e.g., RegionOne). + identity_api_version: + type: string + description: Keystone API version (default: 3). + user_domain_name: + type: string + description: User domain name (default: Default). + project_domain_name: + type: string + description: Project domain name (default: Default). + required: + - auth_url + - username + - password + - region_name writeOnly: true required: - secret @@ -18347,6 +18479,7 @@ components: - oraclecloud - alibabacloud - cloudflare + - openstack type: string description: |- * `aws` - AWS @@ -18360,6 +18493,7 @@ components: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack x-spec-enum-id: 2d8d323e9cc0044b uid: type: string @@ -18477,6 +18611,7 @@ components: - oraclecloud - alibabacloud - cloudflare + - openstack type: string x-spec-enum-id: 2d8d323e9cc0044b description: |- @@ -18493,6 +18628,7 @@ components: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack uid: type: string title: Unique identifier for the provider, set by the provider @@ -18541,6 +18677,7 @@ components: - oraclecloud - alibabacloud - cloudflare + - openstack type: string x-spec-enum-id: 2d8d323e9cc0044b description: |- @@ -18557,6 +18694,7 @@ components: * `oraclecloud` - Oracle Cloud Infrastructure * `alibabacloud` - Alibaba Cloud * `cloudflare` - Cloudflare + * `openstack` - OpenStack uid: type: string minLength: 3 @@ -19378,6 +19516,48 @@ components: required: - api_key - api_email + - type: object + title: OpenStack clouds.yaml Credentials + properties: + clouds_yaml_content: + type: string + description: The full content of a clouds.yaml configuration file. + clouds_yaml_cloud: + type: string + description: The name of the cloud to use from the clouds.yaml + file. + required: + - clouds_yaml_content + - clouds_yaml_cloud + - type: object + title: OpenStack Explicit Credentials + properties: + auth_url: + type: string + description: OpenStack Keystone authentication URL (e.g., https://openstack.example.com:5000/v3). + username: + type: string + description: OpenStack username for authentication. + password: + type: string + description: OpenStack password for authentication. + region_name: + type: string + description: OpenStack region name (e.g., RegionOne). + identity_api_version: + type: string + description: Keystone API version (default: 3). + user_domain_name: + type: string + description: User domain name (default: Default). + project_domain_name: + type: string + description: Project domain name (default: Default). + required: + - auth_url + - username + - password + - region_name writeOnly: true required: - secret_type @@ -19764,6 +19944,50 @@ components: required: - api_key - api_email + - type: object + title: OpenStack clouds.yaml Credentials + properties: + clouds_yaml_content: + type: string + description: The full content of a clouds.yaml configuration + file. + clouds_yaml_cloud: + type: string + description: The name of the cloud to use from the clouds.yaml + file. + required: + - clouds_yaml_content + - clouds_yaml_cloud + - type: object + title: OpenStack Explicit Credentials + properties: + auth_url: + type: string + description: OpenStack Keystone authentication URL (e.g., + https://openstack.example.com:5000/v3). + username: + type: string + description: OpenStack username for authentication. + password: + type: string + description: OpenStack password for authentication. + region_name: + type: string + description: OpenStack region name (e.g., RegionOne). + identity_api_version: + type: string + description: Keystone API version (default: 3). + user_domain_name: + type: string + description: User domain name (default: Default). + project_domain_name: + type: string + description: Project domain name (default: Default). + required: + - auth_url + - username + - password + - region_name writeOnly: true required: - secret_type @@ -20162,6 +20386,48 @@ components: required: - api_key - api_email + - type: object + title: OpenStack clouds.yaml Credentials + properties: + clouds_yaml_content: + type: string + description: The full content of a clouds.yaml configuration file. + clouds_yaml_cloud: + type: string + description: The name of the cloud to use from the clouds.yaml + file. + required: + - clouds_yaml_content + - clouds_yaml_cloud + - type: object + title: OpenStack Explicit Credentials + properties: + auth_url: + type: string + description: OpenStack Keystone authentication URL (e.g., https://openstack.example.com:5000/v3). + username: + type: string + description: OpenStack username for authentication. + password: + type: string + description: OpenStack password for authentication. + region_name: + type: string + description: OpenStack region name (e.g., RegionOne). + identity_api_version: + type: string + description: Keystone API version (default: 3). + user_domain_name: + type: string + description: User domain name (default: Default). + project_domain_name: + type: string + description: Project domain name (default: Default). + required: + - auth_url + - username + - password + - region_name writeOnly: true required: - secret diff --git a/api/src/backend/api/tests/test_utils.py b/api/src/backend/api/tests/test_utils.py index 56f98a5401..236cbf87a2 100644 --- a/api/src/backend/api/tests/test_utils.py +++ b/api/src/backend/api/tests/test_utils.py @@ -27,6 +27,7 @@ from prowler.providers.iac.iac_provider import IacProvider from prowler.providers.kubernetes.kubernetes_provider import KubernetesProvider from prowler.providers.m365.m365_provider import M365Provider from prowler.providers.mongodbatlas.mongodbatlas_provider import MongodbatlasProvider +from prowler.providers.openstack.openstack_provider import OpenstackProvider from prowler.providers.oraclecloud.oraclecloud_provider import OraclecloudProvider @@ -120,6 +121,7 @@ class TestReturnProwlerProvider: (Provider.ProviderChoices.IAC.value, IacProvider), (Provider.ProviderChoices.ALIBABACLOUD.value, AlibabacloudProvider), (Provider.ProviderChoices.CLOUDFLARE.value, CloudflareProvider), + (Provider.ProviderChoices.OPENSTACK.value, OpenstackProvider), ], ) def test_return_prowler_provider(self, provider_type, expected_provider): @@ -227,6 +229,10 @@ class TestGetProwlerProviderKwargs: Provider.ProviderChoices.CLOUDFLARE.value, {"filter_accounts": ["provider_uid"]}, ), + ( + Provider.ProviderChoices.OPENSTACK.value, + {}, + ), ], ) def test_get_prowler_provider_kwargs(self, provider_type, expected_extra_kwargs): diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index c9f2746cfe..02aefa18ff 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -1179,6 +1179,11 @@ class TestProviderViewSet: "uid": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", "alias": "Cloudflare Account", }, + { + "provider": "openstack", + "uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "alias": "OpenStack Project", + }, ] ), ) @@ -1598,6 +1603,26 @@ class TestProviderViewSet: "cloudflare-uid", "uid", ), + # OpenStack UID validation - starts with special character + ( + { + "provider": "openstack", + "uid": "-invalid-project", + "alias": "test", + }, + "openstack-uid", + "uid", + ), + # OpenStack UID validation - too short (below min_length) + ( + { + "provider": "openstack", + "uid": "ab", + "alias": "test", + }, + "min_length", + "uid", + ), ] ), ) @@ -1771,21 +1796,21 @@ class TestProviderViewSet: ( "uid.icontains", "1", - 9, + 10, ), ("alias", "aws_testing_1", 1), ("alias.icontains", "aws", 2), - ("inserted_at", TODAY, 10), + ("inserted_at", TODAY, 11), ( "inserted_at.gte", "2024-01-01", - 10, + 11, ), ("inserted_at.lte", "2024-01-01", 0), ( "updated_at.gte", "2024-01-01", - 10, + 11, ), ("updated_at.lte", "2024-01-01", 0), ] @@ -2392,6 +2417,15 @@ class TestProviderSecretViewSet: "api_email": "user@example.com", }, ), + # OpenStack with clouds.yaml content + ( + Provider.ProviderChoices.OPENSTACK.value, + ProviderSecret.TypeChoices.STATIC, + { + "clouds_yaml_content": "clouds:\n mycloud:\n auth:\n auth_url: https://openstack.example.com:5000/v3\n", + "clouds_yaml_cloud": "mycloud", + }, + ), ], ) def test_provider_secrets_create_valid( diff --git a/api/src/backend/api/utils.py b/api/src/backend/api/utils.py index 343537efa9..355c3b6e03 100644 --- a/api/src/backend/api/utils.py +++ b/api/src/backend/api/utils.py @@ -33,6 +33,7 @@ if TYPE_CHECKING: from prowler.providers.mongodbatlas.mongodbatlas_provider import ( MongodbatlasProvider, ) + from prowler.providers.openstack.openstack_provider import OpenstackProvider from prowler.providers.oraclecloud.oraclecloud_provider import OraclecloudProvider @@ -78,12 +79,14 @@ def return_prowler_provider( AlibabacloudProvider | AwsProvider | AzureProvider + | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider + | OpenstackProvider | OraclecloudProvider ): """Return the Prowler provider class based on the given provider type. @@ -92,7 +95,7 @@ def return_prowler_provider( provider (Provider): The provider object containing the provider type and associated secrets. Returns: - AlibabacloudProvider | AwsProvider | AzureProvider | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider | OraclecloudProvider: The corresponding provider class. + AlibabacloudProvider | AwsProvider | AzureProvider | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider | OpenstackProvider | OraclecloudProvider: The corresponding provider class. Raises: ValueError: If the provider type specified in `provider.provider` is not supported. @@ -152,6 +155,10 @@ def return_prowler_provider( ) prowler_provider = CloudflareProvider + case Provider.ProviderChoices.OPENSTACK.value: + from prowler.providers.openstack.openstack_provider import OpenstackProvider + + prowler_provider = OpenstackProvider case _: raise ValueError(f"Provider type {provider.provider} not supported") return prowler_provider @@ -208,6 +215,12 @@ def get_prowler_provider_kwargs( **prowler_provider_kwargs, "filter_accounts": [provider.uid], } + elif provider.provider == Provider.ProviderChoices.OPENSTACK.value: + # No extra kwargs needed: clouds_yaml_content and clouds_yaml_cloud from the + # secret are sufficient. Validating project_id (provider.uid) against the + # clouds.yaml is not feasible because not all auth methods include it and the + # Keystone API is unavailable on public clouds. + pass if mutelist_processor: mutelist_content = mutelist_processor.configuration.get("Mutelist", {}) @@ -232,6 +245,7 @@ def initialize_prowler_provider( | KubernetesProvider | M365Provider | MongodbatlasProvider + | OpenstackProvider | OraclecloudProvider ): """Initialize a Prowler provider instance based on the given provider type. @@ -241,7 +255,7 @@ def initialize_prowler_provider( mutelist_processor (Processor): The mutelist processor object containing the mutelist configuration. Returns: - AlibabacloudProvider | AwsProvider | AzureProvider | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider | OraclecloudProvider: An instance of the corresponding provider class + AlibabacloudProvider | AwsProvider | AzureProvider | CloudflareProvider | GcpProvider | GithubProvider | IacProvider | KubernetesProvider | M365Provider | MongodbatlasProvider | OpenstackProvider | OraclecloudProvider: An instance of the corresponding provider class initialized with the provider's secrets. """ prowler_provider = return_prowler_provider(provider) @@ -276,6 +290,13 @@ def prowler_provider_connection_test(provider: Provider) -> Connection: if "access_token" in prowler_provider_kwargs: iac_test_kwargs["access_token"] = prowler_provider_kwargs["access_token"] return prowler_provider.test_connection(**iac_test_kwargs) + elif provider.provider == Provider.ProviderChoices.OPENSTACK.value: + openstack_kwargs = { + "clouds_yaml_content": prowler_provider_kwargs["clouds_yaml_content"], + "clouds_yaml_cloud": prowler_provider_kwargs["clouds_yaml_cloud"], + "raise_on_exception": False, + } + return prowler_provider.test_connection(**openstack_kwargs) else: return prowler_provider.test_connection( **prowler_provider_kwargs, diff --git a/api/src/backend/api/v1/serializer_utils/providers.py b/api/src/backend/api/v1/serializer_utils/providers.py index 7b34b06d2b..83ea942793 100644 --- a/api/src/backend/api/v1/serializer_utils/providers.py +++ b/api/src/backend/api/v1/serializer_utils/providers.py @@ -373,6 +373,21 @@ from rest_framework_json_api import serializers }, "required": ["api_key", "api_email"], }, + { + "type": "object", + "title": "OpenStack clouds.yaml Credentials", + "properties": { + "clouds_yaml_content": { + "type": "string", + "description": "The full content of a clouds.yaml configuration file.", + }, + "clouds_yaml_cloud": { + "type": "string", + "description": "The name of the cloud to use from the clouds.yaml file.", + }, + }, + "required": ["clouds_yaml_content", "clouds_yaml_cloud"], + }, ] } ) diff --git a/api/src/backend/api/v1/serializers.py b/api/src/backend/api/v1/serializers.py index 6c42d83aa5..d97a952bc3 100644 --- a/api/src/backend/api/v1/serializers.py +++ b/api/src/backend/api/v1/serializers.py @@ -1525,6 +1525,8 @@ class BaseWriteProviderSecretSerializer(BaseWriteSerializer): "or both 'api_key' and 'api_email'." } ) + elif provider_type == Provider.ProviderChoices.OPENSTACK.value: + serializer = OpenStackCloudsYamlProviderSecret(data=secret) else: raise serializers.ValidationError( {"provider": f"Provider type not supported {provider_type}"} @@ -1691,6 +1693,14 @@ class CloudflareApiKeyProviderSecret(serializers.Serializer): resource_name = "provider-secrets" +class OpenStackCloudsYamlProviderSecret(serializers.Serializer): + clouds_yaml_content = serializers.CharField() + clouds_yaml_cloud = serializers.CharField() + + class Meta: + resource_name = "provider-secrets" + + class AlibabaCloudProviderSecret(serializers.Serializer): access_key_id = serializers.CharField() access_key_secret = serializers.CharField() diff --git a/api/src/backend/config/django/testing.py b/api/src/backend/config/django/testing.py index 5289f067fa..75779f5a68 100644 --- a/api/src/backend/config/django/testing.py +++ b/api/src/backend/config/django/testing.py @@ -18,6 +18,10 @@ DATABASES = { DATABASE_ROUTERS = [] TESTING = True +# Override page size for testing to a value only slightly above the current fixture count. +# We explicitly set PAGE_SIZE to 15 (round number just above fixture) to avoid masking pagination bugs, while not setting it excessively high. +# If you add more providers to the fixture, please review that the total value is below the current one and update this value if needed. +REST_FRAMEWORK["PAGE_SIZE"] = 15 # noqa: F405 SECRETS_ENCRYPTION_KEY = "ZMiYVo7m4Fbe2eXXPyrwxdJss2WSalXSv3xHBcJkPl0=" # DRF Simple API Key settings diff --git a/api/src/backend/conftest.py b/api/src/backend/conftest.py index 00617017bb..e2c22e5112 100644 --- a/api/src/backend/conftest.py +++ b/api/src/backend/conftest.py @@ -537,6 +537,12 @@ def providers_fixture(tenants_fixture): alias="cloudflare_testing", tenant_id=tenant.id, ) + provider11 = Provider.objects.create( + provider="openstack", + uid="a1b2c3d4-e5f6-7890-abcd-ef1234567890", + alias="openstack_testing", + tenant_id=tenant.id, + ) return ( provider1, @@ -549,6 +555,7 @@ def providers_fixture(tenants_fixture): provider8, provider9, provider10, + provider11, ) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index a0128d64fe..773776ce20 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to the **Prowler SDK** are documented in this file. ### 🚀 Added +- OpenStack provider `clouds_yaml_content` parameter for API integration [(#10003)](https://github.com/prowler-cloud/prowler/pull/10003) - `defender_safe_attachments_policy_enabled` check for M365 provider [(#9833)](https://github.com/prowler-cloud/prowler/pull/9833) - `defender_safelinks_policy_enabled` check for M365 provider [(#9832)](https://github.com/prowler-cloud/prowler/pull/9832) - AI Skills: Added a skill for creating new Attack Paths queries in openCypher, compatible with Neo4j and Neptune [(#9975)](https://github.com/prowler-cloud/prowler/pull/9975) diff --git a/prowler/providers/common/provider.py b/prowler/providers/common/provider.py index 0ffe15e825..339220df30 100644 --- a/prowler/providers/common/provider.py +++ b/prowler/providers/common/provider.py @@ -297,6 +297,9 @@ class Provider(ABC): elif "openstack" in provider_class_name.lower(): provider_class( clouds_yaml_file=getattr(arguments, "clouds_yaml_file", None), + clouds_yaml_content=getattr( + arguments, "clouds_yaml_content", None + ), clouds_yaml_cloud=getattr(arguments, "clouds_yaml_cloud", None), auth_url=getattr(arguments, "os_auth_url", None), identity_api_version=getattr( diff --git a/prowler/providers/openstack/openstack_provider.py b/prowler/providers/openstack/openstack_provider.py index fd8e2e005a..d892dc1abb 100644 --- a/prowler/providers/openstack/openstack_provider.py +++ b/prowler/providers/openstack/openstack_provider.py @@ -6,6 +6,7 @@ from colorama import Fore, Style from openstack import config, connect from openstack import exceptions as openstack_exceptions from openstack.connection import Connection as OpenStackConnection +from yaml import YAMLError, safe_load from prowler.config.config import ( default_config_file_path, @@ -49,6 +50,7 @@ class OpenstackProvider(Provider): def __init__( self, clouds_yaml_file: Optional[str] = None, + clouds_yaml_content: Optional[str] = None, clouds_yaml_cloud: Optional[str] = None, auth_url: Optional[str] = None, identity_api_version: Optional[str] = None, @@ -68,6 +70,7 @@ class OpenstackProvider(Provider): self._session = self.setup_session( clouds_yaml_file=clouds_yaml_file, + clouds_yaml_content=clouds_yaml_content, clouds_yaml_cloud=clouds_yaml_cloud, auth_url=auth_url, identity_api_version=identity_api_version, @@ -132,6 +135,7 @@ class OpenstackProvider(Provider): @staticmethod def setup_session( clouds_yaml_file: Optional[str] = None, + clouds_yaml_content: Optional[str] = None, clouds_yaml_cloud: Optional[str] = None, auth_url: Optional[str] = None, identity_api_version: Optional[str] = None, @@ -145,10 +149,16 @@ class OpenstackProvider(Provider): """Collect authentication information from clouds.yaml, explicit parameters, or environment variables. Authentication priority: - 1. clouds.yaml file (if clouds_yaml_file or clouds_yaml_cloud provided) + 1. clouds.yaml content/file (if clouds_yaml_content, clouds_yaml_file, or clouds_yaml_cloud provided) 2. Explicit parameters + environment variable fallback """ # Priority 1: clouds.yaml authentication + if clouds_yaml_content: + logger.info("Using clouds.yaml content string for authentication") + return OpenstackProvider._setup_session_from_clouds_yaml_content( + clouds_yaml_content=clouds_yaml_content, + clouds_yaml_cloud=clouds_yaml_cloud, + ) if clouds_yaml_file or clouds_yaml_cloud: logger.info("Using clouds.yaml configuration for authentication") return OpenstackProvider._setup_session_from_clouds_yaml( @@ -203,6 +213,73 @@ class OpenstackProvider(Provider): project_domain_name=resolved_project_domain, ) + @staticmethod + def _setup_session_from_clouds_yaml_content( + clouds_yaml_content: str, + clouds_yaml_cloud: Optional[str] = None, + ) -> OpenStackSession: + """Setup session from clouds.yaml content provided as a string. + + Parses the YAML content directly instead of writing to a temporary file, + following the same pattern as KubernetesProvider.setup_session(). + + Args: + clouds_yaml_content: The full YAML content of a clouds.yaml file. + clouds_yaml_cloud: Cloud name to use from the clouds.yaml content. + + Returns: + OpenStackSession configured from the provided clouds.yaml content. + + Raises: + OpenStackInvalidConfigError: If the YAML is malformed or missing required fields. + OpenStackCloudNotFoundError: If the specified cloud is not found in the content. + """ + if not clouds_yaml_cloud: + raise OpenStackInvalidConfigError( + message="Cloud name (--clouds-yaml-cloud) is required when using clouds.yaml content", + ) + + try: + parsed = safe_load(clouds_yaml_content) + except YAMLError as error: + raise OpenStackInvalidConfigError( + original_exception=error, + message=f"Failed to parse clouds.yaml content: {error}", + ) + + if not isinstance(parsed, dict) or "clouds" not in parsed: + raise OpenStackInvalidConfigError( + message="Invalid clouds.yaml content: missing 'clouds' key", + ) + + cloud_config = parsed["clouds"].get(clouds_yaml_cloud) + if not cloud_config: + raise OpenStackCloudNotFoundError( + message=f"Cloud '{clouds_yaml_cloud}' not found in clouds.yaml content", + ) + + auth_dict = cloud_config.get("auth", {}) + + required_fields = ["auth_url", "username", "password"] + missing_fields = [ + field for field in required_fields if not auth_dict.get(field) + ] + if missing_fields: + raise OpenStackInvalidConfigError( + message=f"Missing required fields in clouds.yaml for cloud '{clouds_yaml_cloud}': {', '.join(missing_fields)}", + ) + + return OpenStackSession( + auth_url=auth_dict.get("auth_url"), + identity_api_version=str(cloud_config.get("identity_api_version", "3")), + username=auth_dict.get("username"), + password=auth_dict.get("password"), + project_id=auth_dict.get("project_id") or auth_dict.get("project_name"), + region_name=cloud_config.get("region_name"), + user_domain_name=auth_dict.get("user_domain_name", "Default"), + project_domain_name=auth_dict.get("project_domain_name", "Default"), + ) + @staticmethod def _setup_session_from_clouds_yaml( clouds_yaml_file: Optional[str] = None, @@ -394,6 +471,7 @@ class OpenstackProvider(Provider): @staticmethod def test_connection( clouds_yaml_file: Optional[str] = None, + clouds_yaml_content: Optional[str] = None, clouds_yaml_cloud: Optional[str] = None, auth_url: Optional[str] = None, identity_api_version: Optional[str] = None, @@ -412,6 +490,7 @@ class OpenstackProvider(Provider): Args: clouds_yaml_file: Path to clouds.yaml configuration file + clouds_yaml_content: The full content of a clouds.yaml file as a string clouds_yaml_cloud: Cloud name from clouds.yaml to use auth_url: OpenStack Keystone authentication URL identity_api_version: Keystone API version (default: "3") @@ -456,6 +535,7 @@ class OpenstackProvider(Provider): # Setup session with provided credentials session = OpenstackProvider.setup_session( clouds_yaml_file=clouds_yaml_file, + clouds_yaml_content=clouds_yaml_content, clouds_yaml_cloud=clouds_yaml_cloud, auth_url=auth_url, identity_api_version=identity_api_version, From aa7490aab4d634f29f63bd10b3acce47f3ad2d48 Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Thu, 12 Feb 2026 16:36:48 +0100 Subject: [PATCH 11/12] feat(image): add container image provider for CLI scanning (#9984) --- prowler/CHANGELOG.md | 1 + prowler/__main__.py | 23 +- prowler/config/config.py | 10 +- prowler/lib/check/models.py | 57 +- prowler/lib/check/utils.py | 4 +- prowler/lib/cli/parser.py | 5 +- prowler/lib/outputs/finding.py | 17 + prowler/lib/outputs/summary_table.py | 3 + prowler/providers/common/provider.py | 12 + prowler/providers/image/__init__.py | 0 .../providers/image/exceptions/__init__.py | 0 .../providers/image/exceptions/exceptions.py | 164 ++++ prowler/providers/image/image_provider.py | 707 ++++++++++++++++++ prowler/providers/image/lib/__init__.py | 0 .../providers/image/lib/arguments/__init__.py | 0 .../image/lib/arguments/arguments.py | 103 +++ prowler/providers/image/models.py | 21 + tests/lib/cli/parser_test.py | 3 +- tests/providers/image/image_fixtures.py | 92 +++ tests/providers/image/image_provider_test.py | 595 +++++++++++++++ 20 files changed, 1793 insertions(+), 24 deletions(-) create mode 100644 prowler/providers/image/__init__.py create mode 100644 prowler/providers/image/exceptions/__init__.py create mode 100644 prowler/providers/image/exceptions/exceptions.py create mode 100644 prowler/providers/image/image_provider.py create mode 100644 prowler/providers/image/lib/__init__.py create mode 100644 prowler/providers/image/lib/arguments/__init__.py create mode 100644 prowler/providers/image/lib/arguments/arguments.py create mode 100644 prowler/providers/image/models.py create mode 100644 tests/providers/image/image_fixtures.py create mode 100644 tests/providers/image/image_provider_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 773776ce20..c4c53ef93b 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - CSA CCM 4.0 for the GCP provider [(#10042)](https://github.com/prowler-cloud/prowler/pull/10042) - CSA CCM for the Azure provider [(#10039)](https://github.com/prowler-cloud/prowler/pull/10039) - OCI regions updater script and CI workflow [(#10020)](https://github.com/prowler-cloud/prowler/pull/10020) +- `image` provider for container image scanning with Trivy integration [(#9984)](https://github.com/prowler-cloud/prowler/pull/9984) ### 🔄 Changed diff --git a/prowler/__main__.py b/prowler/__main__.py index 121642c675..2d7f7df1cb 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -8,6 +8,7 @@ from colorama import Fore, Style from colorama import init as colorama_init from prowler.config.config import ( + EXTERNAL_TOOL_PROVIDERS, csv_file_suffix, get_available_compliance_frameworks, html_file_suffix, @@ -122,6 +123,8 @@ from prowler.providers.common.quick_inventory import run_provider_quick_inventor from prowler.providers.gcp.models import GCPOutputOptions from prowler.providers.github.models import GithubOutputOptions from prowler.providers.iac.models import IACOutputOptions +from prowler.providers.image.exceptions.exceptions import ImageBaseException +from prowler.providers.image.models import ImageOutputOptions from prowler.providers.kubernetes.models import KubernetesOutputOptions from prowler.providers.llm.models import LLMOutputOptions from prowler.providers.m365.models import M365OutputOptions @@ -209,8 +212,8 @@ def prowler(): # Load compliance frameworks logger.debug("Loading compliance frameworks from .json files") - # Skip compliance frameworks for IAC and LLM providers - if provider != "iac" and provider != "llm": + # Skip compliance frameworks for external-tool providers + if provider not in EXTERNAL_TOOL_PROVIDERS: bulk_compliance_frameworks = Compliance.get_bulk(provider) # Complete checks metadata with the compliance framework specification bulk_checks_metadata = update_checks_metadata_with_compliance( @@ -267,8 +270,8 @@ def prowler(): if not args.only_logs: global_provider.print_credentials() - # Skip service and check loading for IAC and LLM providers - if provider != "iac" and provider != "llm": + # Skip service and check loading for external-tool providers + if provider not in EXTERNAL_TOOL_PROVIDERS: # Import custom checks from folder if checks_folder: custom_checks = parse_checks_from_folder(global_provider, checks_folder) @@ -355,6 +358,8 @@ def prowler(): ) elif provider == "iac": output_options = IACOutputOptions(args, bulk_checks_metadata) + elif provider == "image": + output_options = ImageOutputOptions(args, bulk_checks_metadata) elif provider == "llm": output_options = LLMOutputOptions(args, bulk_checks_metadata) elif provider == "oraclecloud": @@ -378,8 +383,8 @@ def prowler(): # Execute checks findings = [] - if provider == "iac" or provider == "llm": - # For IAC and LLM providers, run the scan directly + if provider in EXTERNAL_TOOL_PROVIDERS: + # For external-tool providers, run the scan directly if provider == "llm": def streaming_callback(findings_batch): @@ -389,7 +394,11 @@ def prowler(): findings = global_provider.run_scan(streaming_callback=streaming_callback) else: # Original behavior for IAC or non-verbose LLM - findings = global_provider.run() + try: + findings = global_provider.run() + except ImageBaseException as error: + logger.critical(f"{error}") + sys.exit(1) # Note: IaC doesn't support granular progress tracking since Trivy runs as a black box # and returns all findings at once. Progress tracking would just be 0% → 100%. diff --git a/prowler/config/config.py b/prowler/config/config.py index daa7378280..77674c7f93 100644 --- a/prowler/config/config.py +++ b/prowler/config/config.py @@ -63,8 +63,13 @@ class Provider(str, Enum): ORACLECLOUD = "oraclecloud" ALIBABACLOUD = "alibabacloud" OPENSTACK = "openstack" + IMAGE = "image" +# Providers that delegate scanning to an external tool (e.g. Trivy, promptfoo) +# and bypass standard check/service loading. +EXTERNAL_TOOL_PROVIDERS = frozenset({"iac", "llm", "image"}) + # Compliance actual_directory = pathlib.Path(os.path.dirname(os.path.realpath(__file__))) @@ -75,7 +80,10 @@ def get_available_compliance_frameworks(provider=None): if provider: providers = [provider] for provider in providers: - with os.scandir(f"{actual_directory}/../compliance/{provider}") as files: + compliance_dir = f"{actual_directory}/../compliance/{provider}" + if not os.path.isdir(compliance_dir): + continue + with os.scandir(compliance_dir) as files: for file in files: if file.is_file() and file.name.endswith(".json"): available_compliance_frameworks.append( diff --git a/prowler/lib/check/models.py b/prowler/lib/check/models.py index 3ec9a10f47..648b962039 100644 --- a/prowler/lib/check/models.py +++ b/prowler/lib/check/models.py @@ -10,7 +10,7 @@ from typing import Any, Dict, Optional, Set from pydantic.v1 import BaseModel, Field, ValidationError, validator from pydantic.v1.error_wrappers import ErrorWrapper -from prowler.config.config import Provider +from prowler.config.config import EXTERNAL_TOOL_PROVIDERS, Provider from prowler.lib.check.compliance_models import Compliance from prowler.lib.check.utils import recover_checks_from_provider from prowler.lib.logger import logger @@ -159,11 +159,7 @@ class CheckMetadata(BaseModel): raise ValueError("ServiceName must be a non-empty string") check_id = values.get("CheckID") - if ( - check_id - and values.get("Provider") != "iac" - and values.get("Provider") != "llm" - ): + if check_id and values.get("Provider") not in EXTERNAL_TOOL_PROVIDERS: service_from_check_id = check_id.split("_")[0] if service_name != service_from_check_id: raise ValueError( @@ -179,11 +175,7 @@ class CheckMetadata(BaseModel): if not check_id: raise ValueError("CheckID must be a non-empty string") - if ( - check_id - and values.get("Provider") != "iac" - and values.get("Provider") != "llm" - ): + if check_id and values.get("Provider") not in EXTERNAL_TOOL_PROVIDERS: if "-" in check_id: raise ValueError( f"CheckID {check_id} contains a hyphen, which is not allowed" @@ -865,6 +857,49 @@ class CheckReportIAC(Check_Report): ) +@dataclass +class CheckReportImage(Check_Report): + """Contains the Container Image Check's finding information using Trivy.""" + + resource_name: str + resource_id: str + image_digest: str + package_name: str + installed_version: str + fixed_version: str + + def __init__( + self, + metadata: Optional[dict] = None, + finding: Optional[dict] = None, + image_name: str = "", + ) -> None: + """ + Initialize the Container Image Check's finding information from a Trivy vulnerability/secret dict. + + Args: + metadata (Dict): Check metadata. + finding (dict): A single vulnerability/secret result from Trivy's JSON output. + image_name (str): The container image name being scanned. + """ + if metadata is None: + metadata = {} + if finding is None: + finding = {} + super().__init__(metadata, finding) + + self.resource_name = image_name + self.resource_id = ( + finding.get("VulnerabilityID", "") + or finding.get("RuleID", "") + or finding.get("ID", "") + ) + self.image_digest = finding.get("PkgID", "") + self.package_name = finding.get("PkgName", "") + self.installed_version = finding.get("InstalledVersion", "") + self.fixed_version = finding.get("FixedVersion", "") + + @dataclass class CheckReportLLM(Check_Report): """Contains the LLM Check's finding information.""" diff --git a/prowler/lib/check/utils.py b/prowler/lib/check/utils.py index 6d5ff69644..45f16cde32 100644 --- a/prowler/lib/check/utils.py +++ b/prowler/lib/check/utils.py @@ -14,8 +14,8 @@ def recover_checks_from_provider( Returns a list of tuples with the following format (check_name, check_path) """ try: - # Bypass check loading for IAC provider since it uses Trivy directly - if provider == "iac" or provider == "llm": + # Bypass check loading for IAC, LLM, and Image providers since they use external tools directly + if provider in ("iac", "llm", "image"): return [] checks = [] diff --git a/prowler/lib/cli/parser.py b/prowler/lib/cli/parser.py index e21fb8e9d2..c3045dbd76 100644 --- a/prowler/lib/cli/parser.py +++ b/prowler/lib/cli/parser.py @@ -27,10 +27,10 @@ class ProwlerArgumentParser: self.parser = argparse.ArgumentParser( prog="prowler", formatter_class=RawTextHelpFormatter, - usage="prowler [-h] [--version] {aws,azure,gcp,kubernetes,m365,github,nhn,mongodbatlas,oraclecloud,alibabacloud,cloudflare,openstack,dashboard,iac} ...", + usage="prowler [-h] [--version] {aws,azure,gcp,kubernetes,m365,github,nhn,mongodbatlas,oraclecloud,alibabacloud,cloudflare,openstack,dashboard,iac,image} ...", epilog=""" Available Cloud Providers: - {aws,azure,gcp,kubernetes,m365,github,iac,llm,nhn,mongodbatlas,oraclecloud,alibabacloud,cloudflare,openstack} + {aws,azure,gcp,kubernetes,m365,github,iac,llm,image,nhn,mongodbatlas,oraclecloud,alibabacloud,cloudflare,openstack} aws AWS Provider azure Azure Provider gcp GCP Provider @@ -43,6 +43,7 @@ Available Cloud Providers: alibabacloud Alibaba Cloud Provider iac IaC Provider (Beta) llm LLM Provider (Beta) + image Container Image Provider nhn NHN Provider (Unofficial) mongodbatlas MongoDB Atlas Provider (Beta) diff --git a/prowler/lib/outputs/finding.py b/prowler/lib/outputs/finding.py index 128adc8dae..82f64850f8 100644 --- a/prowler/lib/outputs/finding.py +++ b/prowler/lib/outputs/finding.py @@ -380,6 +380,23 @@ class Finding(BaseModel): output_data["resource_uid"] = check_output.resource_id output_data["region"] = check_output.region + elif provider.type == "image": + output_data["auth_method"] = provider.auth_method + output_data["account_uid"] = "image" + output_data["account_name"] = "image" + output_data["resource_name"] = getattr( + check_output, "resource_name", "" + ) + output_data["resource_uid"] = getattr(check_output, "resource_id", "") + output_data["region"] = getattr(check_output, "region", "container") + output_data["package_name"] = getattr(check_output, "package_name", "") + output_data["installed_version"] = getattr( + check_output, "installed_version", "" + ) + output_data["fixed_version"] = getattr( + check_output, "fixed_version", "" + ) + # check_output Unique ID # TODO: move this to a function # TODO: in Azure, GCP and K8s there are findings without resource_name diff --git a/prowler/lib/outputs/summary_table.py b/prowler/lib/outputs/summary_table.py index 1a403d6a75..6a1d978d7c 100644 --- a/prowler/lib/outputs/summary_table.py +++ b/prowler/lib/outputs/summary_table.py @@ -93,6 +93,9 @@ def display_summary_table( if provider.identity.project_name else provider.identity.project_id ) + elif provider.type == "image": + entity_type = "Image" + audited_entities = ", ".join(provider.images) # Check if there are findings and that they are not all MANUAL if findings and not all(finding.status == "MANUAL" for finding in findings): diff --git a/prowler/providers/common/provider.py b/prowler/providers/common/provider.py index 339220df30..6f29c0b800 100644 --- a/prowler/providers/common/provider.py +++ b/prowler/providers/common/provider.py @@ -274,6 +274,18 @@ class Provider(ABC): config_path=arguments.config_file, fixer_config=fixer_config, ) + elif "image" in provider_class_name.lower(): + provider_class( + images=arguments.images, + image_list_file=arguments.image_list_file, + scanners=arguments.scanners, + image_config_scanners=arguments.image_config_scanners, + trivy_severity=arguments.trivy_severity, + ignore_unfixed=arguments.ignore_unfixed, + timeout=arguments.timeout, + config_path=arguments.config_file, + fixer_config=fixer_config, + ) elif "mongodbatlas" in provider_class_name.lower(): provider_class( atlas_public_key=arguments.atlas_public_key, diff --git a/prowler/providers/image/__init__.py b/prowler/providers/image/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/image/exceptions/__init__.py b/prowler/providers/image/exceptions/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/image/exceptions/exceptions.py b/prowler/providers/image/exceptions/exceptions.py new file mode 100644 index 0000000000..0e115a83ec --- /dev/null +++ b/prowler/providers/image/exceptions/exceptions.py @@ -0,0 +1,164 @@ +from prowler.exceptions.exceptions import ProwlerException + + +# Exceptions codes from 11000 to 11999 are reserved for Image exceptions +class ImageBaseException(ProwlerException): + """Base class for Image provider errors.""" + + IMAGE_ERROR_CODES = { + (11000, "ImageNoImagesProvidedError"): { + "message": "No container images provided for scanning.", + "remediation": "Provide at least one image using --image or --image-list-file.", + }, + (11001, "ImageListFileNotFoundError"): { + "message": "Image list file not found.", + "remediation": "Ensure the image list file exists at the specified path.", + }, + (11002, "ImageListFileReadError"): { + "message": "Error reading image list file.", + "remediation": "Check file permissions and format. The file should contain one image per line.", + }, + (11003, "ImageFindingProcessingError"): { + "message": "Error processing image scan finding.", + "remediation": "Check the Trivy output format and ensure the finding structure is valid.", + }, + (11004, "ImageTrivyBinaryNotFoundError"): { + "message": "Trivy binary not found.", + "remediation": "Install Trivy from https://trivy.dev/latest/getting-started/installation/", + }, + (11005, "ImageScanError"): { + "message": "Error scanning container image.", + "remediation": "Check the image name and ensure it is accessible.", + }, + (11006, "ImageInvalidTimeoutError"): { + "message": "Invalid timeout format.", + "remediation": "Use a valid timeout like '5m', '300s', or '1h'.", + }, + (11007, "ImageInvalidScannerError"): { + "message": "Invalid scanner type.", + "remediation": "Use valid scanners: vuln, secret, misconfig, license.", + }, + (11008, "ImageInvalidSeverityError"): { + "message": "Invalid severity level.", + "remediation": "Use valid severities: CRITICAL, HIGH, MEDIUM, LOW, UNKNOWN.", + }, + (11009, "ImageInvalidNameError"): { + "message": "Invalid container image name.", + "remediation": "Use a valid image reference (e.g., 'alpine:3.18', 'registry.example.com/repo/image:tag').", + }, + (11010, "ImageInvalidConfigScannerError"): { + "message": "Invalid image config scanner type.", + "remediation": "Use valid image config scanners: misconfig, secret.", + }, + } + + def __init__(self, code, file=None, original_exception=None, message=None): + error_info = self.IMAGE_ERROR_CODES.get((code, self.__class__.__name__)) + if message: + error_info["message"] = message + super().__init__( + code, + source="Image", + file=file, + original_exception=original_exception, + error_info=error_info, + ) + + +class ImageNoImagesProvidedError(ImageBaseException): + """Exception raised when no container images are provided for scanning.""" + + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 11000, file=file, original_exception=original_exception, message=message + ) + + +class ImageListFileNotFoundError(ImageBaseException): + """Exception raised when the image list file is not found.""" + + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 11001, file=file, original_exception=original_exception, message=message + ) + + +class ImageListFileReadError(ImageBaseException): + """Exception raised when the image list file cannot be read.""" + + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 11002, file=file, original_exception=original_exception, message=message + ) + + +class ImageFindingProcessingError(ImageBaseException): + """Exception raised when a finding cannot be processed.""" + + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 11003, file=file, original_exception=original_exception, message=message + ) + + +class ImageTrivyBinaryNotFoundError(ImageBaseException): + """Exception raised when the Trivy binary is not found.""" + + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 11004, file=file, original_exception=original_exception, message=message + ) + + +class ImageScanError(ImageBaseException): + """Exception raised when a general scan error occurs.""" + + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 11005, file=file, original_exception=original_exception, message=message + ) + + +class ImageInvalidTimeoutError(ImageBaseException): + """Exception raised when an invalid timeout format is provided.""" + + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 11006, file=file, original_exception=original_exception, message=message + ) + + +class ImageInvalidScannerError(ImageBaseException): + """Exception raised when an invalid scanner type is provided.""" + + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 11007, file=file, original_exception=original_exception, message=message + ) + + +class ImageInvalidSeverityError(ImageBaseException): + """Exception raised when an invalid severity level is provided.""" + + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 11008, file=file, original_exception=original_exception, message=message + ) + + +class ImageInvalidNameError(ImageBaseException): + """Exception raised when an invalid container image name is provided.""" + + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 11009, file=file, original_exception=original_exception, message=message + ) + + +class ImageInvalidConfigScannerError(ImageBaseException): + """Exception raised when an invalid image config scanner type is provided.""" + + def __init__(self, file=None, original_exception=None, message=None): + super().__init__( + 11010, file=file, original_exception=original_exception, message=message + ) diff --git a/prowler/providers/image/image_provider.py b/prowler/providers/image/image_provider.py new file mode 100644 index 0000000000..1e11651253 --- /dev/null +++ b/prowler/providers/image/image_provider.py @@ -0,0 +1,707 @@ +from __future__ import annotations + +import json +import re +import subprocess +import sys +from typing import Generator + +from alive_progress import alive_bar +from colorama import Fore, Style + +from prowler.config.config import ( + default_config_file_path, + load_and_validate_config_file, +) +from prowler.lib.check.models import CheckReportImage +from prowler.lib.logger import logger +from prowler.lib.utils.utils import print_boxes +from prowler.providers.common.models import Audit_Metadata, Connection +from prowler.providers.common.provider import Provider +from prowler.providers.image.exceptions.exceptions import ( + ImageFindingProcessingError, + ImageInvalidConfigScannerError, + ImageInvalidNameError, + ImageInvalidScannerError, + ImageInvalidSeverityError, + ImageInvalidTimeoutError, + ImageListFileNotFoundError, + ImageListFileReadError, + ImageNoImagesProvidedError, + ImageScanError, + ImageTrivyBinaryNotFoundError, +) +from prowler.providers.image.lib.arguments.arguments import ( + IMAGE_CONFIG_SCANNERS_CHOICES, + SCANNERS_CHOICES, + SEVERITY_CHOICES, +) + + +class ImageProvider(Provider): + """ + Container Image Provider using Trivy for vulnerability and secret scanning. + + This is a Tool/Wrapper provider that delegates all scanning logic to Trivy's + `trivy image` command and converts the output to Prowler's finding format. + """ + + _type: str = "image" + FINDING_BATCH_SIZE: int = 100 + MAX_IMAGE_LIST_LINES: int = 10_000 + MAX_IMAGE_NAME_LENGTH: int = 500 + _IMAGE_NAME_PATTERN = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9.\-_/:@]+$") + _SHELL_METACHARACTERS = frozenset(";|&$`\n\r") + audit_metadata: Audit_Metadata + + def __init__( + self, + images: list[str] | None = None, + image_list_file: str | None = None, + scanners: list[str] | None = None, + image_config_scanners: list[str] | None = None, + trivy_severity: list[str] | None = None, + ignore_unfixed: bool = False, + timeout: str = "5m", + config_path: str | None = None, + config_content: dict | None = None, + fixer_config: dict | None = None, + ): + logger.info("Instantiating Image Provider...") + + self.images = images if images is not None else [] + self.image_list_file = image_list_file + self.scanners = scanners if scanners is not None else ["vuln", "secret"] + self.image_config_scanners = ( + image_config_scanners if image_config_scanners is not None else [] + ) + self.trivy_severity = trivy_severity if trivy_severity is not None else [] + self.ignore_unfixed = ignore_unfixed + self.timeout = timeout + self.region = "container" + self.audited_account = "image-scan" + self._session = None + self._identity = "prowler" + self._auth_method = "No auth" + + self._validate_inputs() + + # Load images from file if provided + if image_list_file: + self._load_images_from_file(image_list_file) + + for image in self.images: + self._validate_image_name(image) + + if not self.images: + raise ImageNoImagesProvidedError( + file=__file__, + message="No images provided for scanning.", + ) + + # Audit Config + if config_content: + self._audit_config = config_content + else: + if not config_path: + config_path = default_config_file_path + self._audit_config = load_and_validate_config_file(self._type, config_path) + + # Fixer Config + self._fixer_config = fixer_config if fixer_config is not None else {} + + # Mutelist (not needed for Image provider since Trivy has its own logic) + self._mutelist = None + + self.audit_metadata = Audit_Metadata( + provider=self._type, + account_id=self.audited_account, + account_name="image", + region=self.region, + services_scanned=0, + expected_checks=[], + completed_checks=0, + audit_progress=0, + ) + + Provider.set_global_provider(self) + + def _load_images_from_file(self, file_path: str) -> None: + """Load image names from a file (one per line).""" + try: + line_count = 0 + with open(file_path, "r") as f: + for line in f: + line_count += 1 + if line_count > self.MAX_IMAGE_LIST_LINES: + raise ImageListFileReadError( + file=file_path, + message=f"Image list file exceeds maximum of {self.MAX_IMAGE_LIST_LINES} lines.", + ) + line = line.strip() + if not line or line.startswith("#"): + continue + if len(line) > self.MAX_IMAGE_NAME_LENGTH: + logger.warning( + f"Skipping image name exceeding {self.MAX_IMAGE_NAME_LENGTH} chars at line {line_count} in {file_path}" + ) + continue + self.images.append(line) + logger.info(f"Loaded {len(self.images)} images from {file_path}") + except FileNotFoundError: + raise ImageListFileNotFoundError( + file=file_path, + message=f"Image list file not found: {file_path}", + ) + except (ImageListFileReadError, ImageListFileNotFoundError): + raise + except Exception as error: + raise ImageListFileReadError( + file=file_path, + original_exception=error, + message=f"Error reading image list file: {error}", + ) + + def _validate_inputs(self) -> None: + """Validate timeout, scanners, and severity inputs.""" + if not re.fullmatch(r"\d+[smh]", self.timeout): + raise ImageInvalidTimeoutError( + file=__file__, + message=f"Invalid timeout format: '{self.timeout}'. Expected pattern like '5m', '300s', or '1h'.", + ) + + for scanner in self.scanners: + if scanner not in SCANNERS_CHOICES: + raise ImageInvalidScannerError( + file=__file__, + message=f"Invalid scanner: '{scanner}'. Valid options: {', '.join(SCANNERS_CHOICES)}.", + ) + + for config_scanner in self.image_config_scanners: + if config_scanner not in IMAGE_CONFIG_SCANNERS_CHOICES: + raise ImageInvalidConfigScannerError( + file=__file__, + message=f"Invalid image config scanner: '{config_scanner}'. Valid options: {', '.join(IMAGE_CONFIG_SCANNERS_CHOICES)}.", + ) + + for severity in self.trivy_severity: + if severity not in SEVERITY_CHOICES: + raise ImageInvalidSeverityError( + file=__file__, + message=f"Invalid severity: '{severity}'. Valid options: {', '.join(SEVERITY_CHOICES)}.", + ) + + def _validate_image_name(self, name: str) -> None: + """Validate a container image name for safety and correctness.""" + if not name: + raise ImageInvalidNameError( + file=__file__, + message="Image name must not be empty.", + ) + + if len(name) > self.MAX_IMAGE_NAME_LENGTH: + raise ImageInvalidNameError( + file=__file__, + message=f"Image name exceeds maximum length of {self.MAX_IMAGE_NAME_LENGTH} characters: '{name[:50]}...'", + ) + + if any(c in self._SHELL_METACHARACTERS for c in name): + raise ImageInvalidNameError( + file=__file__, + message=f"Image name contains invalid characters: '{name}'", + ) + + if not self._IMAGE_NAME_PATTERN.fullmatch(name): + raise ImageInvalidNameError( + file=__file__, + message=f"Image name does not match valid OCI reference format: '{name}'", + ) + + @property + def auth_method(self) -> str: + return self._auth_method + + @property + def type(self) -> str: + return self._type + + @property + def identity(self) -> str: + return self._identity + + @property + def session(self) -> None: + return self._session + + @property + def audit_config(self) -> dict: + return self._audit_config + + @property + def fixer_config(self) -> dict: + return self._fixer_config + + def setup_session(self) -> None: + """Image provider doesn't need a session since it uses Trivy directly""" + return None + + def _process_finding( + self, finding: dict, image_name: str, finding_type: str + ) -> CheckReportImage: + """ + Process a single finding and create a CheckReportImage object. + + Args: + finding: The finding object from Trivy output + image_name: The container image name being scanned + finding_type: The type of finding (Vulnerability, Secret, etc.) + + Returns: + CheckReportImage: The processed check report + """ + try: + # Determine finding ID based on type + if "VulnerabilityID" in finding: + finding_id = finding["VulnerabilityID"] + finding_description = finding.get( + "Description", finding.get("Title", "") + ) + finding_status = "FAIL" + elif "RuleID" in finding: + # Secret finding + finding_id = finding["RuleID"] + finding_description = finding.get("Title", "Secret detected") + finding_status = "FAIL" + else: + finding_id = finding.get("ID", "UNKNOWN") + finding_description = finding.get("Description", "") + finding_status = finding.get("Status", "FAIL") + + # Build remediation text for vulnerabilities + remediation_text = "" + if finding.get("FixedVersion"): + remediation_text = f"Upgrade {finding.get('PkgName', 'package')} to version {finding['FixedVersion']}" + elif finding.get("Resolution"): + remediation_text = finding["Resolution"] + + # Convert Trivy severity to Prowler severity (lowercase, map UNKNOWN to informational) + trivy_severity = finding.get("Severity", "UNKNOWN").lower() + if trivy_severity == "unknown": + trivy_severity = "informational" + + metadata_dict = { + "Provider": "image", + "CheckID": finding_id, + "CheckTitle": finding.get("Title", finding_id), + "CheckType": ["Container Image Security"], + "ServiceName": finding_type, + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": trivy_severity, + "ResourceType": "container-image", + "ResourceGroup": "container", + "Description": finding_description, + "Risk": finding.get( + "Description", "Vulnerability detected in container image" + ), + "RelatedUrl": finding.get("PrimaryURL", ""), + "Remediation": { + "Code": { + "NativeIaC": "", + "Terraform": "", + "CLI": "", + "Other": "", + }, + "Recommendation": { + "Text": remediation_text, + "Url": finding.get("PrimaryURL", ""), + }, + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "", + } + + # Convert metadata dict to JSON string + metadata = json.dumps(metadata_dict) + + report = CheckReportImage( + metadata=metadata, finding=finding, image_name=image_name + ) + report.status = finding_status + report.status_extended = self._build_status_extended(finding) + report.region = self.region + return report + + except Exception as error: + raise ImageFindingProcessingError( + file=__file__, + original_exception=error, + message=f"Error processing finding: {error}", + ) + + def _build_status_extended(self, finding: dict) -> str: + """Build a detailed status message for the finding.""" + parts = [] + + if finding.get("VulnerabilityID"): + parts.append(f"{finding['VulnerabilityID']}") + + if finding.get("PkgName"): + pkg_info = finding["PkgName"] + if finding.get("InstalledVersion"): + pkg_info += f"@{finding['InstalledVersion']}" + parts.append(f"in package {pkg_info}") + + if finding.get("FixedVersion"): + parts.append(f"(fix available: {finding['FixedVersion']})") + elif finding.get("Status") == "will_not_fix": + parts.append("(no fix available)") + + if finding.get("Title"): + parts.append(f"- {finding['Title']}") + + return ( + " ".join(parts) if parts else finding.get("Description", "Finding detected") + ) + + def run(self) -> list[CheckReportImage]: + """Execute the container image scan.""" + reports = [] + for batch in self.run_scan(): + reports.extend(batch) + return reports + + def run_scan(self) -> Generator[list[CheckReportImage], None, None]: + """ + Run Trivy scan on all configured images. + + Yields: + list[CheckReportImage]: Batches of findings + """ + for image in self.images: + try: + yield from self._scan_single_image(image) + except (ImageScanError, ImageTrivyBinaryNotFoundError): + raise + except Exception as error: + logger.error(f"Error scanning image {image}: {error}") + continue + + def _scan_single_image( + self, image: str + ) -> Generator[list[CheckReportImage], None, None]: + """ + Scan a single container image with Trivy. + + Args: + image: The container image name/tag to scan + + Yields: + list[CheckReportImage]: Batches of findings + """ + try: + logger.info(f"Scanning container image: {image}") + + # Build Trivy command + trivy_command = [ + "trivy", + "image", + "--format", + "json", + "--scanners", + ",".join(self.scanners), + "--timeout", + self.timeout, + ] + + if self.image_config_scanners: + trivy_command.extend( + ["--image-config-scanners", ",".join(self.image_config_scanners)] + ) + + if self.trivy_severity: + trivy_command.extend(["--severity", ",".join(self.trivy_severity)]) + + if self.ignore_unfixed: + trivy_command.append("--ignore-unfixed") + + trivy_command.append(image) + + # Execute Trivy + process = self._execute_trivy(trivy_command, image) + + # Log stderr output + if process.stderr: + self._log_trivy_stderr(process.stderr) + + # Check for Trivy failure + if process.returncode != 0: + error_msg = self._extract_trivy_errors(process.stderr) + categorized_msg = self._categorize_trivy_error(error_msg) + raise ImageScanError( + file=__file__, + message=f"Trivy scan failed for {image}: {categorized_msg}", + ) + + # Parse JSON output + try: + output = json.loads(process.stdout) + results = output.get("Results", []) + + if not results: + logger.info(f"No findings for image: {image}") + return + + except json.JSONDecodeError as error: + logger.error(f"Failed to parse Trivy output for {image}: {error}") + logger.debug(f"Trivy stdout: {process.stdout[:500]}") + return + + # Process findings in batches + batch = [] + + for result in results: + target = result.get("Target", image) + result_type = result.get("Type", "unknown") + + # Process Vulnerabilities + for vuln in result.get("Vulnerabilities", []): + report = self._process_finding(vuln, target, result_type) + batch.append(report) + if len(batch) >= self.FINDING_BATCH_SIZE: + yield batch + batch = [] + + # Process Secrets + for secret in result.get("Secrets", []): + report = self._process_finding(secret, target, "secret") + batch.append(report) + if len(batch) >= self.FINDING_BATCH_SIZE: + yield batch + batch = [] + + # Process Misconfigurations (from Dockerfile) + for misconfig in result.get("Misconfigurations", []): + report = self._process_finding( + misconfig, target, "misconfiguration" + ) + batch.append(report) + if len(batch) >= self.FINDING_BATCH_SIZE: + yield batch + batch = [] + + # Yield remaining findings + if batch: + yield batch + + except (ImageScanError, ImageTrivyBinaryNotFoundError): + raise + except Exception as error: + if "No such file or directory: 'trivy'" in str(error): + raise ImageTrivyBinaryNotFoundError( + file=__file__, + original_exception=error, + message="Trivy binary not found. Please install Trivy from https://trivy.dev/latest/getting-started/installation/", + ) + logger.error(f"Error scanning image {image}: {error}") + + def _execute_trivy(self, command: list, image: str) -> subprocess.CompletedProcess: + """Execute Trivy command with optional progress bar.""" + try: + if sys.stdout.isatty(): + with alive_bar( + ctrl_c=False, + bar="blocks", + spinner="classic", + stats=False, + enrich_print=False, + ) as bar: + bar.title = f"-> Scanning {image}..." + process = subprocess.run( + command, + capture_output=True, + text=True, + ) + bar.title = f"-> Scan completed for {image}" + return process + else: + logger.info(f"Scanning {image}...") + process = subprocess.run( + command, + capture_output=True, + text=True, + ) + logger.info(f"Scan completed for {image}") + return process + except (AttributeError, OSError): + logger.info(f"Scanning {image}...") + return subprocess.run(command, capture_output=True, text=True) + + def _log_trivy_stderr(self, stderr: str) -> None: + """Parse and log Trivy's stderr output.""" + for line in stderr.strip().split("\n"): + if line.strip(): + parts = line.split() + if len(parts) >= 3: + level = parts[1] + message = " ".join(parts[2:]) + if level == "ERROR": + logger.error(message) + elif level == "WARN": + logger.warning(message) + elif level == "INFO": + logger.info(message) + elif level == "DEBUG": + logger.debug(message) + else: + logger.info(message) + else: + logger.info(line) + + @staticmethod + def _extract_trivy_errors(stderr: str) -> str: + """Extract only ERROR-level messages from Trivy stderr output.""" + if not stderr: + return "Unknown error" + error_lines = [] + for line in stderr.strip().split("\n"): + parts = line.split() + if len(parts) >= 3 and parts[1] == "ERROR": + error_lines.append(" ".join(parts[2:])) + elif len(parts) >= 3 and parts[1] == "FATAL": + error_lines.append(" ".join(parts[2:])) + if error_lines: + return "; ".join(error_lines)[:500] + # Fallback: no ERROR lines found, return last non-empty line + for line in reversed(stderr.strip().split("\n")): + if line.strip(): + return line.strip()[:500] + return "Unknown error" + + @staticmethod + def _categorize_trivy_error(error_msg: str) -> str: + """Categorize a Trivy error message to provide actionable guidance.""" + lower = error_msg.lower() + + if any(kw in lower for kw in ("401", "403", "unauthorized", "denied")): + return f"Auth failure — check `docker login`: {error_msg}" + if any(kw in lower for kw in ("404", "manifest unknown", "not found")): + return f"Image not found — check name/tag/registry: {error_msg}" + if any(kw in lower for kw in ("429", "rate limit", "too many requests")): + return f"Rate limited — wait or authenticate: {error_msg}" + if any(kw in lower for kw in ("timeout", "connection refused", "no such host")): + return f"Network issue — check connectivity: {error_msg}" + + return error_msg + + def print_credentials(self) -> None: + """Print scan configuration.""" + report_title = f"{Style.BRIGHT}Scanning container images:{Style.RESET_ALL}" + + report_lines = [] + if len(self.images) <= 3: + for img in self.images: + report_lines.append(f"Image: {Fore.YELLOW}{img}{Style.RESET_ALL}") + else: + report_lines.append( + f"Images: {Fore.YELLOW}{len(self.images)} images{Style.RESET_ALL}" + ) + + report_lines.append( + f"Scanners: {Fore.YELLOW}{', '.join(self.scanners)}{Style.RESET_ALL}" + ) + + if self.image_config_scanners: + report_lines.append( + f"Image config scanners: {Fore.YELLOW}{', '.join(self.image_config_scanners)}{Style.RESET_ALL}" + ) + + if self.trivy_severity: + report_lines.append( + f"Severity filter: {Fore.YELLOW}{', '.join(self.trivy_severity)}{Style.RESET_ALL}" + ) + + if self.ignore_unfixed: + report_lines.append(f"Ignore unfixed: {Fore.YELLOW}Yes{Style.RESET_ALL}") + + report_lines.append(f"Timeout: {Fore.YELLOW}{self.timeout}{Style.RESET_ALL}") + + print_boxes(report_lines, report_title) + + @staticmethod + def test_connection( + image: str | None = None, + raise_on_exception: bool = True, + provider_id: str | None = None, + ) -> "Connection": + """ + Test connection to container registry by attempting to inspect an image. + + Args: + image: Container image to test + raise_on_exception: Whether to raise exceptions + provider_id: Fallback for image name + + Returns: + Connection: Connection object with success status + """ + try: + if provider_id and not image: + image = provider_id + + if not image: + return Connection(is_connected=False, error="Image name is required") + + # Test by running trivy with --skip-update to just test image access + process = subprocess.run( + [ + "trivy", + "image", + "--skip-db-update", + "--download-db-only=false", + image, + ], + capture_output=True, + text=True, + timeout=60, + ) + + if process.returncode == 0: + return Connection(is_connected=True) + else: + error_msg = process.stderr or "Unknown error" + if "401" in error_msg or "unauthorized" in error_msg.lower(): + return Connection( + is_connected=False, + error="Authentication failed. Check registry credentials.", + ) + elif "not found" in error_msg.lower() or "404" in error_msg: + return Connection( + is_connected=False, + error="Image not found in registry.", + ) + else: + return Connection( + is_connected=False, + error=f"Failed to access image: {error_msg[:200]}", + ) + + except subprocess.TimeoutExpired: + return Connection( + is_connected=False, + error="Connection timed out", + ) + except FileNotFoundError: + return Connection( + is_connected=False, + error="Trivy binary not found. Please install Trivy.", + ) + except Exception as error: + if raise_on_exception: + raise + return Connection( + is_connected=False, + error=f"Unexpected error: {str(error)}", + ) diff --git a/prowler/providers/image/lib/__init__.py b/prowler/providers/image/lib/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/image/lib/arguments/__init__.py b/prowler/providers/image/lib/arguments/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/image/lib/arguments/arguments.py b/prowler/providers/image/lib/arguments/arguments.py new file mode 100644 index 0000000000..3809aec667 --- /dev/null +++ b/prowler/providers/image/lib/arguments/arguments.py @@ -0,0 +1,103 @@ +SCANNERS_CHOICES = [ + "vuln", + "secret", + "misconfig", + "license", +] + +IMAGE_CONFIG_SCANNERS_CHOICES = [ + "misconfig", + "secret", +] + +SEVERITY_CHOICES = [ + "CRITICAL", + "HIGH", + "MEDIUM", + "LOW", + "UNKNOWN", +] + + +def init_parser(self): + """Init the Image Provider CLI parser""" + image_parser = self.subparsers.add_parser( + "image", parents=[self.common_providers_parser], help="Container Image Provider" + ) + + # Image Selection + image_selection_group = image_parser.add_argument_group("Image Selection") + image_selection_group.add_argument( + "--image", + "-I", + dest="images", + action="append", + default=[], + help="Container image to scan. Can be specified multiple times. Examples: nginx:latest, alpine:3.18, myregistry.io/myapp:v1.0", + ) + + image_selection_group.add_argument( + "--image-list", + dest="image_list_file", + default=None, + help="Path to a file containing list of images to scan (one per line). Lines starting with # are treated as comments.", + ) + + # Scan Configuration + scan_config_group = image_parser.add_argument_group("Scan Configuration") + scan_config_group.add_argument( + "--scanners", + "--scanner", + dest="scanners", + nargs="+", + default=["vuln", "secret"], + choices=SCANNERS_CHOICES, + help="Trivy scanners to use. Default: vuln, secret. Available: vuln, secret, misconfig, license", + ) + + scan_config_group.add_argument( + "--image-config-scanners", + dest="image_config_scanners", + nargs="+", + default=[], + choices=IMAGE_CONFIG_SCANNERS_CHOICES, + help="Trivy image config scanners (scans Dockerfile-level metadata). Available: misconfig, secret", + ) + + scan_config_group.add_argument( + "--trivy-severity", + dest="trivy_severity", + nargs="+", + default=[], + choices=SEVERITY_CHOICES, + help="Filter Trivy findings by severity. Default: all severities. Available: CRITICAL, HIGH, MEDIUM, LOW, UNKNOWN", + ) + + scan_config_group.add_argument( + "--ignore-unfixed", + dest="ignore_unfixed", + action="store_true", + default=False, + help="Ignore vulnerabilities without available fixes.", + ) + + scan_config_group.add_argument( + "--timeout", + dest="timeout", + default="5m", + help="Trivy scan timeout. Default: 5m. Examples: 10m, 1h", + ) + + +def validate_arguments(arguments): + """Validate Image provider arguments.""" + images = getattr(arguments, "images", []) + image_list_file = getattr(arguments, "image_list_file", None) + + if not images and not image_list_file: + return ( + False, + "At least one image must be specified using --image (-I) or --image-list.", + ) + + return (True, "") diff --git a/prowler/providers/image/models.py b/prowler/providers/image/models.py new file mode 100644 index 0000000000..232f8a6e39 --- /dev/null +++ b/prowler/providers/image/models.py @@ -0,0 +1,21 @@ +from prowler.config.config import output_file_timestamp +from prowler.providers.common.models import ProviderOutputOptions + + +class ImageOutputOptions(ProviderOutputOptions): + """ + ImageOutputOptions customizes output filename logic for container image scanning. + + Attributes inherited from ProviderOutputOptions: + - output_filename (str): The base filename used for generated reports. + - output_directory (str): The directory to store the output files. + """ + + def __init__(self, arguments, bulk_checks_metadata): + super().__init__(arguments, bulk_checks_metadata) + + # If --output-filename is not specified, build a default name + if not getattr(arguments, "output_filename", None): + self.output_filename = f"prowler-output-image-{output_file_timestamp}" + else: + self.output_filename = arguments.output_filename diff --git a/tests/lib/cli/parser_test.py b/tests/lib/cli/parser_test.py index 324b9b6c20..f2192d8d0b 100644 --- a/tests/lib/cli/parser_test.py +++ b/tests/lib/cli/parser_test.py @@ -17,7 +17,7 @@ prowler_command = "prowler" # capsys # https://docs.pytest.org/en/7.1.x/how-to/capture-stdout-stderr.html -prowler_default_usage_error = "usage: prowler [-h] [--version] {aws,azure,gcp,kubernetes,m365,github,nhn,mongodbatlas,oraclecloud,alibabacloud,cloudflare,openstack,dashboard,iac} ..." +prowler_default_usage_error = "usage: prowler [-h] [--version] {aws,azure,gcp,kubernetes,m365,github,nhn,mongodbatlas,oraclecloud,alibabacloud,cloudflare,openstack,dashboard,iac,image} ..." def mock_get_available_providers(): @@ -29,6 +29,7 @@ def mock_get_available_providers(): "m365", "github", "iac", + "image", "nhn", "mongodbatlas", "oraclecloud", diff --git a/tests/providers/image/image_fixtures.py b/tests/providers/image/image_fixtures.py new file mode 100644 index 0000000000..a51f934bda --- /dev/null +++ b/tests/providers/image/image_fixtures.py @@ -0,0 +1,92 @@ +import json + +# Sample vulnerability finding from Trivy +SAMPLE_VULNERABILITY_FINDING = { + "VulnerabilityID": "CVE-2024-1234", + "PkgID": "openssl@1.1.1k-r0", + "PkgName": "openssl", + "InstalledVersion": "1.1.1k-r0", + "FixedVersion": "1.1.1l-r0", + "Severity": "HIGH", + "Title": "OpenSSL Buffer Overflow", + "Description": "A buffer overflow vulnerability in OpenSSL allows remote attackers to execute arbitrary code.", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2024-1234", +} + +# Sample secret finding from Trivy +SAMPLE_SECRET_FINDING = { + "RuleID": "aws-access-key-id", + "Category": "AWS", + "Severity": "CRITICAL", + "Title": "AWS Access Key ID", + "StartLine": 10, + "EndLine": 10, + "Match": "AKIA...", +} + +# Sample misconfiguration finding from Trivy +SAMPLE_MISCONFIGURATION_FINDING = { + "ID": "DS001", + "Title": "Dockerfile should not use latest tag", + "Description": "Using latest tag can cause unpredictable builds.", + "Severity": "MEDIUM", + "Resolution": "Use a specific version tag instead of latest", + "PrimaryURL": "https://avd.aquasec.com/misconfig/ds001", +} + +# Sample finding with UNKNOWN severity +SAMPLE_UNKNOWN_SEVERITY_FINDING = { + "VulnerabilityID": "CVE-2024-9999", + "PkgID": "test-pkg@0.0.1", + "PkgName": "test-pkg", + "InstalledVersion": "0.0.1", + "Severity": "UNKNOWN", + "Title": "Unknown severity issue", + "Description": "An issue with unknown severity.", +} + +# Full Trivy JSON output structure with a single vulnerability +SAMPLE_TRIVY_IMAGE_OUTPUT = { + "Results": [ + { + "Target": "alpine:3.18 (alpine 3.18.0)", + "Type": "alpine", + "Vulnerabilities": [SAMPLE_VULNERABILITY_FINDING], + "Secrets": [], + "Misconfigurations": [], + } + ] +} + +# Full Trivy JSON output with mixed finding types +SAMPLE_TRIVY_MULTI_TYPE_OUTPUT = { + "Results": [ + { + "Target": "myimage:latest (debian 12)", + "Type": "debian", + "Vulnerabilities": [SAMPLE_VULNERABILITY_FINDING], + "Secrets": [SAMPLE_SECRET_FINDING], + "Misconfigurations": [SAMPLE_MISCONFIGURATION_FINDING], + } + ] +} + + +def get_sample_trivy_json_output(): + """Return sample Trivy JSON output as string.""" + return json.dumps(SAMPLE_TRIVY_IMAGE_OUTPUT) + + +def get_empty_trivy_output(): + """Return empty Trivy output as string.""" + return json.dumps({"Results": []}) + + +def get_invalid_trivy_output(): + """Return invalid JSON output as string.""" + return "invalid json output" + + +def get_multi_type_trivy_output(): + """Return Trivy output with multiple finding types as string.""" + return json.dumps(SAMPLE_TRIVY_MULTI_TYPE_OUTPUT) diff --git a/tests/providers/image/image_provider_test.py b/tests/providers/image/image_provider_test.py new file mode 100644 index 0000000000..75bebaefc5 --- /dev/null +++ b/tests/providers/image/image_provider_test.py @@ -0,0 +1,595 @@ +import tempfile +from unittest import mock +from unittest.mock import MagicMock, patch + +import pytest + +from prowler.lib.check.models import CheckReportImage +from prowler.providers.image.exceptions.exceptions import ( + ImageInvalidConfigScannerError, + ImageInvalidNameError, + ImageInvalidScannerError, + ImageInvalidSeverityError, + ImageInvalidTimeoutError, + ImageListFileNotFoundError, + ImageListFileReadError, + ImageNoImagesProvidedError, + ImageScanError, + ImageTrivyBinaryNotFoundError, +) +from prowler.providers.image.image_provider import ImageProvider +from tests.providers.image.image_fixtures import ( + SAMPLE_MISCONFIGURATION_FINDING, + SAMPLE_SECRET_FINDING, + SAMPLE_UNKNOWN_SEVERITY_FINDING, + SAMPLE_VULNERABILITY_FINDING, + get_empty_trivy_output, + get_invalid_trivy_output, + get_multi_type_trivy_output, + get_sample_trivy_json_output, +) + + +def _make_provider(**kwargs): + """Helper to create an ImageProvider with test defaults.""" + defaults = { + "images": ["alpine:3.18"], + "config_content": {}, + } + defaults.update(kwargs) + return ImageProvider(**defaults) + + +class TestImageProvider: + def test_image_provider(self): + """Test default initialization.""" + provider = _make_provider() + + assert provider._type == "image" + assert provider.type == "image" + assert provider.images == ["alpine:3.18"] + assert provider.scanners == ["vuln", "secret"] + assert provider.image_config_scanners == [] + assert provider.trivy_severity == [] + assert provider.ignore_unfixed is False + assert provider.timeout == "5m" + assert provider.region == "container" + assert provider.audited_account == "image-scan" + assert provider.identity == "prowler" + assert provider.auth_method == "No auth" + assert provider.session is None + assert provider.audit_config == {} + assert provider.fixer_config == {} + assert provider._mutelist is None + + def test_image_provider_custom_params(self): + """Test initialization with custom parameters.""" + provider = _make_provider( + images=["nginx:1.25", "redis:7"], + scanners=["vuln", "secret", "misconfig"], + trivy_severity=["HIGH", "CRITICAL"], + ignore_unfixed=True, + timeout="10m", + fixer_config={"key": "value"}, + ) + + assert provider.images == ["nginx:1.25", "redis:7"] + assert provider.scanners == ["vuln", "secret", "misconfig"] + assert provider.trivy_severity == ["HIGH", "CRITICAL"] + assert provider.ignore_unfixed is True + assert provider.timeout == "10m" + assert provider.fixer_config == {"key": "value"} + + def test_image_provider_with_image_list_file(self): + """Test loading images from a file, skipping comments and blank lines.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f: + f.write("# Comment line\n") + f.write("alpine:3.18\n") + f.write("\n") + f.write(" nginx:latest \n") + f.write("# Another comment\n") + f.write("redis:7\n") + f.name + + provider = _make_provider( + images=None, + image_list_file=f.name, + ) + + assert "alpine:3.18" in provider.images + assert "nginx:latest" in provider.images + assert "redis:7" in provider.images + assert len(provider.images) == 3 + + def test_image_provider_no_images(self): + """Test that ImageNoImagesProvidedError is raised when no images are given.""" + with pytest.raises(ImageNoImagesProvidedError): + _make_provider(images=[]) + + def test_image_provider_image_list_file_not_found(self): + """Test that ImageListFileNotFoundError is raised for missing file.""" + with pytest.raises(ImageListFileNotFoundError): + _make_provider( + images=None, + image_list_file="/nonexistent/path/images.txt", + ) + + def test_process_finding_vulnerability(self): + """Test processing a vulnerability finding.""" + provider = _make_provider() + report = provider._process_finding( + SAMPLE_VULNERABILITY_FINDING, + "alpine:3.18 (alpine 3.18.0)", + "alpine", + ) + + assert isinstance(report, CheckReportImage) + assert report.status == "FAIL" + assert report.check_metadata.CheckID == "CVE-2024-1234" + assert report.check_metadata.Severity == "high" + assert report.check_metadata.ServiceName == "alpine" + assert report.check_metadata.ResourceType == "container-image" + assert report.check_metadata.ResourceGroup == "container" + assert report.package_name == "openssl" + assert report.installed_version == "1.1.1k-r0" + assert report.fixed_version == "1.1.1l-r0" + assert report.resource_name == "alpine:3.18 (alpine 3.18.0)" + assert report.region == "container" + + def test_process_finding_secret(self): + """Test processing a secret finding (identified by RuleID).""" + provider = _make_provider() + report = provider._process_finding( + SAMPLE_SECRET_FINDING, + "myimage:latest", + "secret", + ) + + assert isinstance(report, CheckReportImage) + assert report.status == "FAIL" + assert report.check_metadata.CheckID == "aws-access-key-id" + assert report.check_metadata.Severity == "critical" + assert report.check_metadata.ServiceName == "secret" + + def test_process_finding_misconfiguration(self): + """Test processing a misconfiguration finding (identified by ID).""" + provider = _make_provider() + report = provider._process_finding( + SAMPLE_MISCONFIGURATION_FINDING, + "myimage:latest", + "misconfiguration", + ) + + assert isinstance(report, CheckReportImage) + assert report.check_metadata.CheckID == "DS001" + assert report.check_metadata.Severity == "medium" + assert report.check_metadata.ServiceName == "misconfiguration" + + def test_process_finding_unknown_severity(self): + """Test that UNKNOWN severity is mapped to informational.""" + provider = _make_provider() + report = provider._process_finding( + SAMPLE_UNKNOWN_SEVERITY_FINDING, + "myimage:latest", + "alpine", + ) + + assert report.check_metadata.Severity == "informational" + + @patch("subprocess.run") + def test_run_scan_success(self, mock_subprocess): + """Test successful scan with mocked subprocess.""" + provider = _make_provider() + mock_subprocess.return_value = MagicMock( + returncode=0, stdout=get_sample_trivy_json_output(), stderr="" + ) + + reports = [] + for batch in provider.run_scan(): + reports.extend(batch) + + assert len(reports) == 1 + assert reports[0].check_metadata.CheckID == "CVE-2024-1234" + + @patch("subprocess.run") + def test_run_scan_empty_output(self, mock_subprocess): + """Test scan with empty Trivy output produces no findings.""" + provider = _make_provider() + mock_subprocess.return_value = MagicMock( + returncode=0, stdout=get_empty_trivy_output(), stderr="" + ) + + reports = [] + for batch in provider.run_scan(): + reports.extend(batch) + + assert len(reports) == 0 + + @patch("subprocess.run") + def test_run_scan_invalid_json(self, mock_subprocess): + """Test scan with malformed output doesn't crash.""" + provider = _make_provider() + mock_subprocess.return_value = MagicMock( + returncode=0, stdout=get_invalid_trivy_output(), stderr="" + ) + + reports = [] + for batch in provider.run_scan(): + reports.extend(batch) + + assert len(reports) == 0 + + @patch("subprocess.run") + def test_run_scan_trivy_not_found(self, mock_subprocess): + """Test that ImageTrivyBinaryNotFoundError is raised when trivy is missing.""" + provider = _make_provider() + mock_subprocess.side_effect = FileNotFoundError( + "[Errno 2] No such file or directory: 'trivy'" + ) + + with pytest.raises(ImageTrivyBinaryNotFoundError): + for _ in provider._scan_single_image("alpine:3.18"): + pass + + @patch("subprocess.run") + def test_run_scan_multiple_images(self, mock_subprocess): + """Test scanning multiple images makes separate subprocess calls.""" + provider = _make_provider(images=["alpine:3.18", "nginx:latest"]) + mock_subprocess.return_value = MagicMock( + returncode=0, stdout=get_sample_trivy_json_output(), stderr="" + ) + + reports = [] + for batch in provider.run_scan(): + reports.extend(batch) + + assert mock_subprocess.call_count == 2 + + @patch("subprocess.run") + def test_run_scan_multi_type_output(self, mock_subprocess): + """Test scan with vulnerabilities, secrets, and misconfigurations.""" + provider = _make_provider() + mock_subprocess.return_value = MagicMock( + returncode=0, stdout=get_multi_type_trivy_output(), stderr="" + ) + + reports = [] + for batch in provider.run_scan(): + reports.extend(batch) + + assert len(reports) == 3 + + check_ids = [r.check_metadata.CheckID for r in reports] + assert "CVE-2024-1234" in check_ids + assert "aws-access-key-id" in check_ids + assert "DS001" in check_ids + + def test_print_credentials(self): + """Test that print_credentials outputs image names.""" + provider = _make_provider() + with mock.patch("builtins.print") as mock_print: + provider.print_credentials() + output = " ".join( + str(call.args[0]) for call in mock_print.call_args_list if call.args + ) + assert "alpine:3.18" in output + + @patch("subprocess.run") + def test_test_connection_success(self, mock_subprocess): + """Test successful connection returns is_connected=True.""" + mock_subprocess.return_value = MagicMock(returncode=0, stderr="") + + result = ImageProvider.test_connection(image="alpine:3.18") + + assert result.is_connected is True + + @patch("subprocess.run") + def test_test_connection_auth_failure(self, mock_subprocess): + """Test 401 error returns auth failure.""" + mock_subprocess.return_value = MagicMock( + returncode=1, stderr="401 unauthorized" + ) + + result = ImageProvider.test_connection(image="private/image:latest") + + assert result.is_connected is False + assert "Authentication failed" in result.error + + @patch("subprocess.run") + def test_test_connection_not_found(self, mock_subprocess): + """Test 404 error returns not found.""" + mock_subprocess.return_value = MagicMock(returncode=1, stderr="404 not found") + + result = ImageProvider.test_connection(image="nonexistent/image:latest") + + assert result.is_connected is False + assert "not found" in result.error + + def test_build_status_extended(self): + """Test status message content for different finding types.""" + provider = _make_provider() + + # Vulnerability with fix + status = provider._build_status_extended(SAMPLE_VULNERABILITY_FINDING) + assert "CVE-2024-1234" in status + assert "openssl" in status + assert "fix available" in status + + # Finding with no special fields + status = provider._build_status_extended({"Description": "Simple finding"}) + assert status == "Simple finding" + + # Finding with will_not_fix status + finding_no_fix = { + "VulnerabilityID": "CVE-2024-0000", + "PkgName": "libc", + "Status": "will_not_fix", + "Title": "Some vuln", + } + status = provider._build_status_extended(finding_no_fix) + assert "no fix available" in status + + def test_validate_arguments(self): + """Test valid and invalid argument combinations.""" + # Valid: images provided + provider = _make_provider(images=["alpine:3.18"]) + assert provider.images == ["alpine:3.18"] + + # Invalid: empty images and no file + with pytest.raises(ImageNoImagesProvidedError): + _make_provider(images=[]) + + # Valid: custom scanners + provider = _make_provider(scanners=["vuln"]) + assert provider.scanners == ["vuln"] + + def test_setup_session(self): + """Test that setup_session returns None.""" + provider = _make_provider() + assert provider.setup_session() is None + + @patch("subprocess.run") + def test_run_method(self, mock_subprocess): + """Test that run() collects all batches into a list.""" + provider = _make_provider() + mock_subprocess.return_value = MagicMock( + returncode=0, stdout=get_sample_trivy_json_output(), stderr="" + ) + + reports = provider.run() + + assert isinstance(reports, list) + assert len(reports) == 1 + + @patch("subprocess.run") + def test_scan_single_image_trivy_nonzero_exit(self, mock_subprocess): + """Test that a non-zero Trivy exit code raises ImageScanError.""" + provider = _make_provider() + mock_subprocess.return_value = MagicMock( + returncode=1, + stdout="", + stderr="fatal error: unable to pull image", + ) + + with pytest.raises(ImageScanError): + for _ in provider._scan_single_image("alpine:3.18"): + pass + + @patch("subprocess.run") + def test_scan_single_image_auth_failure(self, mock_subprocess): + """Test that a 401 unauthorized stderr raises ImageScanError with message.""" + provider = _make_provider() + mock_subprocess.return_value = MagicMock( + returncode=1, + stdout="", + stderr="ERROR 401 unauthorized: authentication required", + ) + + with pytest.raises(ImageScanError, match="401 unauthorized"): + for _ in provider._scan_single_image("private/image:latest"): + pass + + @patch("subprocess.run") + def test_run_scan_propagates_scan_error(self, mock_subprocess): + """Test that run_scan() re-raises ImageScanError instead of swallowing it.""" + provider = _make_provider() + mock_subprocess.return_value = MagicMock( + returncode=1, + stdout="", + stderr="image not found", + ) + + with pytest.raises(ImageScanError): + for _ in provider.run_scan(): + pass + + +class TestImageProviderInputValidation: + def test_invalid_timeout_format_raises_error(self): + """Test that a non-matching timeout string raises ImageInvalidTimeoutError.""" + with pytest.raises(ImageInvalidTimeoutError): + _make_provider(timeout="invalid") + + def test_invalid_timeout_no_unit_raises_error(self): + """Test that a numeric timeout without a unit raises ImageInvalidTimeoutError.""" + with pytest.raises(ImageInvalidTimeoutError): + _make_provider(timeout="300") + + def test_invalid_timeout_wrong_unit_raises_error(self): + """Test that a timeout with an unsupported unit raises ImageInvalidTimeoutError.""" + with pytest.raises(ImageInvalidTimeoutError): + _make_provider(timeout="5d") + + def test_valid_timeout_seconds(self): + """Test that a seconds-based timeout is accepted.""" + provider = _make_provider(timeout="300s") + assert provider.timeout == "300s" + + def test_valid_timeout_hours(self): + """Test that an hours-based timeout is accepted.""" + provider = _make_provider(timeout="1h") + assert provider.timeout == "1h" + + def test_invalid_scanner_raises_error(self): + """Test that an invalid scanner name raises ImageInvalidScannerError.""" + with pytest.raises(ImageInvalidScannerError): + _make_provider(scanners=["vuln", "bad"]) + + def test_invalid_severity_raises_error(self): + """Test that an invalid severity level raises ImageInvalidSeverityError.""" + with pytest.raises(ImageInvalidSeverityError): + _make_provider(trivy_severity=["HIGH", "SUPER_HIGH"]) + + def test_valid_all_scanners(self): + """Test that all valid scanner choices are accepted.""" + provider = _make_provider(scanners=["vuln", "secret", "misconfig", "license"]) + assert provider.scanners == ["vuln", "secret", "misconfig", "license"] + + def test_valid_all_severities(self): + """Test that all valid severity choices are accepted.""" + provider = _make_provider( + trivy_severity=["CRITICAL", "HIGH", "MEDIUM", "LOW", "UNKNOWN"] + ) + assert provider.trivy_severity == [ + "CRITICAL", + "HIGH", + "MEDIUM", + "LOW", + "UNKNOWN", + ] + + def test_image_config_scanners_defaults_to_empty(self): + """Test that image_config_scanners defaults to an empty list.""" + provider = _make_provider() + assert provider.image_config_scanners == [] + + def test_valid_image_config_scanners(self): + """Test that valid image config scanners are accepted.""" + provider = _make_provider(image_config_scanners=["misconfig", "secret"]) + assert provider.image_config_scanners == ["misconfig", "secret"] + + def test_invalid_image_config_scanner_raises_error(self): + """Test that an invalid image config scanner raises ImageInvalidConfigScannerError.""" + with pytest.raises(ImageInvalidConfigScannerError): + _make_provider(image_config_scanners=["misconfig", "vuln"]) + + @patch("subprocess.run") + def test_trivy_command_includes_image_config_scanners(self, mock_subprocess): + """Test that Trivy command includes --image-config-scanners when set.""" + provider = _make_provider(image_config_scanners=["misconfig", "secret"]) + mock_subprocess.return_value = MagicMock( + returncode=0, stdout=get_empty_trivy_output(), stderr="" + ) + + for _ in provider._scan_single_image("alpine:3.18"): + pass + + call_args = mock_subprocess.call_args[0][0] + assert "--image-config-scanners" in call_args + idx = call_args.index("--image-config-scanners") + assert call_args[idx + 1] == "misconfig,secret" + + @patch("subprocess.run") + def test_trivy_command_omits_image_config_scanners_when_empty( + self, mock_subprocess + ): + """Test that Trivy command omits --image-config-scanners when empty.""" + provider = _make_provider(image_config_scanners=[]) + mock_subprocess.return_value = MagicMock( + returncode=0, stdout=get_empty_trivy_output(), stderr="" + ) + + for _ in provider._scan_single_image("alpine:3.18"): + pass + + call_args = mock_subprocess.call_args[0][0] + assert "--image-config-scanners" not in call_args + + +class TestImageProviderErrorCategorization: + def test_categorize_auth_failure(self): + """Test that auth-related errors are categorized correctly.""" + result = ImageProvider._categorize_trivy_error( + "401 unauthorized: access denied" + ) + assert "Auth failure" in result + + def test_categorize_not_found(self): + """Test that not-found errors are categorized correctly.""" + result = ImageProvider._categorize_trivy_error( + "manifest unknown: image not found" + ) + assert "Image not found" in result + + def test_categorize_rate_limit(self): + """Test that rate-limit errors are categorized correctly.""" + result = ImageProvider._categorize_trivy_error("429 too many requests") + assert "Rate limited" in result + + def test_categorize_network_issue(self): + """Test that network errors are categorized correctly.""" + result = ImageProvider._categorize_trivy_error("connection refused to registry") + assert "Network issue" in result + + def test_categorize_unknown_error(self): + """Test that unrecognized errors are returned as-is.""" + msg = "some unknown trivy error" + result = ImageProvider._categorize_trivy_error(msg) + assert result == msg + + +class TestImageProviderNameValidation: + @pytest.mark.parametrize( + "bad_name", + [ + "alpine;rm -rf /", + "image|cat /etc/passwd", + "image&background", + "image$VAR", + "image`whoami`", + "image\ninjected", + "image\rinjected", + ], + ) + def test_image_provider_invalid_image_name_shell_chars(self, bad_name): + """Test that image names with shell metacharacters raise ImageInvalidNameError.""" + with pytest.raises(ImageInvalidNameError): + _make_provider(images=[bad_name]) + + def test_image_provider_invalid_image_name_empty(self): + """Test that an empty string image name raises ImageInvalidNameError.""" + with pytest.raises(ImageInvalidNameError): + _make_provider(images=[""]) + + @pytest.mark.parametrize( + "valid_name", + [ + "alpine:3.18", + "nginx:latest", + "registry.example.com/repo/image:tag", + "ghcr.io/owner/image:v1.2.3", + "myimage@sha256:abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890", + "localhost:5000/myimage:latest", + ], + ) + def test_image_provider_valid_image_names(self, valid_name): + """Test that various valid image name formats pass validation.""" + provider = _make_provider(images=[valid_name]) + assert valid_name in provider.images + + def test_image_provider_image_name_too_long(self): + """Test that a name exceeding 500 chars raises ImageInvalidNameError.""" + long_name = "a" * 501 + with pytest.raises(ImageInvalidNameError): + _make_provider(images=[long_name]) + + def test_image_provider_file_too_many_lines(self): + """Test that a file with more than MAX_IMAGE_LIST_LINES raises ImageListFileReadError.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f: + for i in range(10_001): + f.write(f"image{i}:latest\n") + f.flush() + file_path = f.name + + with pytest.raises(ImageListFileReadError): + _make_provider(images=None, image_list_file=file_path) From 93ac38ca90efa9295a08c8f2d51722cade707258 Mon Sep 17 00:00:00 2001 From: Josema Camacho Date: Thu, 12 Feb 2026 17:09:08 +0100 Subject: [PATCH 12/12] feat(attack-pahts--aws-queries): The rest of Path Finding paths queries (#10008) --- api/CHANGELOG.md | 1 + .../backend/api/attack_paths/queries/aws.py | 2577 ++++++++++++++++- 2 files changed, 2554 insertions(+), 24 deletions(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 226056afea..96cdb90536 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to the **Prowler API** are documented in this file. - Attack Paths: Queries definition now has short description and attribution [(#9983)](https://github.com/prowler-cloud/prowler/pull/9983) - Attack Paths: Internet node is created while scan [(#9992)](https://github.com/prowler-cloud/prowler/pull/9992) +- Attack Paths: Add full paths set from [pathfinding.cloud](https://pathfinding.cloud/) [(#10008)](https://github.com/prowler-cloud/prowler/pull/10008) - Support CSA CCM for the AWS provider [(#10018)](https://github.com/prowler-cloud/prowler/pull/10018) - Support CSA CCM 4.0 for the GCP provider [(#10042)](https://github.com/prowler-cloud/prowler/pull/10042) - Support CSA CCM for the Azure provider [(#10039)](https://github.com/prowler-cloud/prowler/pull/10039) diff --git a/api/src/backend/api/attack_paths/queries/aws.py b/api/src/backend/api/attack_paths/queries/aws.py index 610816a57b..39e5e5716f 100644 --- a/api/src/backend/api/attack_paths/queries/aws.py +++ b/api/src/backend/api/attack_paths/queries/aws.py @@ -324,6 +324,86 @@ AWS_PUBLIC_IP_RESOURCE_LOOKUP = AttackPathsQueryDefinition( # https://github.com/DataDog/pathfinding.cloud # ------------------------------------------------------------------- +# APPRUNNER-001 +AWS_APPRUNNER_PRIVESC_PASSROLE_CREATE_SERVICE = AttackPathsQueryDefinition( + id="aws-apprunner-privesc-passrole-create-service", + name="App Runner Service Creation with Privileged Role (APPRUNNER-001)", + short_description="Create an App Runner service with a privileged IAM role to gain its permissions.", + description="Detect principals who can pass IAM roles and create App Runner services. This allows creating a service with a privileged role attached, gaining that role's permissions via StartCommand execution, a container web shell, or a malicious apprunner.yaml configuration.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - APPRUNNER-001 - iam:PassRole + apprunner:CreateService", + link="https://pathfinding.cloud/paths/apprunner-001", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find apprunner:CreateService permission + MATCH (principal)--(apprunner_policy:AWSPolicy)--(stmt_apprunner:AWSPolicyStatement) + WHERE stmt_apprunner.effect = 'Allow' + AND any(action IN stmt_apprunner.action WHERE + toLower(action) = 'apprunner:createservice' + OR toLower(action) = 'apprunner:*' + OR action = '*' + ) + + // Find roles that trust App Runner tasks service (can be passed to App Runner) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'tasks.apprunner.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# APPRUNNER-002 +AWS_APPRUNNER_PRIVESC_UPDATE_SERVICE = AttackPathsQueryDefinition( + id="aws-apprunner-privesc-update-service", + name="App Runner Service Update for Role Access (APPRUNNER-002)", + short_description="Update an existing App Runner service to leverage its already-attached privileged role.", + description="Detect principals who can update existing App Runner services. This allows modifying a service's configuration to execute arbitrary code with the service's already-attached IAM role, without requiring iam:PassRole. Exploitation methods include injecting a malicious StartCommand, updating to a container image with a web shell, or pointing to a repository with a malicious apprunner.yaml file.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - APPRUNNER-002 - apprunner:UpdateService", + link="https://pathfinding.cloud/paths/apprunner-002", + ), + provider="aws", + cypher=f""" + // Find principals with apprunner:UpdateService permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(update_policy:AWSPolicy)--(stmt_update:AWSPolicyStatement) + WHERE stmt_update.effect = 'Allow' + AND any(action IN stmt_update.action WHERE + toLower(action) = 'apprunner:updateservice' + OR toLower(action) = 'apprunner:*' + OR action = '*' + ) + + // Find existing App Runner services with roles attached (potential targets) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'tasks.apprunner.amazonaws.com'}}) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + # BEDROCK-001 AWS_BEDROCK_PRIVESC_PASSROLE_CODE_INTERPRETER = AttackPathsQueryDefinition( id="aws-bedrock-privesc-passrole-code-interpreter", @@ -331,7 +411,7 @@ AWS_BEDROCK_PRIVESC_PASSROLE_CODE_INTERPRETER = AttackPathsQueryDefinition( short_description="Create a Bedrock AgentCore Code Interpreter with a privileged role attached.", description="Detect principals who can pass IAM roles and create Bedrock AgentCore Code Interpreters. This allows creating a code interpreter with a privileged role attached, gaining that role's permissions.", attribution=AttackPathsQueryAttribution( - text="pathfinding.cloud - BEDROCK-001 - iam:PassRole + bedrock-agentcore:CreateCodeInterpreter", + text="pathfinding.cloud - BEDROCK-001 - iam:PassRole + bedrock-agentcore:CreateCodeInterpreter + bedrock-agentcore:StartCodeInterpreterSession + bedrock-agentcore:InvokeCodeInterpreter", link="https://pathfinding.cloud/paths/bedrock-001", ), provider="aws", @@ -354,6 +434,24 @@ AWS_BEDROCK_PRIVESC_PASSROLE_CODE_INTERPRETER = AttackPathsQueryDefinition( OR action = '*' ) + // Find bedrock-agentcore:StartCodeInterpreterSession permission + MATCH (principal)--(session_policy:AWSPolicy)--(stmt_session:AWSPolicyStatement) + WHERE stmt_session.effect = 'Allow' + AND any(action IN stmt_session.action WHERE + toLower(action) = 'bedrock-agentcore:startcodeinterpretersession' + OR toLower(action) = 'bedrock-agentcore:*' + OR action = '*' + ) + + // Find bedrock-agentcore:InvokeCodeInterpreter permission + MATCH (principal)--(invoke_policy:AWSPolicy)--(stmt_invoke:AWSPolicyStatement) + WHERE stmt_invoke.effect = 'Allow' + AND any(action IN stmt_invoke.action WHERE + toLower(action) = 'bedrock-agentcore:invokecodeinterpreter' + OR toLower(action) = 'bedrock-agentcore:*' + OR action = '*' + ) + // Find roles that trust Bedrock service (can be passed to Bedrock) MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'bedrock.amazonaws.com'}}) WHERE any(resource IN stmt_passrole.resource WHERE @@ -371,6 +469,517 @@ AWS_BEDROCK_PRIVESC_PASSROLE_CODE_INTERPRETER = AttackPathsQueryDefinition( parameters=[], ) +# BEDROCK-002 +AWS_BEDROCK_PRIVESC_INVOKE_CODE_INTERPRETER = AttackPathsQueryDefinition( + id="aws-bedrock-privesc-invoke-code-interpreter", + name="Bedrock Code Interpreter Session Hijacking (BEDROCK-002)", + short_description="Start a session on an existing Bedrock code interpreter to exfiltrate its privileged role credentials.", + description="Detect principals who can start sessions and invoke code on existing Bedrock AgentCore code interpreters. This allows executing arbitrary Python code within an interpreter that has a privileged role attached, gaining that role's credentials via the MicroVM Metadata Service without requiring iam:PassRole.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - BEDROCK-002 - bedrock-agentcore:StartCodeInterpreterSession + bedrock-agentcore:InvokeCodeInterpreter", + link="https://pathfinding.cloud/paths/bedrock-002", + ), + provider="aws", + cypher=f""" + // Find principals with bedrock-agentcore:StartCodeInterpreterSession permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(session_policy:AWSPolicy)--(stmt_session:AWSPolicyStatement) + WHERE stmt_session.effect = 'Allow' + AND any(action IN stmt_session.action WHERE + toLower(action) = 'bedrock-agentcore:startcodeinterpretersession' + OR toLower(action) = 'bedrock-agentcore:*' + OR action = '*' + ) + + // Find bedrock-agentcore:InvokeCodeInterpreter permission + MATCH (principal)--(invoke_policy:AWSPolicy)--(stmt_invoke:AWSPolicyStatement) + WHERE stmt_invoke.effect = 'Allow' + AND any(action IN stmt_invoke.action WHERE + toLower(action) = 'bedrock-agentcore:invokecodeinterpreter' + OR toLower(action) = 'bedrock-agentcore:*' + OR action = '*' + ) + + // Find roles that trust Bedrock service (already attached to existing code interpreters) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'bedrock.amazonaws.com'}}) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# CLOUDFORMATION-001 +AWS_CLOUDFORMATION_PRIVESC_PASSROLE_CREATE_STACK = AttackPathsQueryDefinition( + id="aws-cloudformation-privesc-passrole-create-stack", + name="CloudFormation Stack Creation with Privileged Role (CLOUDFORMATION-001)", + short_description="Create a CloudFormation stack with a privileged role to provision arbitrary AWS resources.", + description="Detect principals who can pass IAM roles and create CloudFormation stacks. This allows launching a stack with a malicious template that executes with the passed role's permissions, enabling creation of resources like IAM users, Lambda functions, or EC2 instances controlled by the attacker.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - CLOUDFORMATION-001 - iam:PassRole + cloudformation:CreateStack", + link="https://pathfinding.cloud/paths/cloudformation-001", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find cloudformation:CreateStack permission + MATCH (principal)--(cfn_policy:AWSPolicy)--(stmt_cfn:AWSPolicyStatement) + WHERE stmt_cfn.effect = 'Allow' + AND any(action IN stmt_cfn.action WHERE + toLower(action) = 'cloudformation:createstack' + OR toLower(action) = 'cloudformation:*' + OR action = '*' + ) + + // Find roles that trust CloudFormation service (can be passed to CloudFormation) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'cloudformation.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# CLOUDFORMATION-002 +AWS_CLOUDFORMATION_PRIVESC_UPDATE_STACK = AttackPathsQueryDefinition( + id="aws-cloudformation-privesc-update-stack", + name="CloudFormation Stack Update for Role Access (CLOUDFORMATION-002)", + short_description="Update an existing CloudFormation stack to leverage its already-attached privileged service role.", + description="Detect principals who can update existing CloudFormation stacks. This allows modifying a stack's template to add new resources (such as IAM roles with admin access) that are created with the stack's already-attached service role permissions, without requiring iam:PassRole.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - CLOUDFORMATION-002 - cloudformation:UpdateStack", + link="https://pathfinding.cloud/paths/cloudformation-002", + ), + provider="aws", + cypher=f""" + // Find principals with cloudformation:UpdateStack permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(update_policy:AWSPolicy)--(stmt_update:AWSPolicyStatement) + WHERE stmt_update.effect = 'Allow' + AND any(action IN stmt_update.action WHERE + toLower(action) = 'cloudformation:updatestack' + OR toLower(action) = 'cloudformation:*' + OR action = '*' + ) + + // Find roles that trust CloudFormation service (already attached to existing stacks) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'cloudformation.amazonaws.com'}}) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# CLOUDFORMATION-003 +AWS_CLOUDFORMATION_PRIVESC_PASSROLE_CREATE_STACKSET = AttackPathsQueryDefinition( + id="aws-cloudformation-privesc-passrole-create-stackset", + name="CloudFormation StackSet Creation with Privileged Role (CLOUDFORMATION-003)", + short_description="Create a CloudFormation StackSet with a privileged execution role to provision arbitrary resources across accounts.", + description="Detect principals who can pass IAM roles, create CloudFormation StackSets, and deploy stack instances. This allows creating a StackSet with a malicious template and a privileged execution role, then deploying instances that create resources (such as IAM roles with admin access) using that role's permissions.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - CLOUDFORMATION-003 - iam:PassRole + cloudformation:CreateStackSet + cloudformation:CreateStackInstances", + link="https://pathfinding.cloud/paths/cloudformation-003", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find cloudformation:CreateStackSet permission + MATCH (principal)--(cfn_policy:AWSPolicy)--(stmt_cfn:AWSPolicyStatement) + WHERE stmt_cfn.effect = 'Allow' + AND any(action IN stmt_cfn.action WHERE + toLower(action) = 'cloudformation:createstackset' + OR toLower(action) = 'cloudformation:*' + OR action = '*' + ) + + // Find cloudformation:CreateStackInstances permission + MATCH (principal)--(cfn_instances_policy:AWSPolicy)--(stmt_cfn_instances:AWSPolicyStatement) + WHERE stmt_cfn_instances.effect = 'Allow' + AND any(action IN stmt_cfn_instances.action WHERE + toLower(action) = 'cloudformation:createstackinstances' + OR toLower(action) = 'cloudformation:*' + OR action = '*' + ) + + // Find roles that trust CloudFormation service (can be passed as execution role) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'cloudformation.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# CLOUDFORMATION-004 +AWS_CLOUDFORMATION_PRIVESC_PASSROLE_UPDATE_STACKSET = AttackPathsQueryDefinition( + id="aws-cloudformation-privesc-passrole-update-stackset", + name="CloudFormation StackSet Update with Privileged Role (CLOUDFORMATION-004)", + short_description="Update an existing CloudFormation StackSet to inject malicious resources using a privileged execution role.", + description="Detect principals who can pass IAM roles and update CloudFormation StackSets. This allows modifying an existing StackSet's template to add resources (such as IAM roles with admin access) that are provisioned by the StackSet's privileged execution role across target accounts.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - CLOUDFORMATION-004 - iam:PassRole + cloudformation:UpdateStackSet", + link="https://pathfinding.cloud/paths/cloudformation-004", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find cloudformation:UpdateStackSet permission + MATCH (principal)--(cfn_policy:AWSPolicy)--(stmt_cfn:AWSPolicyStatement) + WHERE stmt_cfn.effect = 'Allow' + AND any(action IN stmt_cfn.action WHERE + toLower(action) = 'cloudformation:updatestackset' + OR toLower(action) = 'cloudformation:*' + OR action = '*' + ) + + // Find roles that trust CloudFormation service (can be passed as execution role) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'cloudformation.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# CLOUDFORMATION-005 +AWS_CLOUDFORMATION_PRIVESC_CHANGESET = AttackPathsQueryDefinition( + id="aws-cloudformation-privesc-changeset", + name="CloudFormation Change Set Privilege Escalation (CLOUDFORMATION-005)", + short_description="Create and execute a change set on an existing stack to leverage its privileged service role.", + description="Detect principals who can create and execute CloudFormation change sets. This allows modifying an existing stack's template through a staged change set, inheriting the stack's already-attached service role permissions to provision arbitrary resources without requiring iam:PassRole.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - CLOUDFORMATION-005 - cloudformation:CreateChangeSet + cloudformation:ExecuteChangeSet", + link="https://pathfinding.cloud/paths/cloudformation-005", + ), + provider="aws", + cypher=f""" + // Find principals with cloudformation:CreateChangeSet permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(create_policy:AWSPolicy)--(stmt_create:AWSPolicyStatement) + WHERE stmt_create.effect = 'Allow' + AND any(action IN stmt_create.action WHERE + toLower(action) = 'cloudformation:createchangeset' + OR toLower(action) = 'cloudformation:*' + OR action = '*' + ) + + // Find cloudformation:ExecuteChangeSet permission + MATCH (principal)--(exec_policy:AWSPolicy)--(stmt_exec:AWSPolicyStatement) + WHERE stmt_exec.effect = 'Allow' + AND any(action IN stmt_exec.action WHERE + toLower(action) = 'cloudformation:executechangeset' + OR toLower(action) = 'cloudformation:*' + OR action = '*' + ) + + // Find roles that trust CloudFormation service (already attached to existing stacks) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'cloudformation.amazonaws.com'}}) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# CODEBUILD-001 +AWS_CODEBUILD_PRIVESC_PASSROLE_CREATE_PROJECT = AttackPathsQueryDefinition( + id="aws-codebuild-privesc-passrole-create-project", + name="CodeBuild Project Creation with Privileged Role (CODEBUILD-001)", + short_description="Create a CodeBuild project with a privileged role to execute arbitrary code via a malicious buildspec.", + description="Detect principals who can pass IAM roles, create CodeBuild projects, and start builds. This allows creating a project with a privileged role attached and executing arbitrary code through a malicious buildspec, gaining that role's permissions.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - CODEBUILD-001 - iam:PassRole + codebuild:CreateProject + codebuild:StartBuild", + link="https://pathfinding.cloud/paths/codebuild-001", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find codebuild:CreateProject permission + MATCH (principal)--(create_policy:AWSPolicy)--(stmt_create:AWSPolicyStatement) + WHERE stmt_create.effect = 'Allow' + AND any(action IN stmt_create.action WHERE + toLower(action) = 'codebuild:createproject' + OR toLower(action) = 'codebuild:*' + OR action = '*' + ) + + // Find codebuild:StartBuild permission + MATCH (principal)--(build_policy:AWSPolicy)--(stmt_build:AWSPolicyStatement) + WHERE stmt_build.effect = 'Allow' + AND any(action IN stmt_build.action WHERE + toLower(action) = 'codebuild:startbuild' + OR toLower(action) = 'codebuild:*' + OR action = '*' + ) + + // Find roles that trust CodeBuild service (can be passed to CodeBuild) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'codebuild.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# CODEBUILD-002 +AWS_CODEBUILD_PRIVESC_START_BUILD = AttackPathsQueryDefinition( + id="aws-codebuild-privesc-start-build", + name="CodeBuild Buildspec Override for Role Access (CODEBUILD-002)", + short_description="Start a build on an existing CodeBuild project with a buildspec override to execute code with its privileged role.", + description="Detect principals who can start builds on existing CodeBuild projects. This allows overriding the buildspec with malicious commands that execute with the project's already-attached service role permissions, without requiring iam:PassRole or codebuild:CreateProject.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - CODEBUILD-002 - codebuild:StartBuild", + link="https://pathfinding.cloud/paths/codebuild-002", + ), + provider="aws", + cypher=f""" + // Find principals with codebuild:StartBuild permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(build_policy:AWSPolicy)--(stmt_build:AWSPolicyStatement) + WHERE stmt_build.effect = 'Allow' + AND any(action IN stmt_build.action WHERE + toLower(action) = 'codebuild:startbuild' + OR toLower(action) = 'codebuild:*' + OR action = '*' + ) + + // Find roles that trust CodeBuild service (already attached to existing projects) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'codebuild.amazonaws.com'}}) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# CODEBUILD-003 +AWS_CODEBUILD_PRIVESC_START_BUILD_BATCH = AttackPathsQueryDefinition( + id="aws-codebuild-privesc-start-build-batch", + name="CodeBuild Batch Buildspec Override for Role Access (CODEBUILD-003)", + short_description="Start a batch build on an existing CodeBuild project with a buildspec override to execute code with its privileged role.", + description="Detect principals who can start batch builds on existing CodeBuild projects. This allows overriding the buildspec with malicious commands that execute with the project's already-attached service role permissions, without requiring iam:PassRole or codebuild:CreateProject.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - CODEBUILD-003 - codebuild:StartBuildBatch", + link="https://pathfinding.cloud/paths/codebuild-003", + ), + provider="aws", + cypher=f""" + // Find principals with codebuild:StartBuildBatch permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(build_policy:AWSPolicy)--(stmt_build:AWSPolicyStatement) + WHERE stmt_build.effect = 'Allow' + AND any(action IN stmt_build.action WHERE + toLower(action) = 'codebuild:startbuildbatch' + OR toLower(action) = 'codebuild:*' + OR action = '*' + ) + + // Find roles that trust CodeBuild service (already attached to existing projects) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'codebuild.amazonaws.com'}}) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# CODEBUILD-004 +AWS_CODEBUILD_PRIVESC_PASSROLE_CREATE_PROJECT_BATCH = AttackPathsQueryDefinition( + id="aws-codebuild-privesc-passrole-create-project-batch", + name="CodeBuild Batch Project Creation with Privileged Role (CODEBUILD-004)", + short_description="Create a CodeBuild project configured for batch builds with a privileged role to execute arbitrary code via a malicious buildspec.", + description="Detect principals who can pass IAM roles, create CodeBuild projects, and start batch builds. This allows creating a project with a privileged role attached and executing arbitrary code through a malicious batch buildspec, gaining that role's permissions.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - CODEBUILD-004 - iam:PassRole + codebuild:CreateProject + codebuild:StartBuildBatch", + link="https://pathfinding.cloud/paths/codebuild-004", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find codebuild:CreateProject permission + MATCH (principal)--(create_policy:AWSPolicy)--(stmt_create:AWSPolicyStatement) + WHERE stmt_create.effect = 'Allow' + AND any(action IN stmt_create.action WHERE + toLower(action) = 'codebuild:createproject' + OR toLower(action) = 'codebuild:*' + OR action = '*' + ) + + // Find codebuild:StartBuildBatch permission + MATCH (principal)--(batch_policy:AWSPolicy)--(stmt_batch:AWSPolicyStatement) + WHERE stmt_batch.effect = 'Allow' + AND any(action IN stmt_batch.action WHERE + toLower(action) = 'codebuild:startbuildbatch' + OR toLower(action) = 'codebuild:*' + OR action = '*' + ) + + // Find roles that trust CodeBuild service (can be passed to CodeBuild) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'codebuild.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# DATAPIPELINE-001 +AWS_DATAPIPELINE_PRIVESC_PASSROLE_CREATE_PIPELINE = AttackPathsQueryDefinition( + id="aws-datapipeline-privesc-passrole-create-pipeline", + name="Data Pipeline Creation with Privileged Role (DATAPIPELINE-001)", + short_description="Create a Data Pipeline with a privileged role to execute arbitrary commands on provisioned infrastructure.", + description="Detect principals who can pass IAM roles, create Data Pipelines, define pipeline objects, and activate them. This allows creating a pipeline with a privileged role attached and executing arbitrary commands on the provisioned EC2 instances or EMR clusters, gaining that role's permissions.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - DATAPIPELINE-001 - iam:PassRole + datapipeline:CreatePipeline + datapipeline:PutPipelineDefinition + datapipeline:ActivatePipeline", + link="https://pathfinding.cloud/paths/datapipeline-001", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find datapipeline:CreatePipeline permission + MATCH (principal)--(create_policy:AWSPolicy)--(stmt_create:AWSPolicyStatement) + WHERE stmt_create.effect = 'Allow' + AND any(action IN stmt_create.action WHERE + toLower(action) = 'datapipeline:createpipeline' + OR toLower(action) = 'datapipeline:*' + OR action = '*' + ) + + // Find datapipeline:PutPipelineDefinition permission + MATCH (principal)--(put_policy:AWSPolicy)--(stmt_put:AWSPolicyStatement) + WHERE stmt_put.effect = 'Allow' + AND any(action IN stmt_put.action WHERE + toLower(action) = 'datapipeline:putpipelinedefinition' + OR toLower(action) = 'datapipeline:*' + OR action = '*' + ) + + // Find datapipeline:ActivatePipeline permission + MATCH (principal)--(activate_policy:AWSPolicy)--(stmt_activate:AWSPolicyStatement) + WHERE stmt_activate.effect = 'Allow' + AND any(action IN stmt_activate.action WHERE + toLower(action) = 'datapipeline:activatepipeline' + OR toLower(action) = 'datapipeline:*' + OR action = '*' + ) + + // Find roles that trust Data Pipeline or EMR service (can be passed to DataPipeline) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(trusted_principal:AWSPrincipal) + WHERE trusted_principal.arn IN ['datapipeline.amazonaws.com', 'elasticmapreduce.amazonaws.com'] + AND any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + # EC2-001 AWS_EC2_PRIVESC_PASSROLE_IAM = AttackPathsQueryDefinition( id="aws-ec2-privesc-passrole-iam", @@ -558,6 +1167,39 @@ AWS_EC2_PRIVESC_LAUNCH_TEMPLATE = AttackPathsQueryDefinition( parameters=[], ) +# EC2INSTANCECONNECT-003 +AWS_EC2INSTANCECONNECT_PRIVESC_SEND_SSH_PUBLIC_KEY = AttackPathsQueryDefinition( + id="aws-ec2instanceconnect-privesc-send-ssh-public-key", + name="EC2 Instance Connect SSH Access for Role Credentials (EC2INSTANCECONNECT-003)", + short_description="Push a temporary SSH key to an EC2 instance via Instance Connect to access its attached role credentials through IMDS.", + description="Detect principals who can send SSH public keys via EC2 Instance Connect. This allows establishing an SSH session on a running EC2 instance and retrieving the attached IAM role's temporary credentials from the Instance Metadata Service (IMDS), gaining that role's permissions.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - EC2INSTANCECONNECT-003 - ec2-instance-connect:SendSSHPublicKey", + link="https://pathfinding.cloud/paths/ec2instanceconnect-003", + ), + provider="aws", + cypher=f""" + // Find principals with ec2-instance-connect:SendSSHPublicKey permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(connect_policy:AWSPolicy)--(stmt_connect:AWSPolicyStatement) + WHERE stmt_connect.effect = 'Allow' + AND any(action IN stmt_connect.action WHERE + toLower(action) = 'ec2-instance-connect:sendsshpublickey' + OR toLower(action) = 'ec2-instance-connect:*' + OR action = '*' + ) + + // Find EC2 instances with attached roles (targets for credential theft via IMDS) + MATCH path_target = (aws)--(ec2:EC2Instance)-[:STS_ASSUMEROLE_ALLOW]->(target_role:AWSRole) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + # ECS-001 AWS_ECS_PRIVESC_PASSROLE_CREATE_SERVICE = AttackPathsQueryDefinition( id="aws-ecs-privesc-passrole-create-service", @@ -800,6 +1442,104 @@ AWS_ECS_PRIVESC_PASSROLE_RUN_TASK_EXISTING_CLUSTER = AttackPathsQueryDefinition( parameters=[], ) +# ECS-005 +AWS_ECS_PRIVESC_PASSROLE_START_TASK_EXISTING_CLUSTER = AttackPathsQueryDefinition( + id="aws-ecs-privesc-passrole-start-task-existing-cluster", + name="ECS Task Start with Privileged Role on EC2 (ECS-005 - Existing Cluster)", + short_description="Register a task definition with a privileged role and start it on an EC2 container instance to execute arbitrary code.", + description="Detect principals who can pass IAM roles, register ECS task definitions, and start tasks on existing EC2 container instances. Unlike ecs:RunTask which works with both EC2 and Fargate, ecs:StartTask is specific to EC2 launch types and requires specifying an existing container instance ARN. The attacker registers a task definition with a privileged role and starts it on a container instance, gaining that role's permissions.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - ECS-005 - iam:PassRole + ecs:RegisterTaskDefinition + ecs:StartTask", + link="https://pathfinding.cloud/paths/ecs-005", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find ecs:RegisterTaskDefinition permission + MATCH (principal)--(taskdef_policy:AWSPolicy)--(stmt_taskdef:AWSPolicyStatement) + WHERE stmt_taskdef.effect = 'Allow' + AND any(action IN stmt_taskdef.action WHERE + toLower(action) = 'ecs:registertaskdefinition' + OR toLower(action) = 'ecs:*' + OR action = '*' + ) + + // Find ecs:StartTask permission + MATCH (principal)--(starttask_policy:AWSPolicy)--(stmt_starttask:AWSPolicyStatement) + WHERE stmt_starttask.effect = 'Allow' + AND any(action IN stmt_starttask.action WHERE + toLower(action) = 'ecs:starttask' + OR toLower(action) = 'ecs:*' + OR action = '*' + ) + + // Find roles that trust ECS tasks service (can be passed to ECS tasks) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'ecs-tasks.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# ECS-006 +AWS_ECS_PRIVESC_EXECUTE_COMMAND = AttackPathsQueryDefinition( + id="aws-ecs-privesc-execute-command", + name="ECS Exec Container Hijacking for Role Credentials (ECS-006)", + short_description="Shell into a running ECS container via ECS Exec to steal the attached task role's credentials.", + description="Detect principals who can execute commands in running ECS containers and describe tasks. This allows establishing an interactive shell session in a container where ECS Exec is enabled, then retrieving the task role's temporary credentials from the container metadata service, without requiring iam:PassRole.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - ECS-006 - ecs:ExecuteCommand + ecs:DescribeTasks", + link="https://pathfinding.cloud/paths/ecs-006", + ), + provider="aws", + cypher=f""" + // Find principals with ecs:ExecuteCommand permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(exec_policy:AWSPolicy)--(stmt_exec:AWSPolicyStatement) + WHERE stmt_exec.effect = 'Allow' + AND any(action IN stmt_exec.action WHERE + toLower(action) = 'ecs:executecommand' + OR toLower(action) = 'ecs:*' + OR action = '*' + ) + + // Find ecs:DescribeTasks permission (required by AWS CLI to get container runtime ID) + MATCH (principal)--(describe_policy:AWSPolicy)--(stmt_describe:AWSPolicyStatement) + WHERE stmt_describe.effect = 'Allow' + AND any(action IN stmt_describe.action WHERE + toLower(action) = 'ecs:describetasks' + OR toLower(action) = 'ecs:*' + OR action = '*' + ) + + // Find roles that trust ECS tasks service (already attached to running tasks) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'ecs-tasks.amazonaws.com'}}) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + # GLUE-001 AWS_GLUE_PRIVESC_PASSROLE_DEV_ENDPOINT = AttackPathsQueryDefinition( id="aws-glue-privesc-passrole-dev-endpoint", @@ -847,12 +1587,765 @@ AWS_GLUE_PRIVESC_PASSROLE_DEV_ENDPOINT = AttackPathsQueryDefinition( parameters=[], ) +# GLUE-002 +AWS_GLUE_PRIVESC_UPDATE_DEV_ENDPOINT = AttackPathsQueryDefinition( + id="aws-glue-privesc-update-dev-endpoint", + name="Glue Dev Endpoint SSH Hijacking via Update (GLUE-002)", + short_description="Update an existing Glue development endpoint to inject an SSH public key and access its attached role credentials.", + description="Detect principals who can update Glue development endpoints. This allows adding an attacker-controlled SSH public key to an existing dev endpoint that already has a privileged role attached, then SSHing into it to steal the role's temporary credentials without requiring iam:PassRole.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - GLUE-002 - glue:UpdateDevEndpoint", + link="https://pathfinding.cloud/paths/glue-002", + ), + provider="aws", + cypher=f""" + // Find principals with glue:UpdateDevEndpoint permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'glue:updatedevendpoint' + OR toLower(action) = 'glue:*' + OR action = '*' + ) + + // Find roles that trust Glue service (already attached to existing dev endpoints) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'glue.amazonaws.com'}}) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# GLUE-003 +AWS_GLUE_PRIVESC_PASSROLE_CREATE_JOB = AttackPathsQueryDefinition( + id="aws-glue-privesc-passrole-create-job", + name="Glue Job Creation with Privileged Role (GLUE-003)", + short_description="Create a Glue job with a privileged role and start it to execute arbitrary code with that role's permissions.", + description="Detect principals who can pass IAM roles, create Glue jobs, and start job runs. This allows creating a Python shell job with a privileged role attached and executing arbitrary code that modifies IAM permissions, a cost-effective alternative to Glue development endpoints.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - GLUE-003 - iam:PassRole + glue:CreateJob + glue:StartJobRun", + link="https://pathfinding.cloud/paths/glue-003", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find glue:CreateJob permission + MATCH (principal)--(createjob_policy:AWSPolicy)--(stmt_createjob:AWSPolicyStatement) + WHERE stmt_createjob.effect = 'Allow' + AND any(action IN stmt_createjob.action WHERE + toLower(action) = 'glue:createjob' + OR toLower(action) = 'glue:*' + OR action = '*' + ) + + // Find glue:StartJobRun permission + MATCH (principal)--(startjob_policy:AWSPolicy)--(stmt_startjob:AWSPolicyStatement) + WHERE stmt_startjob.effect = 'Allow' + AND any(action IN stmt_startjob.action WHERE + toLower(action) = 'glue:startjobrun' + OR toLower(action) = 'glue:*' + OR action = '*' + ) + + // Find roles that trust Glue service (can be passed to Glue jobs) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'glue.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# GLUE-004 +AWS_GLUE_PRIVESC_PASSROLE_CREATE_JOB_TRIGGER = AttackPathsQueryDefinition( + id="aws-glue-privesc-passrole-create-job-trigger", + name="Glue Job Creation with Scheduled Trigger and Privileged Role (GLUE-004)", + short_description="Create a Glue job with a privileged role and a scheduled trigger to persistently execute arbitrary code.", + description="Detect principals who can pass IAM roles, create Glue jobs, and create triggers with automatic activation. Unlike manual execution via StartJobRun, this creates a persistent attack by scheduling the job to run repeatedly, making it harder to detect and remediate.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - GLUE-004 - iam:PassRole + glue:CreateJob + glue:CreateTrigger", + link="https://pathfinding.cloud/paths/glue-004", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find glue:CreateJob permission + MATCH (principal)--(createjob_policy:AWSPolicy)--(stmt_createjob:AWSPolicyStatement) + WHERE stmt_createjob.effect = 'Allow' + AND any(action IN stmt_createjob.action WHERE + toLower(action) = 'glue:createjob' + OR toLower(action) = 'glue:*' + OR action = '*' + ) + + // Find glue:CreateTrigger permission + MATCH (principal)--(trigger_policy:AWSPolicy)--(stmt_trigger:AWSPolicyStatement) + WHERE stmt_trigger.effect = 'Allow' + AND any(action IN stmt_trigger.action WHERE + toLower(action) = 'glue:createtrigger' + OR toLower(action) = 'glue:*' + OR action = '*' + ) + + // Find roles that trust Glue service (can be passed to Glue jobs) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'glue.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# GLUE-005 +AWS_GLUE_PRIVESC_PASSROLE_UPDATE_JOB = AttackPathsQueryDefinition( + id="aws-glue-privesc-passrole-update-job", + name="Glue Job Hijacking via Update with Privileged Role (GLUE-005)", + short_description="Update an existing Glue job to attach a privileged role and inject malicious code, then start it to gain that role's permissions.", + description="Detect principals who can pass IAM roles, update existing Glue jobs, and start job runs. This allows modifying an existing job's role and script to execute arbitrary code with elevated privileges, a stealthier variant of job creation since it reuses existing infrastructure rather than creating new resources.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - GLUE-005 - iam:PassRole + glue:UpdateJob + glue:StartJobRun", + link="https://pathfinding.cloud/paths/glue-005", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find glue:UpdateJob permission + MATCH (principal)--(updatejob_policy:AWSPolicy)--(stmt_updatejob:AWSPolicyStatement) + WHERE stmt_updatejob.effect = 'Allow' + AND any(action IN stmt_updatejob.action WHERE + toLower(action) = 'glue:updatejob' + OR toLower(action) = 'glue:*' + OR action = '*' + ) + + // Find glue:StartJobRun permission + MATCH (principal)--(startjob_policy:AWSPolicy)--(stmt_startjob:AWSPolicyStatement) + WHERE stmt_startjob.effect = 'Allow' + AND any(action IN stmt_startjob.action WHERE + toLower(action) = 'glue:startjobrun' + OR toLower(action) = 'glue:*' + OR action = '*' + ) + + // Find roles that trust Glue service (can be passed to Glue jobs) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'glue.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# GLUE-006 +AWS_GLUE_PRIVESC_PASSROLE_UPDATE_JOB_TRIGGER = AttackPathsQueryDefinition( + id="aws-glue-privesc-passrole-update-job-trigger", + name="Glue Job Hijacking with Scheduled Trigger and Privileged Role (GLUE-006)", + short_description="Update an existing Glue job to attach a privileged role and inject malicious code, then create a scheduled trigger for persistent automated execution.", + description="Detect principals who can pass IAM roles, update existing Glue jobs, and create triggers with automatic activation. This combines the stealth of modifying existing infrastructure with the persistence of scheduled automation, creating a recurring backdoor that re-executes even after remediation attempts.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - GLUE-006 - iam:PassRole + glue:UpdateJob + glue:CreateTrigger", + link="https://pathfinding.cloud/paths/glue-006", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find glue:UpdateJob permission + MATCH (principal)--(updatejob_policy:AWSPolicy)--(stmt_updatejob:AWSPolicyStatement) + WHERE stmt_updatejob.effect = 'Allow' + AND any(action IN stmt_updatejob.action WHERE + toLower(action) = 'glue:updatejob' + OR toLower(action) = 'glue:*' + OR action = '*' + ) + + // Find glue:CreateTrigger permission + MATCH (principal)--(trigger_policy:AWSPolicy)--(stmt_trigger:AWSPolicyStatement) + WHERE stmt_trigger.effect = 'Allow' + AND any(action IN stmt_trigger.action WHERE + toLower(action) = 'glue:createtrigger' + OR toLower(action) = 'glue:*' + OR action = '*' + ) + + // Find roles that trust Glue service (can be passed to Glue jobs) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'glue.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-001 +AWS_IAM_PRIVESC_CREATE_POLICY_VERSION = AttackPathsQueryDefinition( + id="aws-iam-privesc-create-policy-version", + name="Policy Version Override for Self-Escalation (IAM-001)", + short_description="Create a new version of an attached policy with administrative permissions, instantly escalating the principal's own privileges.", + description="Detect principals who can create new policy versions. If a customer-managed policy is already attached to a principal and that principal has iam:CreatePolicyVersion on that policy, they can replace its contents with a fully permissive policy and set it as the default, gaining immediate administrative access.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-001 - iam:CreatePolicyVersion", + link="https://pathfinding.cloud/paths/iam-001", + ), + provider="aws", + cypher=f""" + // Find principals with iam:CreatePolicyVersion permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:createpolicyversion' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find customer-managed policies attached to the same principal that can be overwritten + MATCH path_target = (aws)--(target_policy:AWSPolicy)--(principal) + WHERE target_policy.arn CONTAINS $provider_uid + AND any(resource IN stmt.resource WHERE + resource = '*' + OR target_policy.arn CONTAINS resource + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-002 +AWS_IAM_PRIVESC_CREATE_ACCESS_KEY = AttackPathsQueryDefinition( + id="aws-iam-privesc-create-access-key", + name="Access Key Creation for Lateral Movement (IAM-002)", + short_description="Create access keys for other IAM users to gain their permissions and move laterally across the account.", + description="Detect principals who can create access keys for other IAM users. This allows generating new credentials for any target user within the resource scope, immediately gaining that user's permissions without needing their password or existing keys.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-002 - iam:CreateAccessKey", + link="https://pathfinding.cloud/paths/iam-002", + ), + provider="aws", + cypher=f""" + // Find principals with iam:CreateAccessKey permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:createaccesskey' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target users that the principal can create access keys for + MATCH path_target = (aws)--(target_user:AWSUser) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_user.arn CONTAINS resource + OR resource CONTAINS target_user.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-003 +AWS_IAM_PRIVESC_DELETE_CREATE_ACCESS_KEY = AttackPathsQueryDefinition( + id="aws-iam-privesc-delete-create-access-key", + name="Access Key Rotation Attack for Lateral Movement (IAM-003)", + short_description="Delete and recreate access keys for other IAM users to bypass the two-key limit and gain their permissions.", + description="Detect principals who can both delete and create access keys for other IAM users. This variation of IAM-002 handles the scenario where a target user already has the maximum of two access keys by first deleting one, then creating a replacement under the attacker's control.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-003 - iam:CreateAccessKey + iam:DeleteAccessKey", + link="https://pathfinding.cloud/paths/iam-003", + ), + provider="aws", + cypher=f""" + // Find principals with iam:CreateAccessKey permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:createaccesskey' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find iam:DeleteAccessKey permission + MATCH (principal)--(delete_policy:AWSPolicy)--(stmt_delete:AWSPolicyStatement) + WHERE stmt_delete.effect = 'Allow' + AND any(action IN stmt_delete.action WHERE + toLower(action) = 'iam:deleteaccesskey' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target users that the principal can rotate access keys for + MATCH path_target = (aws)--(target_user:AWSUser) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_user.arn CONTAINS resource + OR resource CONTAINS target_user.name + ) + AND any(resource IN stmt_delete.resource WHERE + resource = '*' + OR target_user.arn CONTAINS resource + OR resource CONTAINS target_user.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-004 +AWS_IAM_PRIVESC_CREATE_LOGIN_PROFILE = AttackPathsQueryDefinition( + id="aws-iam-privesc-create-login-profile", + name="Console Login Profile Creation for Lateral Movement (IAM-004)", + short_description="Create console login profiles for other IAM users to access the AWS Console with their permissions.", + description="Detect principals who can create console login profiles for other IAM users. By setting a known password on a target user that lacks a login profile, the attacker gains AWS Console access with that user's permissions without needing their existing credentials.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-004 - iam:CreateLoginProfile", + link="https://pathfinding.cloud/paths/iam-004", + ), + provider="aws", + cypher=f""" + // Find principals with iam:CreateLoginProfile permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:createloginprofile' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target users that the principal can create login profiles for + MATCH path_target = (aws)--(target_user:AWSUser) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_user.arn CONTAINS resource + OR resource CONTAINS target_user.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-005 +AWS_IAM_PRIVESC_PUT_ROLE_POLICY = AttackPathsQueryDefinition( + id="aws-iam-privesc-put-role-policy", + name="Inline Policy Injection for Self-Escalation (IAM-005)", + short_description="Attach an inline policy with administrative permissions to your own role, instantly escalating privileges.", + description="Detect roles that can use iam:PutRolePolicy on themselves. A role with this permission can attach an inline policy granting any permissions, including full administrative access, without needing to modify or assume any other resource.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-005 - iam:PutRolePolicy", + link="https://pathfinding.cloud/paths/iam-005", + ), + provider="aws", + cypher=f""" + // Find roles with iam:PutRolePolicy permission scoped to themselves + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(role:AWSRole)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:putrolepolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + AND any(resource IN stmt.resource WHERE + resource = '*' + OR role.arn CONTAINS resource + OR resource CONTAINS role.name + ) + + UNWIND nodes(path_principal) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-006 +AWS_IAM_PRIVESC_UPDATE_LOGIN_PROFILE = AttackPathsQueryDefinition( + id="aws-iam-privesc-update-login-profile", + name="Console Password Override for Lateral Movement (IAM-006)", + short_description="Change the console password of other IAM users to log in as them and gain their permissions.", + description="Detect principals who can update console login profiles for other IAM users. By resetting a target user's password, the attacker gains AWS Console access with that user's permissions. Unlike IAM-004, this targets users who already have a login profile configured.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-006 - iam:UpdateLoginProfile", + link="https://pathfinding.cloud/paths/iam-006", + ), + provider="aws", + cypher=f""" + // Find principals with iam:UpdateLoginProfile permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:updateloginprofile' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target users that the principal can update login profiles for + MATCH path_target = (aws)--(target_user:AWSUser) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_user.arn CONTAINS resource + OR resource CONTAINS target_user.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-007 +AWS_IAM_PRIVESC_PUT_USER_POLICY = AttackPathsQueryDefinition( + id="aws-iam-privesc-put-user-policy", + name="Inline Policy Injection on User for Self-Escalation (IAM-007)", + short_description="Attach an inline policy with administrative permissions to your own IAM user, instantly escalating privileges.", + description="Detect IAM users that can use iam:PutUserPolicy on themselves. A user with this permission can attach an inline policy granting any permissions, including full administrative access, without needing to modify or assume any other resource. This is the user equivalent of IAM-005 (PutRolePolicy).", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-007 - iam:PutUserPolicy", + link="https://pathfinding.cloud/paths/iam-007", + ), + provider="aws", + cypher=f""" + // Find users with iam:PutUserPolicy permission scoped to themselves + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(user:AWSUser)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:putuserpolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + AND any(resource IN stmt.resource WHERE + resource = '*' + OR user.arn CONTAINS resource + OR resource CONTAINS user.name + ) + + UNWIND nodes(path_principal) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-008 +AWS_IAM_PRIVESC_ATTACH_USER_POLICY = AttackPathsQueryDefinition( + id="aws-iam-privesc-attach-user-policy", + name="Managed Policy Attachment on User for Self-Escalation (IAM-008)", + short_description="Attach existing managed policies with administrative permissions to your own IAM user, instantly escalating privileges.", + description="Detect IAM users that can use iam:AttachUserPolicy on themselves. A user with this permission can attach any existing managed policy, including AdministratorAccess, to themselves without needing to modify or assume any other resource. Unlike IAM-007 (PutUserPolicy), this requires an existing managed policy with elevated permissions.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-008 - iam:AttachUserPolicy", + link="https://pathfinding.cloud/paths/iam-008", + ), + provider="aws", + cypher=f""" + // Find users with iam:AttachUserPolicy permission scoped to themselves + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(user:AWSUser)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:attachuserpolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + AND any(resource IN stmt.resource WHERE + resource = '*' + OR user.arn CONTAINS resource + OR resource CONTAINS user.name + ) + + UNWIND nodes(path_principal) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-009 +AWS_IAM_PRIVESC_ATTACH_ROLE_POLICY = AttackPathsQueryDefinition( + id="aws-iam-privesc-attach-role-policy", + name="Managed Policy Attachment on Role for Self-Escalation (IAM-009)", + short_description="Attach existing managed policies with administrative permissions to your own IAM role, instantly escalating privileges.", + description="Detect IAM roles that can use iam:AttachRolePolicy on themselves. A role with this permission can attach any existing managed policy, including AdministratorAccess, to itself without needing to modify or assume any other resource. Unlike IAM-005 (PutRolePolicy), this requires an existing managed policy with elevated permissions.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-009 - iam:AttachRolePolicy", + link="https://pathfinding.cloud/paths/iam-009", + ), + provider="aws", + cypher=f""" + // Find roles with iam:AttachRolePolicy permission scoped to themselves + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(role:AWSRole)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:attachrolepolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + AND any(resource IN stmt.resource WHERE + resource = '*' + OR role.arn CONTAINS resource + OR resource CONTAINS role.name + ) + + UNWIND nodes(path_principal) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-010 +AWS_IAM_PRIVESC_ATTACH_GROUP_POLICY = AttackPathsQueryDefinition( + id="aws-iam-privesc-attach-group-policy", + name="Managed Policy Attachment on Group for Self-Escalation (IAM-010)", + short_description="Attach existing managed policies with administrative permissions to a group you belong to, escalating privileges for all group members.", + description="Detect IAM users that can use iam:AttachGroupPolicy on a group they are a member of. A user with this permission can attach any existing managed policy, including AdministratorAccess, to a group they belong to, immediately escalating privileges for all group members.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-010 - iam:AttachGroupPolicy", + link="https://pathfinding.cloud/paths/iam-010", + ), + provider="aws", + cypher=f""" + // Find users with iam:AttachGroupPolicy permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(user:AWSUser)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:attachgrouppolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find groups the user is a member of and can attach policies to + MATCH path_target = (aws)-[:RESOURCE]->(target_group:AWSGroup)<-[:MEMBER_AWS_GROUP]-(user) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_group.arn CONTAINS resource + OR resource CONTAINS target_group.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-011 +AWS_IAM_PRIVESC_PUT_GROUP_POLICY = AttackPathsQueryDefinition( + id="aws-iam-privesc-put-group-policy", + name="Inline Policy Injection on Group for Self-Escalation (IAM-011)", + short_description="Attach an inline policy with administrative permissions to a group you belong to, escalating privileges for all group members.", + description="Detect IAM users that can use iam:PutGroupPolicy on a group they are a member of. A user with this permission can attach an inline policy granting any permissions to a group they belong to, immediately escalating privileges for all group members. Unlike IAM-010, this does not require an existing managed policy.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-011 - iam:PutGroupPolicy", + link="https://pathfinding.cloud/paths/iam-011", + ), + provider="aws", + cypher=f""" + // Find users with iam:PutGroupPolicy permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(user:AWSUser)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:putgrouppolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find groups the user is a member of and can put policies on + MATCH path_target = (aws)-[:RESOURCE]->(target_group:AWSGroup)<-[:MEMBER_AWS_GROUP]-(user) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_group.arn CONTAINS resource + OR resource CONTAINS target_group.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-012 +AWS_IAM_PRIVESC_UPDATE_ASSUME_ROLE_POLICY = AttackPathsQueryDefinition( + id="aws-iam-privesc-update-assume-role-policy", + name="Trust Policy Hijacking for Role Assumption (IAM-012)", + short_description="Modify a role's trust policy to allow yourself to assume it, gaining the role's permissions.", + description="Detect principals who can update the assume role policy (trust policy) of other IAM roles. By modifying a target role's trust policy to trust the attacker's principal, the attacker can then assume the role and gain all its permissions, including potential administrative access.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-012 - iam:UpdateAssumeRolePolicy", + link="https://pathfinding.cloud/paths/iam-012", + ), + provider="aws", + cypher=f""" + // Find principals with iam:UpdateAssumeRolePolicy permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:updateassumerolepolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target roles whose trust policy can be modified + MATCH path_target = (aws)--(target_role:AWSRole) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-013 +AWS_IAM_PRIVESC_ADD_USER_TO_GROUP = AttackPathsQueryDefinition( + id="aws-iam-privesc-add-user-to-group", + name="Group Membership Hijacking for Privilege Escalation (IAM-013)", + short_description="Add yourself to a privileged IAM group to inherit its permissions, gaining access to all policies attached to the group.", + description="Detect principals who can add users to IAM groups. By adding themselves to a group with elevated permissions such as AdministratorAccess, the attacker immediately inherits all policies attached to that group. The level of access gained depends on the permissions of the target group.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-013 - iam:AddUserToGroup", + link="https://pathfinding.cloud/paths/iam-013", + ), + provider="aws", + cypher=f""" + // Find principals with iam:AddUserToGroup permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:addusertogroup' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target groups the principal can add users to + MATCH path_target = (aws)-[:RESOURCE]->(target_group:AWSGroup) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_group.arn CONTAINS resource + OR resource CONTAINS target_group.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + # IAM-014 AWS_IAM_PRIVESC_ATTACH_ROLE_POLICY_ASSUME_ROLE = AttackPathsQueryDefinition( id="aws-iam-privesc-attach-role-policy-assume-role", - name="Role Policy Attachment and Assumption (IAM-014)", - short_description="Attach policies to IAM roles and then assume them to gain elevated access.", - description="Detect principals who can both attach policies to roles AND assume those roles. This allows modifying a role's permissions then assuming it to gain elevated access.", + name="Managed Policy Attachment with Role Assumption for Lateral Movement (IAM-014)", + short_description="Attach administrative managed policies to another role you can assume, then assume it to gain elevated privileges.", + description="Detect principals who can attach managed policies to a different IAM role and also assume that role. By attaching AdministratorAccess to a target role and then assuming it, the attacker gains full administrative access. This is a variation of IAM-009 for lateral movement where the principal targets another assumable role instead of their own.", attribution=AttackPathsQueryAttribution( text="pathfinding.cloud - IAM-014 - iam:AttachRolePolicy + sts:AssumeRole", link="https://pathfinding.cloud/paths/iam-014", @@ -860,36 +2353,1017 @@ AWS_IAM_PRIVESC_ATTACH_ROLE_POLICY_ASSUME_ROLE = AttackPathsQueryDefinition( provider="aws", cypher=f""" // Find principals with iam:AttachRolePolicy permission - MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(attach_policy:AWSPolicy)--(stmt_attach:AWSPolicyStatement) - WHERE stmt_attach.effect = 'Allow' - AND any(action IN stmt_attach.action WHERE + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE toLower(action) = 'iam:attachrolepolicy' OR toLower(action) = 'iam:*' OR action = '*' ) - // Find sts:AssumeRole permission - MATCH (principal)--(assume_policy:AWSPolicy)--(stmt_assume:AWSPolicyStatement) - WHERE stmt_assume.effect = 'Allow' - AND any(action IN stmt_assume.action WHERE + // Find target roles the principal can assume and attach policies to + MATCH path_target = (aws)--(target_role:AWSRole)<-[:STS_ASSUMEROLE_ALLOW]-(principal) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-015 +AWS_IAM_PRIVESC_ATTACH_USER_POLICY_CREATE_ACCESS_KEY = AttackPathsQueryDefinition( + id="aws-iam-privesc-attach-user-policy-create-access-key", + name="Managed Policy Attachment with Access Key Creation for Lateral Movement (IAM-015)", + short_description="Attach administrative managed policies to another IAM user and create access keys for them to gain programmatic access with elevated privileges.", + description="Detect principals who can attach managed policies to another IAM user and also create access keys for that user. By attaching AdministratorAccess to a target user and creating access keys, the attacker gains programmatic access with the target user's elevated permissions. This combines IAM-008 (AttachUserPolicy) with IAM-002 (CreateAccessKey) for lateral movement.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-015 - iam:AttachUserPolicy + iam:CreateAccessKey", + link="https://pathfinding.cloud/paths/iam-015", + ), + provider="aws", + cypher=f""" + // Find principals with iam:AttachUserPolicy permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:attachuserpolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find iam:CreateAccessKey permission + MATCH (principal)--(policy2:AWSPolicy)--(stmt2:AWSPolicyStatement) + WHERE stmt2.effect = 'Allow' + AND any(action IN stmt2.action WHERE + toLower(action) = 'iam:createaccesskey' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target users the principal can attach policies to and create keys for + MATCH path_target = (aws)--(target_user:AWSUser) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_user.arn CONTAINS resource + OR resource CONTAINS target_user.name + ) + AND any(resource IN stmt2.resource WHERE + resource = '*' + OR target_user.arn CONTAINS resource + OR resource CONTAINS target_user.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-016 +AWS_IAM_PRIVESC_CREATE_POLICY_VERSION_ASSUME_ROLE = AttackPathsQueryDefinition( + id="aws-iam-privesc-create-policy-version-assume-role", + name="Policy Version Override with Role Assumption for Lateral Movement (IAM-016)", + short_description="Create a new version of a customer-managed policy attached to another role with administrative permissions, then assume that role to gain elevated access.", + description="Detect principals who can create new versions of customer-managed policies attached to other roles and also assume those roles. By creating a new policy version with administrative permissions on a policy attached to a target role, then assuming that role, the attacker gains full administrative access. This is a variation of IAM-001 for lateral movement where the modified policy is attached to an assumable role rather than the attacker's own principal.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-016 - iam:CreatePolicyVersion + sts:AssumeRole", + link="https://pathfinding.cloud/paths/iam-016", + ), + provider="aws", + cypher=f""" + // Find principals with iam:CreatePolicyVersion permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:createpolicyversion' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target roles the principal can assume that have customer-managed policies the principal can modify + MATCH path_target = (aws)--(target_role:AWSRole)<-[:STS_ASSUMEROLE_ALLOW]-(principal) + MATCH (target_role)--(target_policy:AWSPolicy) + WHERE target_policy.arn CONTAINS $provider_uid + AND any(resource IN stmt.resource WHERE + resource = '*' + OR target_policy.arn CONTAINS resource + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-017 +AWS_IAM_PRIVESC_PUT_ROLE_POLICY_ASSUME_ROLE = AttackPathsQueryDefinition( + id="aws-iam-privesc-put-role-policy-assume-role", + name="Inline Policy Injection with Role Assumption for Lateral Movement (IAM-017)", + short_description="Attach an inline policy with administrative permissions to another role you can assume, then assume it to gain elevated privileges.", + description="Detect principals who can add inline policies to a different IAM role and also assume that role. By adding an inline policy granting administrative permissions to a target role and then assuming it, the attacker gains full administrative access. This is a variation of IAM-005 for lateral movement where the principal targets another assumable role instead of their own.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-017 - iam:PutRolePolicy + sts:AssumeRole", + link="https://pathfinding.cloud/paths/iam-017", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PutRolePolicy permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:putrolepolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target roles the principal can assume and put inline policies on + MATCH path_target = (aws)--(target_role:AWSRole)<-[:STS_ASSUMEROLE_ALLOW]-(principal) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-018 +AWS_IAM_PRIVESC_PUT_USER_POLICY_CREATE_ACCESS_KEY = AttackPathsQueryDefinition( + id="aws-iam-privesc-put-user-policy-create-access-key", + name="Inline Policy Injection with Access Key Creation for Lateral Movement (IAM-018)", + short_description="Attach an inline policy with administrative permissions to another IAM user and create access keys for them to gain programmatic access with elevated privileges.", + description="Detect principals who can add inline policies to another IAM user and also create access keys for that user. By adding an administrative inline policy to a target user and creating access keys, the attacker gains programmatic access with the target user's elevated permissions. This combines IAM-007 (PutUserPolicy) with IAM-002 (CreateAccessKey) for lateral movement.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-018 - iam:PutUserPolicy + iam:CreateAccessKey", + link="https://pathfinding.cloud/paths/iam-018", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PutUserPolicy permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:putuserpolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find iam:CreateAccessKey permission + MATCH (principal)--(policy2:AWSPolicy)--(stmt2:AWSPolicyStatement) + WHERE stmt2.effect = 'Allow' + AND any(action IN stmt2.action WHERE + toLower(action) = 'iam:createaccesskey' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target users the principal can put policies on and create keys for + MATCH path_target = (aws)--(target_user:AWSUser) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_user.arn CONTAINS resource + OR resource CONTAINS target_user.name + ) + AND any(resource IN stmt2.resource WHERE + resource = '*' + OR target_user.arn CONTAINS resource + OR resource CONTAINS target_user.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-019 +AWS_IAM_PRIVESC_ATTACH_ROLE_POLICY_UPDATE_ASSUME_ROLE = AttackPathsQueryDefinition( + id="aws-iam-privesc-attach-role-policy-update-assume-role", + name="Managed Policy Attachment with Trust Policy Hijacking for Privilege Escalation (IAM-019)", + short_description="Attach administrative managed policies to a role and modify its trust policy to allow yourself to assume it, gaining elevated privileges without prior assume-role access.", + description="Detect principals who can attach managed policies to an IAM role and also update that role's trust policy. By attaching AdministratorAccess and modifying the trust policy to allow the attacker, the principal can then assume the role without needing pre-existing sts:AssumeRole permission. This combines IAM-009 (AttachRolePolicy) with IAM-012 (UpdateAssumeRolePolicy).", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-019 - iam:AttachRolePolicy + iam:UpdateAssumeRolePolicy", + link="https://pathfinding.cloud/paths/iam-019", + ), + provider="aws", + cypher=f""" + // Find principals with iam:AttachRolePolicy permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:attachrolepolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find iam:UpdateAssumeRolePolicy permission + MATCH (principal)--(policy2:AWSPolicy)--(stmt2:AWSPolicyStatement) + WHERE stmt2.effect = 'Allow' + AND any(action IN stmt2.action WHERE + toLower(action) = 'iam:updateassumerolepolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target roles the principal can attach policies to and update trust policy for + MATCH path_target = (aws)--(target_role:AWSRole) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + AND any(resource IN stmt2.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-020 +AWS_IAM_PRIVESC_CREATE_POLICY_VERSION_UPDATE_ASSUME_ROLE = AttackPathsQueryDefinition( + id="aws-iam-privesc-create-policy-version-update-assume-role", + name="Policy Version Override with Trust Policy Hijacking for Privilege Escalation (IAM-020)", + short_description="Create a new version of a customer-managed policy attached to a role with administrative permissions and modify its trust policy to assume it, without prior assume-role access.", + description="Detect principals who can create new versions of customer-managed policies attached to roles and also update those roles' trust policies. By creating an administrative policy version and modifying the trust policy to allow the attacker, the principal can assume the role without needing pre-existing sts:AssumeRole permission. This combines IAM-001 (CreatePolicyVersion) with IAM-012 (UpdateAssumeRolePolicy).", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-020 - iam:CreatePolicyVersion + iam:UpdateAssumeRolePolicy", + link="https://pathfinding.cloud/paths/iam-020", + ), + provider="aws", + cypher=f""" + // Find principals with iam:CreatePolicyVersion permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:createpolicyversion' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find iam:UpdateAssumeRolePolicy permission + MATCH (principal)--(policy2:AWSPolicy)--(stmt2:AWSPolicyStatement) + WHERE stmt2.effect = 'Allow' + AND any(action IN stmt2.action WHERE + toLower(action) = 'iam:updateassumerolepolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target roles with customer-managed policies the principal can modify and update trust policy for + MATCH path_target = (aws)--(target_role:AWSRole) + WHERE any(resource IN stmt2.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + MATCH (target_role)--(target_policy:AWSPolicy) + WHERE target_policy.arn CONTAINS $provider_uid + AND any(resource IN stmt.resource WHERE + resource = '*' + OR target_policy.arn CONTAINS resource + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# IAM-021 +AWS_IAM_PRIVESC_PUT_ROLE_POLICY_UPDATE_ASSUME_ROLE = AttackPathsQueryDefinition( + id="aws-iam-privesc-put-role-policy-update-assume-role", + name="Inline Policy Injection with Trust Policy Hijacking for Privilege Escalation (IAM-021)", + short_description="Add an inline policy with administrative permissions to a role and modify its trust policy to allow yourself to assume it, gaining elevated privileges without prior assume-role access.", + description="Detect principals who can add inline policies to an IAM role and also update that role's trust policy. By adding an administrative inline policy and modifying the trust policy to allow the attacker, the principal can then assume the role without needing pre-existing sts:AssumeRole permission. This combines IAM-005 (PutRolePolicy) with IAM-012 (UpdateAssumeRolePolicy).", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - IAM-021 - iam:PutRolePolicy + iam:UpdateAssumeRolePolicy", + link="https://pathfinding.cloud/paths/iam-021", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PutRolePolicy permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'iam:putrolepolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find iam:UpdateAssumeRolePolicy permission + MATCH (principal)--(policy2:AWSPolicy)--(stmt2:AWSPolicyStatement) + WHERE stmt2.effect = 'Allow' + AND any(action IN stmt2.action WHERE + toLower(action) = 'iam:updateassumerolepolicy' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find target roles the principal can put inline policies on and update trust policy for + MATCH path_target = (aws)--(target_role:AWSRole) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + AND any(resource IN stmt2.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# LAMBDA-001 +AWS_LAMBDA_PRIVESC_PASSROLE_CREATE_FUNCTION = AttackPathsQueryDefinition( + id="aws-lambda-privesc-passrole-create-function", + name="Lambda Function Creation with Privileged Role (LAMBDA-001)", + short_description="Create a Lambda function with a privileged IAM role and invoke it to execute code with that role's permissions.", + description="Detect principals who can create Lambda functions with privileged IAM roles and invoke them. By passing a privileged role to a new Lambda function and invoking it, the attacker executes code with the role's permissions, gaining access to any resources the role can access.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - LAMBDA-001 - iam:PassRole + lambda:CreateFunction + lambda:InvokeFunction", + link="https://pathfinding.cloud/paths/lambda-001", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find lambda:CreateFunction permission + MATCH (principal)--(create_policy:AWSPolicy)--(stmt_create:AWSPolicyStatement) + WHERE stmt_create.effect = 'Allow' + AND any(action IN stmt_create.action WHERE + toLower(action) = 'lambda:createfunction' + OR toLower(action) = 'lambda:*' + OR action = '*' + ) + + // Find lambda:InvokeFunction permission + MATCH (principal)--(invoke_policy:AWSPolicy)--(stmt_invoke:AWSPolicyStatement) + WHERE stmt_invoke.effect = 'Allow' + AND any(action IN stmt_invoke.action WHERE + toLower(action) = 'lambda:invokefunction' + OR toLower(action) = 'lambda:*' + OR action = '*' + ) + + // Find roles that trust Lambda service (can be passed to Lambda) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'lambda.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# LAMBDA-002 +AWS_LAMBDA_PRIVESC_PASSROLE_CREATE_FUNCTION_EVENT_SOURCE = AttackPathsQueryDefinition( + id="aws-lambda-privesc-passrole-create-function-event-source", + name="Lambda Function Creation with Event Source Trigger (LAMBDA-002)", + short_description="Create a Lambda function with a privileged IAM role and an event source mapping to trigger it automatically, executing code with the role's permissions.", + description="Detect principals who can create Lambda functions with privileged IAM roles and configure event source mappings to trigger them. By passing a privileged role to a new Lambda function and creating an event source mapping (DynamoDB stream, Kinesis, SQS), the attacker executes code with elevated privileges without needing to invoke the function directly.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - LAMBDA-002 - iam:PassRole + lambda:CreateFunction + lambda:CreateEventSourceMapping", + link="https://pathfinding.cloud/paths/lambda-002", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find lambda:CreateFunction permission + MATCH (principal)--(create_policy:AWSPolicy)--(stmt_create:AWSPolicyStatement) + WHERE stmt_create.effect = 'Allow' + AND any(action IN stmt_create.action WHERE + toLower(action) = 'lambda:createfunction' + OR toLower(action) = 'lambda:*' + OR action = '*' + ) + + // Find lambda:CreateEventSourceMapping permission + MATCH (principal)--(event_policy:AWSPolicy)--(stmt_event:AWSPolicyStatement) + WHERE stmt_event.effect = 'Allow' + AND any(action IN stmt_event.action WHERE + toLower(action) = 'lambda:createeventsourcemapping' + OR toLower(action) = 'lambda:*' + OR action = '*' + ) + + // Find roles that trust Lambda service (can be passed to Lambda) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'lambda.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# LAMBDA-003 +AWS_LAMBDA_PRIVESC_UPDATE_FUNCTION_CODE = AttackPathsQueryDefinition( + id="aws-lambda-privesc-update-function-code", + name="Lambda Function Code Injection (LAMBDA-003)", + short_description="Modify the code of an existing Lambda function to execute arbitrary commands with the function's execution role permissions.", + description="Detect principals who can update the code of existing Lambda functions. By replacing a Lambda function's code with malicious code, the attacker executes arbitrary commands with the privileges of the function's execution role when it is next invoked, either manually or via automatic triggers.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - LAMBDA-003 - lambda:UpdateFunctionCode", + link="https://pathfinding.cloud/paths/lambda-003", + ), + provider="aws", + cypher=f""" + // Find principals with lambda:UpdateFunctionCode permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'lambda:updatefunctioncode' + OR toLower(action) = 'lambda:*' + OR action = '*' + ) + + // Find existing Lambda functions with execution roles + MATCH path_target = (aws)-[:RESOURCE]->(lambda_fn:AWSLambda)-[:STS_ASSUMEROLE_ALLOW]->(target_role:AWSRole) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR lambda_fn.arn CONTAINS resource + OR resource CONTAINS lambda_fn.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# LAMBDA-004 +AWS_LAMBDA_PRIVESC_UPDATE_FUNCTION_CODE_INVOKE = AttackPathsQueryDefinition( + id="aws-lambda-privesc-update-function-code-invoke", + name="Lambda Function Code Injection with Direct Invocation (LAMBDA-004)", + short_description="Modify the code of an existing Lambda function and invoke it directly to execute arbitrary commands with the function's execution role permissions.", + description="Detect principals who can update the code of existing Lambda functions and invoke them. By replacing a Lambda function's code with malicious code and invoking it directly, the attacker executes arbitrary commands with the privileges of the function's execution role immediately, without waiting for automatic triggers.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - LAMBDA-004 - lambda:UpdateFunctionCode + lambda:InvokeFunction", + link="https://pathfinding.cloud/paths/lambda-004", + ), + provider="aws", + cypher=f""" + // Find principals with lambda:UpdateFunctionCode permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'lambda:updatefunctioncode' + OR toLower(action) = 'lambda:*' + OR action = '*' + ) + + // Find lambda:InvokeFunction permission + MATCH (principal)--(policy2:AWSPolicy)--(stmt2:AWSPolicyStatement) + WHERE stmt2.effect = 'Allow' + AND any(action IN stmt2.action WHERE + toLower(action) = 'lambda:invokefunction' + OR toLower(action) = 'lambda:*' + OR action = '*' + ) + + // Find existing Lambda functions with execution roles + MATCH path_target = (aws)-[:RESOURCE]->(lambda_fn:AWSLambda)-[:STS_ASSUMEROLE_ALLOW]->(target_role:AWSRole) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR lambda_fn.arn CONTAINS resource + OR resource CONTAINS lambda_fn.name + ) + AND any(resource IN stmt2.resource WHERE + resource = '*' + OR lambda_fn.arn CONTAINS resource + OR resource CONTAINS lambda_fn.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# LAMBDA-005 +AWS_LAMBDA_PRIVESC_UPDATE_FUNCTION_CODE_ADD_PERMISSION = AttackPathsQueryDefinition( + id="aws-lambda-privesc-update-function-code-add-permission", + name="Lambda Function Code Injection with Resource Policy Grant (LAMBDA-005)", + short_description="Modify the code of an existing Lambda function and grant yourself invocation permission via its resource-based policy to execute code with the function's execution role.", + description="Detect principals who can update the code of existing Lambda functions and add permissions to their resource-based policies. By replacing a Lambda function's code and granting themselves invoke access through the resource-based policy, the attacker executes malicious code with the function's execution role without needing lambda:InvokeFunction as an IAM permission.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - LAMBDA-005 - lambda:UpdateFunctionCode + lambda:AddPermission", + link="https://pathfinding.cloud/paths/lambda-005", + ), + provider="aws", + cypher=f""" + // Find principals with lambda:UpdateFunctionCode permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'lambda:updatefunctioncode' + OR toLower(action) = 'lambda:*' + OR action = '*' + ) + + // Find lambda:AddPermission permission + MATCH (principal)--(policy2:AWSPolicy)--(stmt2:AWSPolicyStatement) + WHERE stmt2.effect = 'Allow' + AND any(action IN stmt2.action WHERE + toLower(action) = 'lambda:addpermission' + OR toLower(action) = 'lambda:*' + OR action = '*' + ) + + // Find existing Lambda functions with execution roles + MATCH path_target = (aws)-[:RESOURCE]->(lambda_fn:AWSLambda)-[:STS_ASSUMEROLE_ALLOW]->(target_role:AWSRole) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR lambda_fn.arn CONTAINS resource + OR resource CONTAINS lambda_fn.name + ) + AND any(resource IN stmt2.resource WHERE + resource = '*' + OR lambda_fn.arn CONTAINS resource + OR resource CONTAINS lambda_fn.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# LAMBDA-006 +AWS_LAMBDA_PRIVESC_PASSROLE_CREATE_FUNCTION_ADD_PERMISSION = AttackPathsQueryDefinition( + id="aws-lambda-privesc-passrole-create-function-add-permission", + name="Lambda Function Creation with Resource Policy Invocation (LAMBDA-006)", + short_description="Create a Lambda function with a privileged IAM role and grant yourself invocation permission via its resource-based policy to execute code with the role's permissions.", + description="Detect principals who can create Lambda functions with privileged IAM roles and add permissions to their resource-based policies. By passing a privileged role to a new Lambda function and granting themselves invoke access through the resource-based policy, the attacker executes malicious code with elevated privileges without needing lambda:InvokeFunction as an IAM permission.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - LAMBDA-006 - iam:PassRole + lambda:CreateFunction + lambda:AddPermission", + link="https://pathfinding.cloud/paths/lambda-006", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find lambda:CreateFunction permission + MATCH (principal)--(create_policy:AWSPolicy)--(stmt_create:AWSPolicyStatement) + WHERE stmt_create.effect = 'Allow' + AND any(action IN stmt_create.action WHERE + toLower(action) = 'lambda:createfunction' + OR toLower(action) = 'lambda:*' + OR action = '*' + ) + + // Find lambda:AddPermission permission + MATCH (principal)--(perm_policy:AWSPolicy)--(stmt_perm:AWSPolicyStatement) + WHERE stmt_perm.effect = 'Allow' + AND any(action IN stmt_perm.action WHERE + toLower(action) = 'lambda:addpermission' + OR toLower(action) = 'lambda:*' + OR action = '*' + ) + + // Find roles that trust Lambda service (can be passed to Lambda) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'lambda.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# SAGEMAKER-001 +AWS_SAGEMAKER_PRIVESC_PASSROLE_CREATE_NOTEBOOK = AttackPathsQueryDefinition( + id="aws-sagemaker-privesc-passrole-create-notebook", + name="SageMaker Notebook Creation with Privileged Role (SAGEMAKER-001)", + short_description="Create a SageMaker notebook instance with a privileged IAM role to execute arbitrary code with the role's permissions via the Jupyter environment.", + description="Detect principals who can create SageMaker notebook instances with privileged IAM roles. By passing a privileged role to a new notebook instance, the attacker gains shell access through the Jupyter environment and can execute arbitrary commands with the role's permissions.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - SAGEMAKER-001 - iam:PassRole + sagemaker:CreateNotebookInstance", + link="https://pathfinding.cloud/paths/sagemaker-001", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find sagemaker:CreateNotebookInstance permission + MATCH (principal)--(sm_policy:AWSPolicy)--(stmt_sm:AWSPolicyStatement) + WHERE stmt_sm.effect = 'Allow' + AND any(action IN stmt_sm.action WHERE + toLower(action) = 'sagemaker:createnotebookinstance' + OR toLower(action) = 'sagemaker:*' + OR action = '*' + ) + + // Find roles that trust SageMaker service (can be passed to SageMaker) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'sagemaker.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# SAGEMAKER-002 +AWS_SAGEMAKER_PRIVESC_PASSROLE_CREATE_TRAINING_JOB = AttackPathsQueryDefinition( + id="aws-sagemaker-privesc-passrole-create-training-job", + name="SageMaker Training Job Creation with Privileged Role (SAGEMAKER-002)", + short_description="Create a SageMaker training job with a privileged IAM role to execute arbitrary container code with the role's permissions.", + description="Detect principals who can create SageMaker training jobs with privileged IAM roles. By passing a privileged role to a new training job with a malicious training script or container, the attacker executes code with elevated privileges and can exfiltrate credentials or modify AWS resources.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - SAGEMAKER-002 - iam:PassRole + sagemaker:CreateTrainingJob", + link="https://pathfinding.cloud/paths/sagemaker-002", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find sagemaker:CreateTrainingJob permission + MATCH (principal)--(sm_policy:AWSPolicy)--(stmt_sm:AWSPolicyStatement) + WHERE stmt_sm.effect = 'Allow' + AND any(action IN stmt_sm.action WHERE + toLower(action) = 'sagemaker:createtrainingjob' + OR toLower(action) = 'sagemaker:*' + OR action = '*' + ) + + // Find roles that trust SageMaker service (can be passed to SageMaker) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'sagemaker.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# SAGEMAKER-003 +AWS_SAGEMAKER_PRIVESC_PASSROLE_CREATE_PROCESSING_JOB = AttackPathsQueryDefinition( + id="aws-sagemaker-privesc-passrole-create-processing-job", + name="SageMaker Processing Job Creation with Privileged Role (SAGEMAKER-003)", + short_description="Create a SageMaker processing job with a privileged IAM role to execute arbitrary container code with the role's permissions.", + description="Detect principals who can create SageMaker processing jobs with privileged IAM roles. By passing a privileged role to a new processing job with a malicious script or container, the attacker executes code with elevated privileges and can exfiltrate credentials or modify AWS resources.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - SAGEMAKER-003 - iam:PassRole + sagemaker:CreateProcessingJob", + link="https://pathfinding.cloud/paths/sagemaker-003", + ), + provider="aws", + cypher=f""" + // Find principals with iam:PassRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(passrole_policy:AWSPolicy)--(stmt_passrole:AWSPolicyStatement) + WHERE stmt_passrole.effect = 'Allow' + AND any(action IN stmt_passrole.action WHERE + toLower(action) = 'iam:passrole' + OR toLower(action) = 'iam:*' + OR action = '*' + ) + + // Find sagemaker:CreateProcessingJob permission + MATCH (principal)--(sm_policy:AWSPolicy)--(stmt_sm:AWSPolicyStatement) + WHERE stmt_sm.effect = 'Allow' + AND any(action IN stmt_sm.action WHERE + toLower(action) = 'sagemaker:createprocessingjob' + OR toLower(action) = 'sagemaker:*' + OR action = '*' + ) + + // Find roles that trust SageMaker service (can be passed to SageMaker) + MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {{arn: 'sagemaker.amazonaws.com'}}) + WHERE any(resource IN stmt_passrole.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# SAGEMAKER-004 +AWS_SAGEMAKER_PRIVESC_PRESIGNED_NOTEBOOK_URL = AttackPathsQueryDefinition( + id="aws-sagemaker-privesc-presigned-notebook-url", + name="SageMaker Presigned Notebook URL for Privilege Escalation (SAGEMAKER-004)", + short_description="Generate a presigned URL to access an existing SageMaker notebook instance and execute code with its execution role's permissions.", + description="Detect principals who can generate presigned URLs to access existing SageMaker notebook instances. By accessing the Jupyter environment via a presigned URL, the attacker can execute arbitrary code with the permissions of the notebook's execution role without creating any new resources.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - SAGEMAKER-004 - sagemaker:CreatePresignedNotebookInstanceUrl", + link="https://pathfinding.cloud/paths/sagemaker-004", + ), + provider="aws", + cypher=f""" + // Find principals with sagemaker:CreatePresignedNotebookInstanceUrl permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'sagemaker:createpresignednotebookinstanceurl' + OR toLower(action) = 'sagemaker:*' + OR action = '*' + ) + + // Find existing SageMaker notebook instances with execution roles + MATCH path_target = (aws)-[:RESOURCE]->(notebook:AWSSageMakerNotebookInstance)-[:HAS_EXECUTION_ROLE]->(target_role:AWSRole) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR notebook.arn CONTAINS resource + OR resource CONTAINS notebook.notebook_instance_name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# SAGEMAKER-005 +AWS_SAGEMAKER_PRIVESC_LIFECYCLE_CONFIG_NOTEBOOK = AttackPathsQueryDefinition( + id="aws-sagemaker-privesc-lifecycle-config-notebook", + name="SageMaker Notebook Lifecycle Config Injection (SAGEMAKER-005)", + short_description="Inject a malicious lifecycle configuration into an existing SageMaker notebook to execute code with the notebook's execution role during startup.", + description="Detect principals who can inject malicious lifecycle configurations into existing SageMaker notebook instances. By stopping a notebook, attaching a malicious lifecycle config, and restarting it, the attacker executes arbitrary code with the notebook's execution role permissions during startup.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - SAGEMAKER-005 - sagemaker:CreateNotebookInstanceLifecycleConfig + sagemaker:StopNotebookInstance + sagemaker:UpdateNotebookInstance + sagemaker:StartNotebookInstance", + link="https://pathfinding.cloud/paths/sagemaker-005", + ), + provider="aws", + cypher=f""" + // Find principals with sagemaker:CreateNotebookInstanceLifecycleConfig permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'sagemaker:createnotebookinstancelifecycleconfig' + OR toLower(action) = 'sagemaker:*' + OR action = '*' + ) + + // Find sagemaker:UpdateNotebookInstance permission + MATCH (principal)--(policy2:AWSPolicy)--(stmt2:AWSPolicyStatement) + WHERE stmt2.effect = 'Allow' + AND any(action IN stmt2.action WHERE + toLower(action) = 'sagemaker:updatenotebookinstance' + OR toLower(action) = 'sagemaker:*' + OR action = '*' + ) + + // Find sagemaker:StopNotebookInstance permission + MATCH (principal)--(policy3:AWSPolicy)--(stmt3:AWSPolicyStatement) + WHERE stmt3.effect = 'Allow' + AND any(action IN stmt3.action WHERE + toLower(action) = 'sagemaker:stopnotebookinstance' + OR toLower(action) = 'sagemaker:*' + OR action = '*' + ) + + // Find sagemaker:StartNotebookInstance permission + MATCH (principal)--(policy4:AWSPolicy)--(stmt4:AWSPolicyStatement) + WHERE stmt4.effect = 'Allow' + AND any(action IN stmt4.action WHERE + toLower(action) = 'sagemaker:startnotebookinstance' + OR toLower(action) = 'sagemaker:*' + OR action = '*' + ) + + // Find existing SageMaker notebook instances with execution roles + MATCH path_target = (aws)-[:RESOURCE]->(notebook:AWSSageMakerNotebookInstance)-[:HAS_EXECUTION_ROLE]->(target_role:AWSRole) + WHERE any(resource IN stmt2.resource WHERE + resource = '*' + OR notebook.arn CONTAINS resource + OR resource CONTAINS notebook.notebook_instance_name + ) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# SSM-001 +AWS_SSM_PRIVESC_START_SESSION = AttackPathsQueryDefinition( + id="aws-ssm-privesc-start-session", + name="SSM Session Access for EC2 Role Credentials (SSM-001)", + short_description="Start an SSM session on an EC2 instance to access its attached role credentials through IMDS.", + description="Detect principals who can start SSM sessions on EC2 instances. This allows establishing a shell session on a running EC2 instance and retrieving the attached IAM role's temporary credentials from the Instance Metadata Service (IMDS), gaining that role's permissions.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - SSM-001 - ssm:StartSession", + link="https://pathfinding.cloud/paths/ssm-001", + ), + provider="aws", + cypher=f""" + // Find principals with ssm:StartSession permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'ssm:startsession' + OR toLower(action) = 'ssm:*' + OR action = '*' + ) + + // Find EC2 instances with attached roles (targets for credential theft via IMDS) + MATCH path_target = (aws)--(ec2:EC2Instance)-[:STS_ASSUMEROLE_ALLOW]->(target_role:AWSRole) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# SSM-002 +AWS_SSM_PRIVESC_SEND_COMMAND = AttackPathsQueryDefinition( + id="aws-ssm-privesc-send-command", + name="SSM Send Command for EC2 Role Credentials (SSM-002)", + short_description="Execute commands on an EC2 instance via SSM Run Command to access its attached role credentials through IMDS.", + description="Detect principals who can send SSM commands to EC2 instances. This allows executing arbitrary commands on a running EC2 instance and retrieving the attached IAM role's temporary credentials from the Instance Metadata Service (IMDS), gaining that role's permissions.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - SSM-002 - ssm:SendCommand", + link="https://pathfinding.cloud/paths/ssm-002", + ), + provider="aws", + cypher=f""" + // Find principals with ssm:SendCommand permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE + toLower(action) = 'ssm:sendcommand' + OR toLower(action) = 'ssm:*' + OR action = '*' + ) + + // Find EC2 instances with attached roles (targets for credential theft via IMDS) + MATCH path_target = (aws)--(ec2:EC2Instance)-[:STS_ASSUMEROLE_ALLOW]->(target_role:AWSRole) + + UNWIND nodes(path_principal) + nodes(path_target) as n + OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) + + RETURN path_principal, path_target, + collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr + """, + parameters=[], +) + +# STS-001 +AWS_STS_PRIVESC_ASSUME_ROLE = AttackPathsQueryDefinition( + id="aws-sts-privesc-assume-role", + name="Role Assumption for Privilege Escalation (STS-001)", + short_description="Assume IAM roles with elevated permissions by exploiting bidirectional trust between the starting principal and the target role.", + description="Detect principals who can assume other IAM roles via sts:AssumeRole. When a principal has sts:AssumeRole permission and the target role's trust policy allows the principal to assume it (bidirectional trust), the attacker gains all permissions of the target role. This enables privilege escalation when the target role has higher privileges than the starting principal.", + attribution=AttackPathsQueryAttribution( + text="pathfinding.cloud - STS-001 - sts:AssumeRole", + link="https://pathfinding.cloud/paths/sts-001", + ), + provider="aws", + cypher=f""" + // Find principals with sts:AssumeRole permission + MATCH path_principal = (aws:AWSAccount {{id: $provider_uid}})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement) + WHERE stmt.effect = 'Allow' + AND any(action IN stmt.action WHERE toLower(action) = 'sts:assumerole' OR toLower(action) = 'sts:*' OR action = '*' ) - // Find target roles that the principal can both modify AND assume - MATCH path_target = (aws)--(target_role:AWSRole) - WHERE target_role.arn CONTAINS $provider_uid - AND any(resource IN stmt_attach.resource WHERE - resource = '*' - OR target_role.arn CONTAINS resource - OR resource CONTAINS target_role.name - ) - AND any(resource IN stmt_assume.resource WHERE - resource = '*' - OR target_role.arn CONTAINS resource - OR resource CONTAINS target_role.name - ) + // Find target roles the principal can assume (bidirectional trust via Cartography) + MATCH path_target = (aws)--(target_role:AWSRole)<-[:STS_ASSUMEROLE_ALLOW]-(principal) + WHERE any(resource IN stmt.resource WHERE + resource = '*' + OR target_role.arn CONTAINS resource + OR resource CONTAINS target_role.name + ) UNWIND nodes(path_principal) + nodes(path_target) as n OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}}) @@ -916,15 +3390,70 @@ AWS_QUERIES: list[AttackPathsQueryDefinition] = [ AWS_CLASSIC_ELB_INTERNET_EXPOSED, AWS_ELBV2_INTERNET_EXPOSED, AWS_PUBLIC_IP_RESOURCE_LOOKUP, + AWS_APPRUNNER_PRIVESC_PASSROLE_CREATE_SERVICE, + AWS_APPRUNNER_PRIVESC_UPDATE_SERVICE, AWS_BEDROCK_PRIVESC_PASSROLE_CODE_INTERPRETER, + AWS_BEDROCK_PRIVESC_INVOKE_CODE_INTERPRETER, + AWS_CLOUDFORMATION_PRIVESC_PASSROLE_CREATE_STACK, + AWS_CLOUDFORMATION_PRIVESC_UPDATE_STACK, + AWS_CLOUDFORMATION_PRIVESC_PASSROLE_CREATE_STACKSET, + AWS_CLOUDFORMATION_PRIVESC_PASSROLE_UPDATE_STACKSET, + AWS_CLOUDFORMATION_PRIVESC_CHANGESET, + AWS_CODEBUILD_PRIVESC_PASSROLE_CREATE_PROJECT, + AWS_CODEBUILD_PRIVESC_START_BUILD, + AWS_CODEBUILD_PRIVESC_START_BUILD_BATCH, + AWS_CODEBUILD_PRIVESC_PASSROLE_CREATE_PROJECT_BATCH, + AWS_DATAPIPELINE_PRIVESC_PASSROLE_CREATE_PIPELINE, AWS_EC2_PRIVESC_PASSROLE_IAM, AWS_EC2_PRIVESC_MODIFY_INSTANCE_ATTRIBUTE, AWS_EC2_PRIVESC_PASSROLE_SPOT_INSTANCES, AWS_EC2_PRIVESC_LAUNCH_TEMPLATE, + AWS_EC2INSTANCECONNECT_PRIVESC_SEND_SSH_PUBLIC_KEY, AWS_ECS_PRIVESC_PASSROLE_CREATE_SERVICE, AWS_ECS_PRIVESC_PASSROLE_RUN_TASK, AWS_ECS_PRIVESC_PASSROLE_CREATE_SERVICE_EXISTING_CLUSTER, AWS_ECS_PRIVESC_PASSROLE_RUN_TASK_EXISTING_CLUSTER, + AWS_ECS_PRIVESC_PASSROLE_START_TASK_EXISTING_CLUSTER, + AWS_ECS_PRIVESC_EXECUTE_COMMAND, AWS_GLUE_PRIVESC_PASSROLE_DEV_ENDPOINT, + AWS_GLUE_PRIVESC_UPDATE_DEV_ENDPOINT, + AWS_GLUE_PRIVESC_PASSROLE_CREATE_JOB, + AWS_GLUE_PRIVESC_PASSROLE_CREATE_JOB_TRIGGER, + AWS_GLUE_PRIVESC_PASSROLE_UPDATE_JOB, + AWS_GLUE_PRIVESC_PASSROLE_UPDATE_JOB_TRIGGER, + AWS_IAM_PRIVESC_CREATE_POLICY_VERSION, + AWS_IAM_PRIVESC_CREATE_ACCESS_KEY, + AWS_IAM_PRIVESC_DELETE_CREATE_ACCESS_KEY, + AWS_IAM_PRIVESC_CREATE_LOGIN_PROFILE, + AWS_IAM_PRIVESC_PUT_ROLE_POLICY, + AWS_IAM_PRIVESC_UPDATE_LOGIN_PROFILE, + AWS_IAM_PRIVESC_PUT_USER_POLICY, + AWS_IAM_PRIVESC_ATTACH_USER_POLICY, + AWS_IAM_PRIVESC_ATTACH_ROLE_POLICY, + AWS_IAM_PRIVESC_ATTACH_GROUP_POLICY, + AWS_IAM_PRIVESC_PUT_GROUP_POLICY, + AWS_IAM_PRIVESC_UPDATE_ASSUME_ROLE_POLICY, + AWS_IAM_PRIVESC_ADD_USER_TO_GROUP, AWS_IAM_PRIVESC_ATTACH_ROLE_POLICY_ASSUME_ROLE, + AWS_IAM_PRIVESC_ATTACH_USER_POLICY_CREATE_ACCESS_KEY, + AWS_IAM_PRIVESC_CREATE_POLICY_VERSION_ASSUME_ROLE, + AWS_IAM_PRIVESC_PUT_ROLE_POLICY_ASSUME_ROLE, + AWS_IAM_PRIVESC_PUT_USER_POLICY_CREATE_ACCESS_KEY, + AWS_IAM_PRIVESC_ATTACH_ROLE_POLICY_UPDATE_ASSUME_ROLE, + AWS_IAM_PRIVESC_CREATE_POLICY_VERSION_UPDATE_ASSUME_ROLE, + AWS_IAM_PRIVESC_PUT_ROLE_POLICY_UPDATE_ASSUME_ROLE, + AWS_LAMBDA_PRIVESC_PASSROLE_CREATE_FUNCTION, + AWS_LAMBDA_PRIVESC_PASSROLE_CREATE_FUNCTION_EVENT_SOURCE, + AWS_LAMBDA_PRIVESC_UPDATE_FUNCTION_CODE, + AWS_LAMBDA_PRIVESC_UPDATE_FUNCTION_CODE_INVOKE, + AWS_LAMBDA_PRIVESC_UPDATE_FUNCTION_CODE_ADD_PERMISSION, + AWS_LAMBDA_PRIVESC_PASSROLE_CREATE_FUNCTION_ADD_PERMISSION, + AWS_SAGEMAKER_PRIVESC_PASSROLE_CREATE_NOTEBOOK, + AWS_SAGEMAKER_PRIVESC_PASSROLE_CREATE_TRAINING_JOB, + AWS_SAGEMAKER_PRIVESC_PASSROLE_CREATE_PROCESSING_JOB, + AWS_SAGEMAKER_PRIVESC_PRESIGNED_NOTEBOOK_URL, + AWS_SAGEMAKER_PRIVESC_LIFECYCLE_CONFIG_NOTEBOOK, + AWS_SSM_PRIVESC_START_SESSION, + AWS_SSM_PRIVESC_SEND_COMMAND, + AWS_STS_PRIVESC_ASSUME_ROLE, ]