smithery/prowler-cloud

prowler-sdk-check

Creates Prowler security checks following SDK architecture patterns.

Installation

$ npx skills add smithery/prowler-cloud --skill prowler-sdk-check

Also in this package

Other skills from smithery/prowler-cloud · top by installs.

npx skills add smithery/prowler-cloud

Browse all from smithery/prowler-cloud

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0
LicenseApache-2.0
Allowed toolsRead, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task
More metadata
author
prowler-cloud
version
1.0
scope
["root","sdk"]
auto_invoke
["Creating new checks","Updating existing checks and metadata"]

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 9,657 B
  • docs SUMMARY.md 240 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Check Structure

prowler/providers/{provider}/services/{service}/{check_name}/
├── __init__.py
├── {check_name}.py
└── {check_name}.metadata.json

Step-by-Step Creation Process

1. Prerequisites

  • Verify check doesn't exist: Search prowler/providers/{provider}/services/{service}/
  • Ensure provider and service exist - create them first if not
  • Confirm service has required methods - may need to add/modify service methods to get data

2. Create Check Files

mkdir -p prowler/providers/{provider}/services/{service}/{check_name}
touch prowler/providers/{provider}/services/{service}/{check_name}/__init__.py
touch prowler/providers/{provider}/services/{service}/{check_name}/{check_name}.py
touch prowler/providers/{provider}/services/{service}/{check_name}/{check_name}.metadata.json

3. Implement Check Logic

from prowler.lib.check.models import Check, Check_Report_{Provider}
from prowler.providers.{provider}.services.{service}.{service}_client import {service}_client

class {check_name}(Check):
    """Ensure that {resource} meets {security_requirement}."""
    def execute(self) -> list[Check_Report_{Provider}]:
        """Execute the check logic.

        Returns:
            A list of reports containing the result of the check.
        """
        findings = []
        for resource in {service}_client.{resources}:
            report = Check_Report_{Provider}(metadata=self.metadata(), resource=resource)
            report.status = "PASS" if resource.is_compliant else "FAIL"
            report.status_extended = f"Resource {resource.name} compliance status."
            findings.append(report)
        return findings

4. Create Metadata File

See complete schema below and assets/ folder for complete templates. For detailed field documentation, see references/metadata-docs.md.

5. Verify Check Detection

uv run python prowler-cli.py {provider} --list-checks | grep {check_name}

6. Run Check Locally

uv run python prowler-cli.py {provider} --log-level ERROR --verbose --check {check_name}

7. Create Tests

See prowler-test-sdk skill for test patterns (PASS, FAIL, no resources, error handling).


Check Naming Convention

{service}_{resource}_{security_control}

Examples:

  • ec2instancepublicipdisabled
  • s3bucketencryption_enabled
  • iamusermfa_enabled

Metadata Schema (COMPLETE)

{
  "Provider": "aws",
  "CheckID": "{check_name}",
  "CheckTitle": "Human-readable title",
  "CheckType": [
    "Software and Configuration Checks/AWS Security Best Practices",
    "Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices"
  ],
  "ServiceName": "{service}",
  "SubServiceName": "",
  "ResourceIdTemplate": "",
  "Severity": "low|medium|high|critical",
  "ResourceType": "AwsEc2Instance|Other",
  "ResourceGroup": "security|compute|storage|network",
  "Description": "**Bold resource name**. Detailed explanation of what this check evaluates and why it matters.",
  "Risk": "What happens if non-compliant. Explain attack vectors, data exposure risks, compliance impact.",
  "RelatedUrl": "",
  "AdditionalURLs": [
    "https://docs.aws.amazon.com/..."
  ],
  "Remediation": {
    "Code": {
      "CLI": "aws {service} {command} --option value",
      "NativeIaC": "```yaml\nResources:\n  Resource:\n    Type: AWS::{Service}::{Resource}\n    Properties:\n      Key: value  # This line fixes the issue\n```",
      "Other": "1. Console steps\n2. Step by step",
      "Terraform": "```hcl\nresource \"aws_{service}_{resource}\" \"example\" {\n  key = \"value\"  # This line fixes the issue\n}\n```"
    },
    "Recommendation": {
      "Text": "Detailed recommendation for remediation.",
      "Url": "https://hub.prowler.com/check/{check_name}"
    }
  },
  "Categories": [
    "identity-access",
    "encryption",
    "logging",
    "forensics-ready",
    "internet-exposed",
    "trust-boundaries"
  ],
  "DependsOn": [],
  "RelatedTo": [],
  "Notes": ""
}

Required Fields

Field Description
Provider Provider name: aws, azure, gcp, kubernetes, github, m365
CheckID Must match class name and folder name
CheckTitle Human-readable title
Severity low, medium, high, critical
ServiceName Service being checked
Description What the check evaluates
Risk Security impact of non-compliance
Remediation.Code.CLI CLI fix command
Remediation.Recommendation.Text How to fix

Severity Guidelines

Severity When to Use
critical Direct data exposure, RCE, privilege escalation
high Significant security risk, compliance violation
medium Defense-in-depth, best practice
low Informational, minor hardening

Check Report Statuses

Status When to Use
PASS Resource is compliant
FAIL Resource is non-compliant
MANUAL Requires human verification, or the data needed to evaluate the resource could not be retrieved

Permission / availability errors are NOT findings

Never set FAIL because an API call failed (missing permission or scope, API not enabled, feature not licensed, data unavailable). That is a scan-configuration problem, not a security issue, and it surfaces as a misleading high-severity finding.

  • Service: log the error and expose it distinctly from an empty result (None instead of [], an error attribute, or a lookup_failed set). Only treat real access errors this way; a 404/not-found usually means "not configured" and IS a legitimate FAIL, and a definitively disabled API is a legitimate FAIL when the API's activation is itself the audited control (e.g. GCP Access Approval).
  • Check: emit ONE tenant/account/project/subscription-level MANUAL finding (not one per resource) whose status_extended says the check cannot be evaluated and names the required permission/API/license.
  • Do not touch report.check_metadata.Severity to hide it.
if <service>_client.<data> is None:
    report = CheckReport<Provider>(metadata=self.metadata(), resource={})
    report.resource_name = "<Tenant-level resource>"
    report.resource_id = "<stable-id>"
    report.status = "MANUAL"
    report.status_extended = "Cannot evaluate <requirement>: <data> could not be retrieved. Verify that <permission> is granted to the scanning identity."
    return [report]

Common Patterns

AWS Check with Regional Resources

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

class s3_bucket_encryption_enabled(Check):
    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 bucket.encryption:
                report.status = "PASS"
                report.status_extended = f"S3 bucket {bucket.name} has encryption enabled."
            else:
                report.status = "FAIL"
                report.status_extended = f"S3 bucket {bucket.name} does not have encryption enabled."
            findings.append(report)
        return findings

Check with Multiple Conditions

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.ec2.ec2_client import ec2_client

class ec2_instance_hardened(Check):
    def execute(self) -> list[Check_Report_AWS]:
        findings = []
        for instance in ec2_client.instances:
            report = Check_Report_AWS(metadata=self.metadata(), resource=instance)

            issues = []
            if instance.public_ip:
                issues.append("has public IP")
            if not instance.metadata_options.http_tokens == "required":
                issues.append("IMDSv2 not enforced")

            if issues:
                report.status = "FAIL"
                report.status_extended = f"Instance {instance.id} {', '.join(issues)}."
            else:
                report.status = "PASS"
                report.status_extended = f"Instance {instance.id} is properly hardened."

            findings.append(report)
        return findings

Commands

# Verify detection
uv run python prowler-cli.py {provider} --list-checks | grep {check_name}

# Run check
uv run python prowler-cli.py {provider} --log-level ERROR --verbose --check {check_name}

# Run with specific profile/credentials
uv run python prowler-cli.py aws --profile myprofile --check {check_name}

# Run multiple checks
uv run python prowler-cli.py {provider} --check {check1} {check2} {check3}

Resources

  • Templates: See [assets/](assets/) for complete check and metadata templates (AWS, Azure, GCP)
  • Documentation: See [references/metadata-docs.md](references/metadata-docs.md) for official Prowler Developer Guide links