Skip to content
Security
Skill

/prowler-sdk-check

Creates and updates Prowler SDK security checks (implementation, metadata, fixers, configurable checks). Trigger: When creating or updating a Prowler SDK security check or its metadata.json for any provider (AWS, Azure, GCP, Kubernetes, GitHub, M365, etc.), adding a check fixer,

From plugin
prowler
15k39 skills1 MCP

Claude Code

$ npx -y skills add prowler-cloud/prowler --skill prowler-sdk-check --agent claude-code

SKILL.md

prowler-sdk-check.SKILL.md
name: prowler-sdk-check
description: >
  Creates and updates Prowler SDK security checks (implementation, metadata, fixers, configurable checks).
  Trigger: When creating or updating a Prowler SDK security check or its metadata.json for any provider (AWS, Azure, GCP, Kubernetes, GitHub, M365, etc.), adding a check fixer, or making a check configurable via audit_config.
license: Apache-2.0
metadata:
  author: prowler-cloud
  version: "1.1"
  scope: [root, sdk]
  auto_invoke:
    - "Creating new checks"
    - "Updating existing checks and metadata"
allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task

Check Structure

prowler/providers/{provider}/services/{service}/{check_name}/
├── __init__.py
├── {check_name}.py               # class {check_name}(Check)
├── {check_name}.metadata.json
└── {check_name}_fixer.py         # optional, see Fixers

Naming: `{service}_{resource}_{security_control}` (e.g. `s3_bucket_object_versioning`). Tests go in `tests/providers/{provider}/services/{service}/{check_name}/{check_name}_test.py` (see `prowler-test-sdk`).

Hard Rules (enforced in code)

`Check.__init__` and `CheckMetadata` (`prowler/lib/check/models.py`) reject the check at load time if any of these fail:

| Rule | Enforced by | |------|-------------| | `CheckID` == class name == file name (without `.py`) | `Check.__init__` | | `CheckID` has no `-` | `valid_check_id` | | `ServiceName` == `CheckID.split("_")[0]` and lowercase (so the AWS Lambda service is `awslambda`) | `validate_service_name` | | `CheckTitle` <= 150 chars and does not start with `Ensure` | `validate_check_title` | | `Description` and `Risk` <= 400 chars each | `validate_description`, `validate_risk` | | `CheckType` is `[]` for every provider except AWS; AWS values must be paths in `prowler/providers/aws/config/check_types.json` | `validate_check_type` | | `RelatedUrl` is `""` (deprecated, use `AdditionalURLs`) | `validate_related_url` | | `Remediation.Recommendation.Url` is empty or starts with `https://hub.prowler.com/` (use `https://hub.prowler.com/check/{check_id}`) | `validate_recommendation_url` | | `Remediation.Code.CLI` is not a URL | `valid_cli_command` | | `ResourceType` non-empty | `valid_resource_type` | | `ResourceGroup` in `VALID_RESOURCE_GROUPS` (or `""`) | `validate_resource_group` | | Every `Categories` item in `VALID_CATEGORIES` | `valid_category` | | `AdditionalURLs` has no empty or duplicate items | `validate_additional_urls` | | `Severity` in `critical`, `high`, `medium`, `low`, `informational` | `Severity` enum |

Tool-wrapper providers (`iac`, `llm`, `image`, or plug-ins with `is_external_tool_provider = True`) skip most of these.

Validate a metadata file without running a scan:

uv run python -c "import sys; from prowler.lib.check.models import CheckMetadata; CheckMetadata.parse_file(sys.argv[1]); print('OK')" prowler/providers/{provider}/services/{service}/{check_name}/{check_name}.metadata.json

Check Implementation

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.s3.s3_client import s3_client


class s3_bucket_object_versioning(Check):
    """S3 buckets have object versioning enabled."""

    def execute(self) -> list[Check_Report_AWS]:
        findings = []
        for bucket in s3_client.buckets.values():
            report = Check_Report_AWS(metadata=self.metadata(), resource=bucket)
            if not bucket.versioning_retrieved:
                report.status = "MANUAL"
                report.status_extended = f"Cannot evaluate versioning for S3 Bucket {bucket.name}: the versioning configuration could not be retrieved. Verify that the scanning credentials are allowed to call s3:GetBucketVersioning."
            elif bucket.versioning:
                report.status = "PASS"
                report.status_extended = f"S3 Bucket {bucket.name} has versioning enabled."
            else:
                report.status = "FAIL"
                report.status_extended = f"S3 Bucket {bucket.name} has versioning disabled."
            findings.append(report)
        return findings
  • Only use the service client (`{service}_client`); never call the provider SDK from a check. If data is missing, extend the service (see `prowler-provider`).
  • `execute()` returns a list (empty if there are no resources), one report per audited resource.
  • `status_extended` must end with a period and identify the resource.
  • `resource=` accepts a dict, a Pydantic model, a dataclass or an object with `to_dict()`; anything else becomes `{}` and logs an error.
  • Severity can be adjusted per finding with `report.check_metadata.Severity = "..."` when the risk depends on the scenario.
  • Secret-scanning checks use a dedicated batched structure: read `docs/developer-guide/secret-scanning-checks.mdx` first.

Report Class per Provider (`prowler/lib/check/models.py`)

| Provider | Class | Fields set from `resource` | |----------|-------|----------------------------| | aws | `Check_Report_AWS` | `resource_id` (`id` or `name`), `resource_arn`, `region` | | azure | `Check_Report_Azure` | `resource_name`, `resource_id`, `location`; set `report.subscription` yourself | | gcp | `Check_Report_GCP` | `resource_id`, `resource_name`, `project_id`, `location`; also accepts `location=`, `resource_name=`, `resource_id=`, `project_id=` kwargs | | kubernetes | `Check_Report_Kubernetes` | `resource_id` (`uid`), `resource_name`, `namespace` | | oraclecloud | `Check_Report_OCI` | `resource_id`, `resource_name`, `compartment_id`, `region` | | all others | `CheckReport<Name>` (e.g. `CheckReportGithub`, `CheckReportM365`, `CheckReportStackIT`, `CheckReportMongoDBAtlas`, `CheckReportAlibabaCloud`) | grep `^class CheckReport` in `models.py` for the exact name and constructor kwargs |

Statuses

| Status | When | |--------|------| | `PASS` | Resource is compliant | | `FAIL` | An insecure condition was actually detected | | `MANUAL` | H

Read more
@prowler-cloud
Ships withprowler

Prowler is the world’s most widely used Open-Source Cloud Security Platform that automates security and compliance across any cloud environment.

15k39 skills1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
15.2k
Star history of prowler-cloud/prowler on GitHub, a chart by star-history.com

Other skills on prowler.

ai-sdk-5

ai-sdk-5

Vercel AI SDK patterns for the installed major (ui/package.json: `ai` 6.x, `@ai-sdk/react` 3.x). The skill name is historical;…

django-drf

django-drf

Django REST Framework patterns. Trigger: When implementing generic DRF APIs (ViewSets, serializers, routers, permissions,…

gh-aw

gh-aw

Create and maintain GitHub Agentic Workflows (gh-aw) for Prowler. Trigger: When creating agentic workflows, modifying gh-aw…

jsonapi

jsonapi

Strict JSON:API v1.1 specification compliance. Trigger: When creating or modifying API endpoints, reviewing API responses, or…

More skills from other plugins.

api-security

api-security

Use for authorized security assessment of REST, GraphQL, WebSocket, or SOAP APIs, including discovery, authentication,…

@zhaoxuya520@zhaoxuya520Install Skill
nemoclaw-user-guide

nemoclaw-user-guide

Find official NemoClaw documentation for installation, configuration, operation, or troubleshooting. Also handles requested docs…

nemoclaw10d23k
@nvidia@nvidiaInstall Skill

Questions about prowler-sdk-check.

Which coding agents can use prowler-sdk-check?
prowler-sdk-check installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.