prowler-cloud 5.17.1__py3-none-any.whl → 5.18.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. dashboard/compliance/hipaa_azure.py +25 -0
  2. dashboard/pages/overview.py +20 -11
  3. prowler/AGENTS.md +1 -1
  4. prowler/CHANGELOG.md +43 -0
  5. prowler/__main__.py +5 -0
  6. prowler/compliance/azure/hipaa_azure.json +820 -0
  7. prowler/compliance/m365/cis_4.0_m365.json +6 -2
  8. prowler/compliance/m365/cis_6.0_m365.json +6 -2
  9. prowler/compliance/m365/iso27001_2022_m365.json +13 -11
  10. prowler/compliance/openstack/__init__.py +0 -0
  11. prowler/config/config.py +2 -1
  12. prowler/config/config.yaml +4 -1
  13. prowler/config/openstack_mutelist_example.yaml +60 -0
  14. prowler/lib/check/check.py +4 -0
  15. prowler/lib/check/models.py +27 -2
  16. prowler/lib/cli/parser.py +3 -2
  17. prowler/lib/outputs/finding.py +14 -0
  18. prowler/lib/outputs/html/html.py +72 -0
  19. prowler/lib/outputs/jira/jira.py +3 -3
  20. prowler/lib/outputs/outputs.py +2 -0
  21. prowler/lib/outputs/summary_table.py +7 -0
  22. prowler/lib/timeline/__init__.py +0 -0
  23. prowler/lib/timeline/models.py +27 -0
  24. prowler/lib/timeline/timeline.py +36 -0
  25. prowler/providers/aws/lib/cloudtrail_timeline/__init__.py +0 -0
  26. prowler/providers/aws/lib/cloudtrail_timeline/cloudtrail_timeline.py +218 -0
  27. prowler/providers/aws/services/codebuild/codebuild_project_webhook_filters_use_anchored_patterns/__init__.py +0 -0
  28. prowler/providers/aws/services/codebuild/codebuild_project_webhook_filters_use_anchored_patterns/codebuild_project_webhook_filters_use_anchored_patterns.metadata.json +40 -0
  29. prowler/providers/aws/services/codebuild/codebuild_project_webhook_filters_use_anchored_patterns/codebuild_project_webhook_filters_use_anchored_patterns.py +58 -0
  30. prowler/providers/aws/services/codebuild/codebuild_service.py +45 -0
  31. prowler/providers/aws/services/dynamodb/dynamodb_table_cross_account_access/dynamodb_table_cross_account_access.metadata.json +1 -1
  32. prowler/providers/aws/services/dynamodb/dynamodb_table_cross_account_access/dynamodb_table_cross_account_access.py +4 -0
  33. prowler/providers/aws/services/eventbridge/eventbridge_bus_cross_account_access/eventbridge_bus_cross_account_access.metadata.json +1 -1
  34. prowler/providers/aws/services/eventbridge/eventbridge_bus_cross_account_access/eventbridge_bus_cross_account_access.py +4 -0
  35. prowler/providers/aws/services/eventbridge/eventbridge_schema_registry_cross_account_access/eventbridge_schema_registry_cross_account_access.metadata.json +1 -1
  36. prowler/providers/aws/services/eventbridge/eventbridge_schema_registry_cross_account_access/eventbridge_schema_registry_cross_account_access.py +2 -0
  37. prowler/providers/aws/services/iam/lib/policy.py +19 -3
  38. prowler/providers/aws/services/rds/rds_instance_extended_support/__init__.py +0 -0
  39. prowler/providers/aws/services/rds/rds_instance_extended_support/rds_instance_extended_support.metadata.json +41 -0
  40. prowler/providers/aws/services/rds/rds_instance_extended_support/rds_instance_extended_support.py +37 -0
  41. prowler/providers/aws/services/rds/rds_service.py +4 -0
  42. prowler/providers/aws/services/s3/s3_bucket_cross_account_access/s3_bucket_cross_account_access.metadata.json +1 -1
  43. prowler/providers/aws/services/s3/s3_bucket_cross_account_access/s3_bucket_cross_account_access.py +5 -1
  44. prowler/providers/azure/lib/service/service.py +23 -0
  45. prowler/providers/azure/services/app/app_client_certificates_on/app_client_certificates_on.metadata.json +18 -12
  46. prowler/providers/azure/services/app/app_ensure_auth_is_set_up/app_ensure_auth_is_set_up.metadata.json +18 -11
  47. prowler/providers/azure/services/app/app_ensure_http_is_redirected_to_https/app_ensure_http_is_redirected_to_https.metadata.json +19 -12
  48. prowler/providers/azure/services/app/app_ensure_java_version_is_latest/app_ensure_java_version_is_latest.metadata.json +19 -12
  49. prowler/providers/azure/services/app/app_ensure_php_version_is_latest/app_ensure_php_version_is_latest.metadata.json +19 -12
  50. prowler/providers/azure/services/app/app_ensure_python_version_is_latest/app_ensure_python_version_is_latest.metadata.json +19 -12
  51. prowler/providers/azure/services/app/app_ensure_using_http20/app_ensure_using_http20.metadata.json +18 -11
  52. prowler/providers/azure/services/app/app_ftp_deployment_disabled/app_ftp_deployment_disabled.metadata.json +21 -13
  53. prowler/providers/azure/services/app/app_function_access_keys_configured/app_function_access_keys_configured.metadata.json +19 -11
  54. prowler/providers/azure/services/app/app_function_application_insights_enabled/app_function_application_insights_enabled.metadata.json +21 -14
  55. prowler/providers/azure/services/app/app_function_ftps_deployment_disabled/app_function_ftps_deployment_disabled.metadata.json +18 -13
  56. prowler/providers/azure/services/app/app_function_identity_is_configured/app_function_identity_is_configured.metadata.json +20 -13
  57. prowler/providers/azure/services/app/app_function_identity_without_admin_privileges/app_function_identity_without_admin_privileges.metadata.json +18 -11
  58. prowler/providers/azure/services/app/app_function_latest_runtime_version/app_function_latest_runtime_version.metadata.json +20 -13
  59. prowler/providers/azure/services/app/app_function_not_publicly_accessible/app_function_not_publicly_accessible.metadata.json +20 -13
  60. prowler/providers/azure/services/app/app_function_vnet_integration_enabled/app_function_vnet_integration_enabled.metadata.json +21 -14
  61. prowler/providers/azure/services/app/app_http_logs_enabled/app_http_logs_enabled.metadata.json +18 -12
  62. prowler/providers/azure/services/app/app_minimum_tls_version_12/app_minimum_tls_version_12.metadata.json +20 -12
  63. prowler/providers/azure/services/app/app_register_with_identity/app_register_with_identity.metadata.json +18 -11
  64. prowler/providers/azure/services/appinsights/appinsights_ensure_is_configured/appinsights_ensure_is_configured.metadata.json +18 -12
  65. prowler/providers/azure/services/containerregistry/containerregistry_admin_user_disabled/containerregistry_admin_user_disabled.metadata.json +17 -11
  66. prowler/providers/azure/services/containerregistry/containerregistry_not_publicly_accessible/containerregistry_not_publicly_accessible.metadata.json +18 -12
  67. prowler/providers/azure/services/containerregistry/containerregistry_uses_private_link/containerregistry_uses_private_link.metadata.json +21 -13
  68. prowler/providers/azure/services/cosmosdb/cosmosdb_account_firewall_use_selected_networks/cosmosdb_account_firewall_use_selected_networks.metadata.json +20 -12
  69. prowler/providers/azure/services/cosmosdb/cosmosdb_account_use_aad_and_rbac/cosmosdb_account_use_aad_and_rbac.metadata.json +19 -13
  70. prowler/providers/azure/services/cosmosdb/cosmosdb_account_use_private_endpoints/cosmosdb_account_use_private_endpoints.metadata.json +20 -13
  71. prowler/providers/azure/services/databricks/databricks_workspace_cmk_encryption_enabled/databricks_workspace_cmk_encryption_enabled.metadata.json +20 -14
  72. prowler/providers/azure/services/databricks/databricks_workspace_vnet_injection_enabled/databricks_workspace_vnet_injection_enabled.metadata.json +20 -14
  73. prowler/providers/azure/services/defender/defender_additional_email_configured_with_a_security_contact/defender_additional_email_configured_with_a_security_contact.metadata.json +20 -13
  74. prowler/providers/azure/services/defender/defender_assessments_vm_endpoint_protection_installed/defender_assessments_vm_endpoint_protection_installed.metadata.json +17 -11
  75. prowler/providers/azure/services/defender/defender_attack_path_notifications_properly_configured/defender_attack_path_notifications_properly_configured.metadata.json +19 -13
  76. prowler/providers/azure/services/defender/defender_auto_provisioning_log_analytics_agent_vms_on/defender_auto_provisioning_log_analytics_agent_vms_on.metadata.json +20 -13
  77. prowler/providers/azure/services/defender/defender_auto_provisioning_vulnerabilty_assessments_machines_on/defender_auto_provisioning_vulnerabilty_assessments_machines_on.metadata.json +19 -12
  78. prowler/providers/azure/services/defender/defender_container_images_resolved_vulnerabilities/defender_container_images_resolved_vulnerabilities.metadata.json +20 -12
  79. prowler/providers/azure/services/defender/defender_container_images_scan_enabled/defender_container_images_scan_enabled.metadata.json +22 -13
  80. prowler/providers/azure/services/defender/defender_ensure_defender_for_app_services_is_on/defender_ensure_defender_for_app_services_is_on.metadata.json +17 -11
  81. prowler/providers/azure/services/defender/defender_ensure_defender_for_arm_is_on/defender_ensure_defender_for_arm_is_on.metadata.json +17 -11
  82. prowler/providers/azure/services/defender/defender_ensure_defender_for_azure_sql_databases_is_on/defender_ensure_defender_for_azure_sql_databases_is_on.metadata.json +17 -11
  83. prowler/providers/azure/services/defender/defender_ensure_defender_for_containers_is_on/defender_ensure_defender_for_containers_is_on.metadata.json +17 -11
  84. prowler/providers/azure/services/defender/defender_ensure_defender_for_cosmosdb_is_on/defender_ensure_defender_for_cosmosdb_is_on.metadata.json +17 -11
  85. prowler/providers/azure/services/defender/defender_ensure_defender_for_databases_is_on/defender_ensure_defender_for_databases_is_on.metadata.json +17 -11
  86. prowler/providers/azure/services/defender/defender_ensure_defender_for_dns_is_on/defender_ensure_defender_for_dns_is_on.metadata.json +17 -11
  87. prowler/providers/azure/services/defender/defender_ensure_defender_for_keyvault_is_on/defender_ensure_defender_for_keyvault_is_on.metadata.json +17 -11
  88. prowler/providers/azure/services/defender/defender_ensure_defender_for_os_relational_databases_is_on/defender_ensure_defender_for_os_relational_databases_is_on.metadata.json +17 -11
  89. prowler/providers/azure/services/defender/defender_ensure_defender_for_server_is_on/defender_ensure_defender_for_server_is_on.metadata.json +19 -11
  90. prowler/providers/azure/services/defender/defender_ensure_defender_for_sql_servers_is_on/defender_ensure_defender_for_sql_servers_is_on.metadata.json +17 -11
  91. prowler/providers/azure/services/defender/defender_ensure_defender_for_storage_is_on/defender_ensure_defender_for_storage_is_on.metadata.json +17 -11
  92. prowler/providers/azure/services/defender/defender_ensure_iot_hub_defender_is_on/defender_ensure_iot_hub_defender_is_on.metadata.json +17 -11
  93. prowler/providers/azure/services/defender/defender_ensure_mcas_is_enabled/defender_ensure_mcas_is_enabled.metadata.json +20 -12
  94. prowler/providers/azure/services/defender/defender_ensure_notify_alerts_severity_is_high/defender_ensure_notify_alerts_severity_is_high.metadata.json +19 -12
  95. prowler/providers/azure/services/defender/defender_ensure_notify_emails_to_owners/defender_ensure_notify_emails_to_owners.metadata.json +19 -12
  96. prowler/providers/azure/services/defender/defender_ensure_system_updates_are_applied/defender_ensure_system_updates_are_applied.metadata.json +17 -9
  97. prowler/providers/azure/services/defender/defender_ensure_wdatp_is_enabled/defender_ensure_wdatp_is_enabled.metadata.json +21 -13
  98. prowler/providers/azure/services/entra/entra_service.py +3 -11
  99. prowler/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa.py +6 -0
  100. prowler/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks.metadata.json +19 -13
  101. prowler/providers/azure/services/iam/iam_role_user_access_admin_restricted/iam_role_user_access_admin_restricted.metadata.json +16 -10
  102. prowler/providers/azure/services/iam/iam_subscription_roles_owner_custom_not_created/iam_subscription_roles_owner_custom_not_created.metadata.json +18 -12
  103. prowler/providers/azure/services/keyvault/keyvault_rbac_secret_expiration_set/keyvault_rbac_secret_expiration_set.py +10 -11
  104. prowler/providers/azure/services/keyvault/keyvault_service.py +164 -81
  105. prowler/providers/azure/services/mysql/mysql_flexible_server_audit_log_connection_activated/mysql_flexible_server_audit_log_connection_activated.metadata.json +18 -12
  106. prowler/providers/azure/services/mysql/mysql_flexible_server_audit_log_enabled/mysql_flexible_server_audit_log_enabled.metadata.json +19 -12
  107. prowler/providers/azure/services/mysql/mysql_flexible_server_minimum_tls_version_12/mysql_flexible_server_minimum_tls_version_12.metadata.json +18 -12
  108. prowler/providers/azure/services/mysql/mysql_flexible_server_ssl_connection_enabled/mysql_flexible_server_ssl_connection_enabled.metadata.json +19 -12
  109. prowler/providers/azure/services/network/network_bastion_host_exists/network_bastion_host_exists.metadata.json +21 -12
  110. prowler/providers/azure/services/network/network_flow_log_captured_sent/network_flow_log_captured_sent.metadata.json +19 -12
  111. prowler/providers/azure/services/network/network_flow_log_more_than_90_days/network_flow_log_more_than_90_days.metadata.json +21 -12
  112. prowler/providers/azure/services/network/network_http_internet_access_restricted/network_http_internet_access_restricted.metadata.json +18 -12
  113. prowler/providers/azure/services/network/network_public_ip_shodan/network_public_ip_shodan.metadata.json +15 -10
  114. prowler/providers/azure/services/network/network_rdp_internet_access_restricted/network_rdp_internet_access_restricted.metadata.json +20 -12
  115. prowler/providers/azure/services/network/network_ssh_internet_access_restricted/network_ssh_internet_access_restricted.metadata.json +19 -12
  116. prowler/providers/azure/services/network/network_udp_internet_access_restricted/network_udp_internet_access_restricted.metadata.json +19 -12
  117. prowler/providers/azure/services/network/network_watcher_enabled/network_watcher_enabled.metadata.json +21 -13
  118. prowler/providers/azure/services/policy/policy_ensure_asc_enforcement_enabled/policy_ensure_asc_enforcement_enabled.metadata.json +16 -11
  119. prowler/providers/azure/services/postgresql/postgresql_flexible_server_allow_access_services_disabled/postgresql_flexible_server_allow_access_services_disabled.metadata.json +20 -13
  120. prowler/providers/azure/services/postgresql/postgresql_flexible_server_connection_throttling_on/postgresql_flexible_server_connection_throttling_on.metadata.json +18 -12
  121. prowler/providers/azure/services/postgresql/postgresql_flexible_server_enforce_ssl_enabled/postgresql_flexible_server_enforce_ssl_enabled.metadata.json +19 -13
  122. prowler/providers/azure/services/postgresql/postgresql_flexible_server_entra_id_authentication_enabled/postgresql_flexible_server_entra_id_authentication_enabled.metadata.json +4 -4
  123. prowler/providers/azure/services/postgresql/postgresql_flexible_server_log_checkpoints_on/postgresql_flexible_server_log_checkpoints_on.metadata.json +19 -13
  124. prowler/providers/azure/services/postgresql/postgresql_flexible_server_log_connections_on/postgresql_flexible_server_log_connections_on.metadata.json +18 -11
  125. prowler/providers/azure/services/postgresql/postgresql_flexible_server_log_disconnections_on/postgresql_flexible_server_log_disconnections_on.metadata.json +18 -12
  126. prowler/providers/azure/services/postgresql/postgresql_flexible_server_log_retention_days_greater_3/postgresql_flexible_server_log_retention_days_greater_3.metadata.json +18 -12
  127. prowler/providers/azure/services/sqlserver/sqlserver_auditing_enabled/sqlserver_auditing_enabled.metadata.json +20 -13
  128. prowler/providers/azure/services/sqlserver/sqlserver_auditing_retention_90_days/sqlserver_auditing_retention_90_days.metadata.json +20 -12
  129. prowler/providers/azure/services/sqlserver/sqlserver_azuread_administrator_enabled/sqlserver_azuread_administrator_enabled.metadata.json +18 -12
  130. prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled.metadata.json +23 -13
  131. prowler/providers/azure/services/sqlserver/sqlserver_recommended_minimal_tls_version/sqlserver_recommended_minimal_tls_version.metadata.json +19 -12
  132. prowler/providers/azure/services/sqlserver/sqlserver_tde_encrypted_with_cmk/sqlserver_tde_encrypted_with_cmk.metadata.json +20 -13
  133. prowler/providers/azure/services/sqlserver/sqlserver_tde_encryption_enabled/sqlserver_tde_encryption_enabled.metadata.json +20 -13
  134. prowler/providers/azure/services/sqlserver/sqlserver_unrestricted_inbound_access/sqlserver_unrestricted_inbound_access.metadata.json +18 -12
  135. prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled.metadata.json +19 -12
  136. prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled.metadata.json +19 -12
  137. prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured.metadata.json +18 -12
  138. prowler/providers/azure/services/sqlserver/sqlserver_vulnerability_assessment_enabled/sqlserver_vulnerability_assessment_enabled.metadata.json +19 -12
  139. prowler/providers/azure/services/storage/storage_account_key_access_disabled/storage_account_key_access_disabled.metadata.json +17 -12
  140. prowler/providers/azure/services/storage/storage_blob_public_access_level_is_disabled/storage_blob_public_access_level_is_disabled.metadata.json +18 -12
  141. prowler/providers/azure/services/storage/storage_blob_versioning_is_enabled/storage_blob_versioning_is_enabled.metadata.json +19 -11
  142. prowler/providers/azure/services/storage/storage_cross_tenant_replication_disabled/storage_cross_tenant_replication_disabled.metadata.json +19 -13
  143. prowler/providers/azure/services/storage/storage_default_network_access_rule_is_denied/storage_default_network_access_rule_is_denied.metadata.json +19 -12
  144. prowler/providers/azure/services/storage/storage_default_to_entra_authorization_enabled/storage_default_to_entra_authorization_enabled.metadata.json +20 -13
  145. prowler/providers/azure/services/storage/storage_ensure_azure_services_are_trusted_to_access_is_enabled/storage_ensure_azure_services_are_trusted_to_access_is_enabled.metadata.json +17 -10
  146. prowler/providers/azure/services/storage/storage_ensure_encryption_with_customer_managed_keys/storage_ensure_encryption_with_customer_managed_keys.metadata.json +15 -10
  147. prowler/providers/azure/services/storage/storage_ensure_file_shares_soft_delete_is_enabled/storage_ensure_file_shares_soft_delete_is_enabled.metadata.json +18 -12
  148. prowler/providers/azure/services/storage/storage_ensure_minimum_tls_version_12/storage_ensure_minimum_tls_version_12.metadata.json +14 -10
  149. prowler/providers/azure/services/storage/storage_ensure_private_endpoints_in_storage_accounts/storage_ensure_private_endpoints_in_storage_accounts.metadata.json +19 -11
  150. prowler/providers/azure/services/storage/storage_ensure_soft_delete_is_enabled/storage_ensure_soft_delete_is_enabled.metadata.json +17 -12
  151. prowler/providers/azure/services/storage/storage_geo_redundant_enabled/storage_geo_redundant_enabled.metadata.json +19 -12
  152. prowler/providers/azure/services/storage/storage_infrastructure_encryption_is_enabled/storage_infrastructure_encryption_is_enabled.metadata.json +13 -9
  153. prowler/providers/azure/services/storage/storage_key_rotation_90_days/storage_key_rotation_90_days.metadata.json +17 -12
  154. prowler/providers/azure/services/storage/storage_secure_transfer_required_is_enabled/storage_secure_transfer_required_is_enabled.metadata.json +15 -11
  155. prowler/providers/azure/services/storage/storage_smb_channel_encryption_with_secure_algorithm/storage_smb_channel_encryption_with_secure_algorithm.metadata.json +19 -12
  156. prowler/providers/azure/services/storage/storage_smb_protocol_version_is_latest/storage_smb_protocol_version_is_latest.metadata.json +19 -13
  157. prowler/providers/cloudflare/cloudflare_provider.py +95 -12
  158. prowler/providers/cloudflare/lib/arguments/arguments.py +7 -0
  159. prowler/providers/cloudflare/services/dns/dns_record_cname_target_valid/__init__.py +0 -0
  160. prowler/providers/cloudflare/services/dns/dns_record_cname_target_valid/dns_record_cname_target_valid.metadata.json +36 -0
  161. prowler/providers/cloudflare/services/dns/dns_record_cname_target_valid/dns_record_cname_target_valid.py +109 -0
  162. prowler/providers/cloudflare/services/dns/dns_record_no_internal_ip/__init__.py +0 -0
  163. prowler/providers/cloudflare/services/dns/dns_record_no_internal_ip/dns_record_no_internal_ip.metadata.json +36 -0
  164. prowler/providers/cloudflare/services/dns/dns_record_no_internal_ip/dns_record_no_internal_ip.py +73 -0
  165. prowler/providers/cloudflare/services/dns/dns_record_no_wildcard/__init__.py +0 -0
  166. prowler/providers/cloudflare/services/dns/dns_record_no_wildcard/dns_record_no_wildcard.metadata.json +36 -0
  167. prowler/providers/cloudflare/services/dns/dns_record_no_wildcard/dns_record_no_wildcard.py +60 -0
  168. prowler/providers/cloudflare/services/dns/dns_record_proxied/__init__.py +0 -0
  169. prowler/providers/cloudflare/services/dns/dns_record_proxied/dns_record_proxied.metadata.json +36 -0
  170. prowler/providers/cloudflare/services/dns/dns_record_proxied/dns_record_proxied.py +49 -0
  171. prowler/providers/cloudflare/services/dns/dns_service.py +52 -6
  172. prowler/providers/cloudflare/services/firewall/__init__.py +0 -0
  173. prowler/providers/cloudflare/services/firewall/firewall_client.py +4 -0
  174. prowler/providers/cloudflare/services/firewall/firewall_service.py +123 -0
  175. prowler/providers/cloudflare/services/zone/zone_firewall_blocking_rules_configured/__init__.py +0 -0
  176. prowler/providers/cloudflare/services/zone/zone_firewall_blocking_rules_configured/zone_firewall_blocking_rules_configured.metadata.json +36 -0
  177. prowler/providers/cloudflare/services/zone/zone_firewall_blocking_rules_configured/zone_firewall_blocking_rules_configured.py +53 -0
  178. prowler/providers/cloudflare/services/zone/zone_service.py +133 -1
  179. prowler/providers/cloudflare/services/zone/zone_waf_owasp_ruleset_enabled/__init__.py +0 -0
  180. prowler/providers/cloudflare/services/zone/zone_waf_owasp_ruleset_enabled/zone_waf_owasp_ruleset_enabled.metadata.json +36 -0
  181. prowler/providers/cloudflare/services/zone/zone_waf_owasp_ruleset_enabled/zone_waf_owasp_ruleset_enabled.py +58 -0
  182. prowler/providers/common/provider.py +23 -0
  183. prowler/providers/gcp/services/compute/compute_instance_suspended_without_persistent_disks/__init__.py +0 -0
  184. prowler/providers/gcp/services/compute/compute_instance_suspended_without_persistent_disks/compute_instance_suspended_without_persistent_disks.metadata.json +37 -0
  185. prowler/providers/gcp/services/compute/compute_instance_suspended_without_persistent_disks/compute_instance_suspended_without_persistent_disks.py +35 -0
  186. prowler/providers/gcp/services/compute/compute_service.py +2 -0
  187. prowler/providers/m365/lib/powershell/m365_powershell.py +47 -1
  188. prowler/providers/m365/services/defender/defender_service.py +52 -0
  189. prowler/providers/m365/services/defender/defender_zap_for_teams_enabled/__init__.py +0 -0
  190. prowler/providers/m365/services/defender/defender_zap_for_teams_enabled/defender_zap_for_teams_enabled.metadata.json +38 -0
  191. prowler/providers/m365/services/defender/defender_zap_for_teams_enabled/defender_zap_for_teams_enabled.py +53 -0
  192. prowler/providers/m365/services/exchange/exchange_service.py +78 -0
  193. prowler/providers/m365/services/exchange/exchange_shared_mailbox_sign_in_disabled/__init__.py +0 -0
  194. prowler/providers/m365/services/exchange/exchange_shared_mailbox_sign_in_disabled/exchange_shared_mailbox_sign_in_disabled.metadata.json +37 -0
  195. prowler/providers/m365/services/exchange/exchange_shared_mailbox_sign_in_disabled/exchange_shared_mailbox_sign_in_disabled.py +59 -0
  196. prowler/providers/openstack/__init__.py +0 -0
  197. prowler/providers/openstack/exceptions/__init__.py +0 -0
  198. prowler/providers/openstack/exceptions/exceptions.py +166 -0
  199. prowler/providers/openstack/lib/__init__.py +0 -0
  200. prowler/providers/openstack/lib/arguments/__init__.py +0 -0
  201. prowler/providers/openstack/lib/arguments/arguments.py +113 -0
  202. prowler/providers/openstack/lib/mutelist/__init__.py +0 -0
  203. prowler/providers/openstack/lib/mutelist/mutelist.py +31 -0
  204. prowler/providers/openstack/lib/service/__init__.py +0 -0
  205. prowler/providers/openstack/lib/service/service.py +21 -0
  206. prowler/providers/openstack/models.py +100 -0
  207. prowler/providers/openstack/openstack_provider.py +515 -0
  208. prowler/providers/openstack/services/__init__.py +0 -0
  209. prowler/providers/openstack/services/compute/__init__.py +0 -0
  210. prowler/providers/openstack/services/compute/compute_client.py +4 -0
  211. prowler/providers/openstack/services/compute/compute_instance_security_groups_attached/__init__.py +0 -0
  212. prowler/providers/openstack/services/compute/compute_instance_security_groups_attached/compute_instance_security_groups_attached.metadata.json +40 -0
  213. prowler/providers/openstack/services/compute/compute_instance_security_groups_attached/compute_instance_security_groups_attached.py +35 -0
  214. prowler/providers/openstack/services/compute/compute_service.py +63 -0
  215. {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.1.dist-info}/METADATA +11 -9
  216. {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.1.dist-info}/RECORD +219 -155
  217. {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.1.dist-info}/LICENSE +0 -0
  218. {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.1.dist-info}/WHEEL +0 -0
  219. {prowler_cloud-5.17.1.dist-info → prowler_cloud-5.18.1.dist-info}/entry_points.txt +0 -0
@@ -14,6 +14,7 @@ from prowler.lib.utils.utils import print_boxes
14
14
  from prowler.providers.cloudflare.exceptions.exceptions import (
15
15
  CloudflareCredentialsError,
16
16
  CloudflareIdentityError,
17
+ CloudflareInvalidAccountError,
17
18
  CloudflareSessionError,
18
19
  )
19
20
  from prowler.providers.cloudflare.lib.mutelist.mutelist import CloudflareMutelist
@@ -36,16 +37,21 @@ class CloudflareProvider(Provider):
36
37
  _fixer_config: dict
37
38
  _mutelist: CloudflareMutelist
38
39
  _filter_zones: set[str] | None
40
+ _filter_accounts: set[str] | None
39
41
  audit_metadata: Audit_Metadata
40
42
 
41
43
  def __init__(
42
44
  self,
43
45
  filter_zones: Iterable[str] | None = None,
46
+ filter_accounts: Iterable[str] | None = None,
44
47
  config_path: str = None,
45
48
  config_content: dict | None = None,
46
49
  fixer_config: dict = {},
47
50
  mutelist_path: str = None,
48
51
  mutelist_content: dict = None,
52
+ api_token: str = None,
53
+ api_key: str = None,
54
+ api_email: str = None,
49
55
  ):
50
56
  logger.info("Instantiating Cloudflare provider...")
51
57
 
@@ -58,7 +64,12 @@ class CloudflareProvider(Provider):
58
64
 
59
65
  max_retries = self._audit_config.get("max_retries", 2)
60
66
 
61
- self._session = CloudflareProvider.setup_session(max_retries=max_retries)
67
+ self._session = CloudflareProvider.setup_session(
68
+ max_retries=max_retries,
69
+ api_token=api_token,
70
+ api_key=api_key,
71
+ api_email=api_email,
72
+ )
62
73
 
63
74
  self._identity = CloudflareProvider.setup_identity(self._session)
64
75
 
@@ -74,6 +85,23 @@ class CloudflareProvider(Provider):
74
85
  # Store zone filter for filtering resources across services
75
86
  self._filter_zones = set(filter_zones) if filter_zones else None
76
87
 
88
+ # Store account filter and restrict audited_accounts accordingly
89
+ self._filter_accounts = set(filter_accounts) if filter_accounts else None
90
+ if self._filter_accounts:
91
+ discovered_account_ids = {account.id for account in self._identity.accounts}
92
+ invalid_accounts = self._filter_accounts - discovered_account_ids
93
+ if invalid_accounts:
94
+ invalid_str = ", ".join(sorted(invalid_accounts))
95
+ raise CloudflareInvalidAccountError(
96
+ file=os.path.basename(__file__),
97
+ message=f"Account IDs not found: {invalid_str}.",
98
+ )
99
+ self._identity.audited_accounts = [
100
+ account_id
101
+ for account_id in self._identity.audited_accounts
102
+ if account_id in self._filter_accounts
103
+ ]
104
+
77
105
  Provider.set_global_provider(self)
78
106
 
79
107
  @property
@@ -105,24 +133,38 @@ class CloudflareProvider(Provider):
105
133
  """Zone filter from --region argument to filter resources."""
106
134
  return self._filter_zones
107
135
 
136
+ @property
137
+ def filter_accounts(self) -> set[str] | None:
138
+ """Account filter from --account-id argument to restrict scanned accounts."""
139
+ return self._filter_accounts
140
+
108
141
  @property
109
142
  def accounts(self) -> list[CloudflareAccount]:
110
143
  return self._identity.accounts
111
144
 
112
145
  @staticmethod
113
- def setup_session(max_retries: int = 2) -> CloudflareSession:
146
+ def setup_session(
147
+ max_retries: int = 2,
148
+ api_token: str = None,
149
+ api_key: str = None,
150
+ api_email: str = None,
151
+ ) -> CloudflareSession:
114
152
  """Initialize Cloudflare SDK client.
115
153
 
116
- Credentials are read from environment variables:
154
+ Credentials can be provided as arguments or read from environment variables:
117
155
  - CLOUDFLARE_API_TOKEN (recommended)
118
156
  - CLOUDFLARE_API_KEY and CLOUDFLARE_API_EMAIL (legacy)
119
157
 
120
158
  Args:
121
159
  max_retries: Maximum number of retries for API requests (default is 2).
160
+ api_token: Cloudflare API token (optional, falls back to env var).
161
+ api_key: Cloudflare API key (optional, falls back to env var).
162
+ api_email: Cloudflare API email (optional, falls back to env var).
122
163
  """
123
- token = os.environ.get("CLOUDFLARE_API_TOKEN", "")
124
- key = os.environ.get("CLOUDFLARE_API_KEY", "")
125
- email = os.environ.get("CLOUDFLARE_API_EMAIL", "")
164
+ # Use provided credentials or fall back to environment variables
165
+ token = api_token or os.environ.get("CLOUDFLARE_API_TOKEN", "")
166
+ key = api_key or os.environ.get("CLOUDFLARE_API_KEY", "")
167
+ email = api_email or os.environ.get("CLOUDFLARE_API_EMAIL", "")
126
168
 
127
169
  # Warn if both auth methods are set, use API Token (recommended)
128
170
  if token and key and email:
@@ -248,21 +290,62 @@ class CloudflareProvider(Provider):
248
290
  if email:
249
291
  report_lines.append(f"Email: {Fore.YELLOW}{email}{Style.RESET_ALL}")
250
292
 
251
- # Accounts
252
- if self.accounts:
253
- accounts = ", ".join([account.id for account in self.accounts])
254
- report_lines.append(f"Accounts: {Fore.YELLOW}{accounts}{Style.RESET_ALL}")
293
+ # Audited accounts (only the ones that will actually be scanned)
294
+ audited_accounts = self.identity.audited_accounts
295
+ if audited_accounts:
296
+ account_names = {
297
+ account.id: account.name for account in self.identity.accounts
298
+ }
299
+ accounts_str = ", ".join(
300
+ (
301
+ f"{account_id} ({account_names[account_id]})"
302
+ if account_id in account_names and account_names[account_id]
303
+ else account_id
304
+ )
305
+ for account_id in audited_accounts
306
+ )
307
+ report_lines.append(
308
+ f"Audited Accounts: {Fore.YELLOW}{accounts_str}{Style.RESET_ALL}"
309
+ )
255
310
 
256
311
  print_boxes(report_lines, report_title)
257
312
 
258
- def test_connection(self) -> Connection:
313
+ @staticmethod
314
+ def test_connection(
315
+ api_token: str = None,
316
+ api_key: str = None,
317
+ api_email: str = None,
318
+ raise_on_exception: bool = True,
319
+ provider_id: str = None,
320
+ ) -> Connection:
321
+ """Test connection to Cloudflare.
322
+
323
+ Test the connection to Cloudflare using the provided credentials.
324
+
325
+ Args:
326
+ api_token: Cloudflare API token (optional, falls back to env var).
327
+ api_key: Cloudflare API key (optional, falls back to env var).
328
+ api_email: Cloudflare API email (optional, falls back to env var).
329
+ raise_on_exception: Flag indicating whether to raise an exception if the connection fails.
330
+ provider_id: The provider ID (Cloudflare account ID).
331
+
332
+ Returns:
333
+ Connection: Connection object with is_connected status.
334
+ """
259
335
  try:
260
- _ = self._session.client.user.get()
336
+ session = CloudflareProvider.setup_session(
337
+ api_token=api_token,
338
+ api_key=api_key,
339
+ api_email=api_email,
340
+ )
341
+ _ = session.client.user.get()
261
342
  return Connection(is_connected=True)
262
343
  except Exception as error:
263
344
  logger.error(
264
345
  f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
265
346
  )
347
+ if raise_on_exception:
348
+ raise error
266
349
  return Connection(is_connected=False, error=error)
267
350
 
268
351
  def validate_arguments(self) -> None:
@@ -5,6 +5,13 @@ def init_parser(self):
5
5
  )
6
6
 
7
7
  scope_group = cloudflare_parser.add_argument_group("Scope")
8
+ scope_group.add_argument(
9
+ "--account-id",
10
+ nargs="+",
11
+ default=None,
12
+ metavar="ACCOUNT_ID",
13
+ help="Filter scan to specific Cloudflare account IDs. Only zones belonging to these accounts will be scanned.",
14
+ )
8
15
  scope_group.add_argument(
9
16
  "--region",
10
17
  "--filter-region",
@@ -0,0 +1,36 @@
1
+ {
2
+ "Provider": "cloudflare",
3
+ "CheckID": "dns_record_cname_target_valid",
4
+ "CheckTitle": "DNS records pointing to hostnames have valid targets without takeover risk",
5
+ "CheckType": [],
6
+ "ServiceName": "dns",
7
+ "SubServiceName": "",
8
+ "ResourceIdTemplate": "",
9
+ "Severity": "high",
10
+ "ResourceType": "DNSRecord",
11
+ "ResourceGroup": "network",
12
+ "Description": "**Cloudflare DNS records** (CNAME, MX, NS, SRV) that point to hostnames are assessed for **dangling record** vulnerabilities by checking if the target domain resolves to a valid address, preventing **subdomain takeover**, **mail interception**, and **service hijacking** attacks.",
13
+ "Risk": "Dangling **DNS records** pointing to non-existent targets create multiple vulnerabilities.\n- **Confidentiality**: dangling CNAME/NS allows subdomain takeover; dangling MX allows mail interception\n- **Integrity**: attackers can impersonate your organization, intercept emails, or hijack services\n- **Availability**: legitimate services may be disrupted or redirected to attacker-controlled infrastructure",
14
+ "RelatedUrl": "",
15
+ "AdditionalURLs": [
16
+ "https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/"
17
+ ],
18
+ "Remediation": {
19
+ "Code": {
20
+ "CLI": "",
21
+ "NativeIaC": "",
22
+ "Other": "1. Log in to the Cloudflare dashboard and select your account and domain\n2. Go to DNS > Records\n3. Identify CNAME, MX, NS, or SRV records with dangling targets\n4. Either update the record to point to a valid target or delete the record\n5. If the target service was decommissioned, remove the DNS record",
23
+ "Terraform": ""
24
+ },
25
+ "Recommendation": {
26
+ "Text": "Remove or update **dangling DNS records** to prevent takeover and interception attacks.\n- Regularly audit DNS records when decommissioning services\n- Remove CNAME, MX, NS, and SRV records pointing to deprovisioned resources\n- Monitor for unauthorized changes to DNS records\n- Consider using DNS monitoring tools to detect dangling records",
27
+ "Url": "https://hub.prowler.com/checks/cloudflare/dns_record_cname_target_valid"
28
+ }
29
+ },
30
+ "Categories": [
31
+ "internet-exposed"
32
+ ],
33
+ "DependsOn": [],
34
+ "RelatedTo": [],
35
+ "Notes": "Subdomain takeover occurs when a CNAME or NS record points to a service that has been deprovisioned, allowing attackers to claim that service and control the subdomain. Similarly, dangling MX records can allow mail interception, and dangling SRV records can expose service discovery vulnerabilities."
36
+ }
@@ -0,0 +1,109 @@
1
+ import socket
2
+
3
+ from prowler.lib.check.models import Check, CheckReportCloudflare
4
+ from prowler.providers.cloudflare.services.dns.dns_client import dns_client
5
+
6
+ # Record types that point to hostnames and can be dangling:
7
+ # - CNAME: Alias to another hostname
8
+ # - MX: Mail server hostname (dangling = potential mail interception)
9
+ # - NS: Nameserver delegation (dangling = subdomain takeover)
10
+ # - SRV: Service location hostname
11
+ DANGLING_RISK_TYPES = {"CNAME", "MX", "NS", "SRV"}
12
+
13
+ # Risk descriptions for each record type
14
+ RISK_DESCRIPTIONS = {
15
+ "CNAME": "subdomain takeover risk",
16
+ "MX": "potential mail interception risk",
17
+ "NS": "subdomain delegation takeover risk",
18
+ "SRV": "service discovery vulnerability",
19
+ }
20
+
21
+
22
+ class dns_record_cname_target_valid(Check):
23
+ """Ensure that DNS records pointing to hostnames have valid, resolvable targets.
24
+
25
+ Dangling DNS records that point to non-existent or unresolvable targets pose
26
+ significant security risks. CNAME and NS records can lead to subdomain takeover,
27
+ MX records can allow mail interception, and SRV records can expose service
28
+ vulnerabilities. Attackers can claim orphaned target resources and serve
29
+ malicious content, intercept email, or hijack services under your domain.
30
+ """
31
+
32
+ def execute(self) -> list[CheckReportCloudflare]:
33
+ """Execute the dangling DNS record validation check.
34
+
35
+ Iterates through all DNS records that point to hostnames (CNAME, MX, NS, SRV)
36
+ and attempts to resolve their targets using DNS lookup. Records pointing to
37
+ unresolvable targets are flagged as potential security risks.
38
+
39
+ Returns:
40
+ A list of CheckReportCloudflare objects with PASS status if the
41
+ target resolves successfully, or FAIL status if the target
42
+ cannot be resolved (dangling record).
43
+ """
44
+ findings = []
45
+
46
+ for record in dns_client.records:
47
+ # Check record types that point to hostnames
48
+ if record.type not in DANGLING_RISK_TYPES:
49
+ continue
50
+
51
+ report = CheckReportCloudflare(
52
+ metadata=self.metadata(),
53
+ resource=record,
54
+ )
55
+
56
+ target = self._extract_target(record.type, record.content)
57
+ is_valid = self._check_target_resolves(target)
58
+ risk_desc = RISK_DESCRIPTIONS.get(record.type, "security risk")
59
+
60
+ if is_valid:
61
+ report.status = "PASS"
62
+ report.status_extended = f"{record.type} record {record.name} points to valid target {target}."
63
+ else:
64
+ report.status = "FAIL"
65
+ report.status_extended = (
66
+ f"{record.type} record {record.name} points to potentially dangling "
67
+ f"target {target} - {risk_desc}."
68
+ )
69
+ findings.append(report)
70
+
71
+ return findings
72
+
73
+ def _extract_target(self, record_type: str, content: str) -> str:
74
+ """Extract the target hostname from record content.
75
+
76
+ Different record types have different content formats:
77
+ - CNAME: hostname
78
+ - MX: priority hostname (e.g., "10 mail.example.com")
79
+ - NS: hostname
80
+ - SRV: Cloudflare returns "weight port hostname" (e.g., "5 80 sip.example.com")
81
+ """
82
+ if record_type == "MX":
83
+ # MX format: "priority hostname"
84
+ parts = content.split(None, 1)
85
+ return parts[1] if len(parts) > 1 else content
86
+ elif record_type == "SRV":
87
+ # SRV format from Cloudflare: "weight port hostname"
88
+ parts = content.split()
89
+ # Target is the last part (hostname)
90
+ return parts[-1] if parts else content
91
+ else:
92
+ # CNAME and NS are just hostnames
93
+ return content
94
+
95
+ def _check_target_resolves(self, target: str) -> bool:
96
+ """Check if target hostname resolves to a valid address."""
97
+ # Remove trailing dot if present
98
+ target = target.rstrip(".")
99
+
100
+ try:
101
+ # Attempt DNS resolution
102
+ socket.getaddrinfo(target, None, socket.AF_UNSPEC)
103
+ return True
104
+ except socket.gaierror:
105
+ # DNS resolution failed - potential dangling record
106
+ return False
107
+ except Exception:
108
+ # On any other error, assume valid to avoid false positives
109
+ return True
@@ -0,0 +1,36 @@
1
+ {
2
+ "Provider": "cloudflare",
3
+ "CheckID": "dns_record_no_internal_ip",
4
+ "CheckTitle": "DNS records do not expose internal IP addresses",
5
+ "CheckType": [],
6
+ "ServiceName": "dns",
7
+ "SubServiceName": "",
8
+ "ResourceIdTemplate": "",
9
+ "Severity": "high",
10
+ "ResourceType": "DNSRecord",
11
+ "ResourceGroup": "network",
12
+ "Description": "**Cloudflare DNS records** are assessed for **internal IP exposure** by checking if A or AAAA records point to private, loopback, or reserved IP addresses which could **leak internal network structure**.",
13
+ "Risk": "DNS records exposing **internal IP addresses** leak sensitive network information.\n- **Confidentiality**: reveals internal network topology and addressing schemes to attackers\n- **Integrity**: provides reconnaissance data for targeted attacks on internal infrastructure\n- **Availability**: internal IPs in public DNS may indicate misconfiguration affecting service routing",
14
+ "RelatedUrl": "",
15
+ "AdditionalURLs": [
16
+ "https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/"
17
+ ],
18
+ "Remediation": {
19
+ "Code": {
20
+ "CLI": "",
21
+ "NativeIaC": "",
22
+ "Other": "1. Log in to the Cloudflare dashboard and select your account and domain\n2. Go to DNS > Records\n3. Identify A/AAAA records pointing to internal IP addresses\n4. Update records to point to public IP addresses or remove if not needed\n5. Use split-horizon DNS if internal resolution is required",
23
+ "Terraform": ""
24
+ },
25
+ "Recommendation": {
26
+ "Text": "Remove **internal IP addresses** from public DNS records.\n- Use split-horizon DNS for internal service resolution\n- Ensure DNS records only contain publicly routable IP addresses\n- Review DNS records after network changes or migrations\n- Consider using Cloudflare Access for secure internal service access",
27
+ "Url": "https://hub.prowler.com/checks/cloudflare/dns_record_no_internal_ip"
28
+ }
29
+ },
30
+ "Categories": [
31
+ "internet-exposed"
32
+ ],
33
+ "DependsOn": [],
34
+ "RelatedTo": [],
35
+ "Notes": "Internal IP ranges include: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 (IPv4), fc00::/7 (IPv6 ULA), and loopback addresses. These should not appear in public DNS records."
36
+ }
@@ -0,0 +1,73 @@
1
+ import ipaddress
2
+
3
+ from prowler.lib.check.models import Check, CheckReportCloudflare
4
+ from prowler.providers.cloudflare.services.dns.dns_client import dns_client
5
+
6
+
7
+ class dns_record_no_internal_ip(Check):
8
+ """Ensure that DNS records do not expose internal or private IP addresses.
9
+
10
+ Public DNS records should only contain publicly routable IP addresses.
11
+ Exposing internal, private, loopback, or link-local addresses in DNS records
12
+ can leak information about internal network infrastructure, potentially
13
+ aiding attackers in reconnaissance and targeted attacks against internal
14
+ systems.
15
+ """
16
+
17
+ def execute(self) -> list[CheckReportCloudflare]:
18
+ """Execute the internal IP address exposure check.
19
+
20
+ Iterates through all A and AAAA DNS records and checks if they contain
21
+ private, loopback, link-local, or reserved IP addresses that should not
22
+ be exposed publicly.
23
+
24
+ Returns:
25
+ A list of CheckReportCloudflare objects with PASS status if the
26
+ record points to a public IP address, or FAIL status if it exposes
27
+ an internal IP address.
28
+ """
29
+ findings = []
30
+
31
+ for record in dns_client.records:
32
+ # Only check A and AAAA records
33
+ if record.type not in ("A", "AAAA"):
34
+ continue
35
+
36
+ report = CheckReportCloudflare(
37
+ metadata=self.metadata(),
38
+ resource=record,
39
+ )
40
+
41
+ is_internal = self._is_internal_ip(record.content)
42
+
43
+ if not is_internal:
44
+ report.status = "PASS"
45
+ report.status_extended = (
46
+ f"DNS record {record.name} ({record.type}) points to "
47
+ f"public IP address {record.content}."
48
+ )
49
+ else:
50
+ report.status = "FAIL"
51
+ report.status_extended = (
52
+ f"DNS record {record.name} ({record.type}) exposes "
53
+ f"internal IP address {record.content} - information disclosure risk."
54
+ )
55
+ findings.append(report)
56
+
57
+ return findings
58
+
59
+ def _is_internal_ip(self, ip_str: str) -> bool:
60
+ """Check if IP address is internal/private."""
61
+ try:
62
+ ip = ipaddress.ip_address(ip_str)
63
+ # Check for private, loopback, link-local, or reserved addresses
64
+ return (
65
+ ip.is_private
66
+ or ip.is_loopback
67
+ or ip.is_link_local
68
+ or ip.is_reserved
69
+ or ip.is_unspecified
70
+ )
71
+ except ValueError:
72
+ # Invalid IP format, assume not internal
73
+ return False
@@ -0,0 +1,36 @@
1
+ {
2
+ "Provider": "cloudflare",
3
+ "CheckID": "dns_record_no_wildcard",
4
+ "CheckTitle": "DNS records do not use wildcard entries",
5
+ "CheckType": [],
6
+ "ServiceName": "dns",
7
+ "SubServiceName": "",
8
+ "ResourceIdTemplate": "",
9
+ "Severity": "medium",
10
+ "ResourceType": "DNSRecord",
11
+ "ResourceGroup": "network",
12
+ "Description": "**Cloudflare DNS records** are assessed for **wildcard usage** by checking if A, AAAA, CNAME, MX, or SRV records use wildcard entries (*.example.com) which can **increase attack surface**, expose unintended services, or allow mail interception.",
13
+ "Risk": "**Wildcard DNS records** can expose unintended services and increase attack surface.\n- **Confidentiality**: any subdomain resolves, potentially exposing internal naming conventions; wildcard MX allows mail interception\n- **Integrity**: attackers can access unintended services via arbitrary subdomains\n- **Availability**: wildcard records may route traffic or services not designed for public access",
14
+ "RelatedUrl": "",
15
+ "AdditionalURLs": [
16
+ "https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/"
17
+ ],
18
+ "Remediation": {
19
+ "Code": {
20
+ "CLI": "",
21
+ "NativeIaC": "",
22
+ "Other": "1. Log in to the Cloudflare dashboard and select your account and domain\n2. Go to DNS > Records\n3. Identify wildcard DNS records (starting with *.)\n4. Evaluate if the wildcard is necessary for your use case\n5. Replace wildcard records with specific subdomain records where possible",
23
+ "Terraform": ""
24
+ },
25
+ "Recommendation": {
26
+ "Text": "Avoid using **wildcard DNS records** unless absolutely necessary.\n- Use specific subdomain records instead of wildcards\n- If wildcards are required, ensure the target service handles unknown subdomains securely\n- Document the business justification for any wildcard records\n- Combine with proper web server configuration to reject unknown hosts",
27
+ "Url": "https://hub.prowler.com/checks/cloudflare/dns_record_no_wildcard"
28
+ }
29
+ },
30
+ "Categories": [
31
+ "internet-exposed"
32
+ ],
33
+ "DependsOn": [],
34
+ "RelatedTo": [],
35
+ "Notes": "Wildcard DNS records (*.example.com) cause any subdomain query to resolve. While useful for some applications, they can expose services unintentionally and make subdomain enumeration easier for attackers. Wildcard MX records can accept mail for any subdomain, and wildcard SRV records can expose services on arbitrary subdomains."
36
+ }
@@ -0,0 +1,60 @@
1
+ from prowler.lib.check.models import Check, CheckReportCloudflare
2
+ from prowler.providers.cloudflare.services.dns.dns_client import dns_client
3
+
4
+ # Record types where wildcards pose security risks:
5
+ # - A, AAAA: Wildcard resolves any subdomain to an IP, exposing services
6
+ # - CNAME: Wildcard aliases any subdomain, potential for subdomain takeover
7
+ # - MX: Wildcard accepts mail for any subdomain, potential mail interception
8
+ # - SRV: Wildcard exposes services on any subdomain
9
+ WILDCARD_RISK_TYPES = {"A", "AAAA", "CNAME", "MX", "SRV"}
10
+
11
+
12
+ class dns_record_no_wildcard(Check):
13
+ """Ensure that wildcard DNS records are not configured for the zone.
14
+
15
+ Wildcard DNS records (*.domain.com) match any subdomain that doesn't have
16
+ an explicit record, which can unintentionally expose services or create
17
+ security risks. Attackers may discover hidden services, and wildcard
18
+ certificates combined with wildcard DNS can increase the attack surface
19
+ for subdomain takeover vulnerabilities. Wildcard MX records can allow
20
+ mail interception for arbitrary subdomains.
21
+ """
22
+
23
+ def execute(self) -> list[CheckReportCloudflare]:
24
+ """Execute the wildcard DNS record check.
25
+
26
+ Iterates through all security-relevant DNS records (A, AAAA, CNAME, MX, SRV)
27
+ and identifies those configured as wildcard records (starting with *.).
28
+ Wildcard records may expose unintended services or create security risks.
29
+
30
+ Returns:
31
+ A list of CheckReportCloudflare objects with PASS status if the
32
+ record is not a wildcard, or FAIL status if it is a wildcard record.
33
+ """
34
+ findings = []
35
+
36
+ for record in dns_client.records:
37
+ # Check record types where wildcards pose security risks
38
+ if record.type not in WILDCARD_RISK_TYPES:
39
+ continue
40
+
41
+ report = CheckReportCloudflare(
42
+ metadata=self.metadata(),
43
+ resource=record,
44
+ )
45
+
46
+ # Check if record name starts with wildcard
47
+ is_wildcard = record.name.startswith("*.")
48
+
49
+ if not is_wildcard:
50
+ report.status = "PASS"
51
+ report.status_extended = f"DNS record {record.name} ({record.type}) is not a wildcard record."
52
+ else:
53
+ report.status = "FAIL"
54
+ report.status_extended = (
55
+ f"DNS record {record.name} ({record.type}) is a wildcard record - "
56
+ f"may expose unintended services."
57
+ )
58
+ findings.append(report)
59
+
60
+ return findings
@@ -0,0 +1,36 @@
1
+ {
2
+ "Provider": "cloudflare",
3
+ "CheckID": "dns_record_proxied",
4
+ "CheckTitle": "Cloudflare proxy is enabled for applicable DNS records",
5
+ "CheckType": [],
6
+ "ServiceName": "dns",
7
+ "SubServiceName": "",
8
+ "ResourceIdTemplate": "",
9
+ "Severity": "medium",
10
+ "ResourceType": "DNSRecord",
11
+ "ResourceGroup": "network",
12
+ "Description": "**Cloudflare DNS records** are assessed for **proxy configuration** by checking if A, AAAA, and CNAME records are proxied through Cloudflare to benefit from **DDoS protection**, **WAF**, and **caching** capabilities.",
13
+ "Risk": "Unproxied **DNS records** expose origin server IP addresses directly to the internet.\n- **Confidentiality**: origin IP exposure enables targeted reconnaissance and attacks\n- **Integrity**: direct access to origin bypasses WAF and security controls\n- **Availability**: origin is exposed to DDoS attacks without Cloudflare protection",
14
+ "RelatedUrl": "",
15
+ "AdditionalURLs": [
16
+ "https://developers.cloudflare.com/dns/manage-dns-records/reference/proxied-dns-records/"
17
+ ],
18
+ "Remediation": {
19
+ "Code": {
20
+ "CLI": "",
21
+ "NativeIaC": "",
22
+ "Other": "1. Log in to the Cloudflare dashboard and select your account and domain\n2. Go to DNS > Records\n3. For each A, AAAA, or CNAME record that should be protected\n4. Click Edit and toggle Proxy status to Proxied (orange cloud)\n5. Save the changes and verify traffic flows through Cloudflare",
23
+ "Terraform": "```hcl\n# Enable Cloudflare proxy for DNS records\nresource \"cloudflare_record\" \"proxied_record\" {\n zone_id = \"<ZONE_ID>\"\n name = \"www\"\n content = \"192.0.2.1\"\n type = \"A\"\n proxied = true # Critical: enables DDoS protection, WAF, and caching\n}\n```"
24
+ },
25
+ "Recommendation": {
26
+ "Text": "Enable the **Cloudflare proxy** (orange cloud) for DNS records that should be protected.\n- Proxied records benefit from DDoS protection, WAF, and caching\n- Origin server IP addresses are hidden from public DNS queries\n- Apply defense in depth by combining proxy protection with origin hardening\n- Some record types (MX, TXT) cannot be proxied by design",
27
+ "Url": "https://hub.prowler.com/checks/cloudflare/dns_record_proxied"
28
+ }
29
+ },
30
+ "Categories": [
31
+ "internet-exposed"
32
+ ],
33
+ "DependsOn": [],
34
+ "RelatedTo": [],
35
+ "Notes": "Only A, AAAA, and CNAME records can be proxied. MX, TXT, and other record types are always DNS-only. Some services may require DNS-only mode for specific use cases."
36
+ }
@@ -0,0 +1,49 @@
1
+ from prowler.lib.check.models import Check, CheckReportCloudflare
2
+ from prowler.providers.cloudflare.services.dns.dns_client import dns_client
3
+
4
+ PROXYABLE_TYPES = {"A", "AAAA", "CNAME"}
5
+
6
+
7
+ class dns_record_proxied(Check):
8
+ """Ensure that DNS records are proxied through Cloudflare.
9
+
10
+ Proxying DNS records through Cloudflare hides the origin server's IP address
11
+ and provides DDoS protection, WAF capabilities, and performance optimizations.
12
+ Non-proxied (DNS-only) records expose the origin IP directly, bypassing
13
+ Cloudflare's security features and making the origin vulnerable to direct
14
+ attacks.
15
+ """
16
+
17
+ def execute(self) -> list[CheckReportCloudflare]:
18
+ """Execute the DNS record proxy status check.
19
+
20
+ Iterates through all proxyable DNS records (A, AAAA, CNAME) and verifies
21
+ that they are configured to be proxied through Cloudflare. Non-proxied
22
+ records bypass Cloudflare's security and performance features.
23
+
24
+ Returns:
25
+ A list of CheckReportCloudflare objects with PASS status if the
26
+ record is proxied through Cloudflare, or FAIL status if it is
27
+ DNS-only (not proxied).
28
+ """
29
+ findings = []
30
+
31
+ for record in dns_client.records:
32
+ # Only check proxyable record types
33
+ if record.type not in PROXYABLE_TYPES:
34
+ continue
35
+
36
+ report = CheckReportCloudflare(
37
+ metadata=self.metadata(),
38
+ resource=record,
39
+ )
40
+
41
+ if record.proxied:
42
+ report.status = "PASS"
43
+ report.status_extended = f"DNS record {record.name} ({record.type}) is proxied through Cloudflare."
44
+ else:
45
+ report.status = "FAIL"
46
+ report.status_extended = f"DNS record {record.name} ({record.type}) is not proxied through Cloudflare."
47
+ findings.append(report)
48
+
49
+ return findings