Token导航 LogoToken导航TokenDH.com
研究检索需要联网github未标认证来源可访问许可证需确认审计异常

prowler-attack-paths-queryprowler 攻击路径查询

Agent Skill

prowler-attack-paths-query 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

1,042

周安装

43

GitHub Stars

13,685

下载量

341
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:prowler-attack-paths-query(prowler 攻击路径查询)
来源仓库:https://github.com/prowler-cloud/prowler
仓库路径:skills/prowler-attack-paths-query
安装命令:
npx skills add https://github.com/prowler-cloud/prowler --skill prowler-attack-paths-query
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/prowler-cloud/prowler --skill prowler-attack-paths-query

简介

prowler-attack-paths-query 用于查找、检索和筛选相关信息。

  • 适合在 Codex、Claude、Cursor、Gemini CLI 中根据关键词或任务场景快速定位候选结果。
  • 通过 npx skills add 命令从指定仓库安装,需结合原始 README 核验具体用法。
  • 安装前建议确认权限范围、维护状态及是否会触发联网、命令执行或文件读写。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

Overview

Attack Paths queries are openCypher queries that analyze cloud infrastructure graphs (ingested via Cartography) to detect security risks like privilege escalation paths, network exposure, and misconfigurations.

Queries are written in openCypher Version 9 for compatibility with both Neo4j and Amazon Neptune.


Two query audiences

This skill covers two types of queries with different isolation mechanisms:

Predefined queriesCustom queries
Where they liveapi/src/backend/api/attack_paths/queries/{provider}.pyUser/LLM-supplied via the custom query API endpoint
Provider isolationAWSAccount {id: $provider_uid} anchor + path connectivityAutomatic _Provider_{uuid} label injection via cypher_sanitizer.py
What to writeChain every MATCH from the aws variablePlain Cypher, no isolation boilerplate needed
Internal labelsNever use (_ProviderResource, _Tenant_*, _Provider_*)Never use (injected automatically by the system)

For predefined queries: every node must be reachable from the AWSAccount root via graph traversal. This is the isolation boundary.

For custom queries: write natural Cypher without isolation concerns. The query runner injects a _Provider_{uuid} label into every node pattern before execution, and a post-query filter catches edge cases.


Input Sources

Queries can be created from:

  1. pathfinding.cloud ID (e.g., ECS-001, GLUE-001) # Fetch a single path by ID curl -s https://raw.githubusercontent.com/DataDog/pathfinding.cloud/main/docs/paths.json \ | jq '.[] | select(.id == "ecs-002")' # List all path IDs and names curl -s https://raw.githubusercontent.com/DataDog/pathfinding.cloud/main/docs/paths.json \ | jq -r '.[] | "\(.id): \(.name)"' # Filter by service prefix curl -s https://raw.githubusercontent.com/DataDog/pathfinding.cloud/main/docs/paths.json \ | jq -r '.[] | select(.id | startswith("ecs")) | "\(.id): \(.name)"' If jq is not available, use python3 -c "import json,sys;..." as a fallback.

- Reference: https://github.com/DataDog/pathfinding.cloud - The aggregated paths.json is too large for WebFetch. Use Bash:

  1. Natural language description from the user

Query Structure

Provider scoping parameter

One parameter is injected automatically by the query runner:

ParameterProperty it matchesUsed onPurpose
$provider_uididAWSAccountScopes to a specific AWS account

All other nodes are isolated by path connectivity from the AWSAccount anchor.

Imports

All query files start with these imports:

from api.attack_paths.queries.types import (
    AttackPathsQueryAttribution,
    AttackPathsQueryDefinition,
    AttackPathsQueryParameterDefinition,
)
from tasks.jobs.attack_paths.config import PROWLER_FINDING_LABEL

The PROWLER_FINDING_LABEL constant (value: "ProwlerFinding") is used via f-string interpolation in all queries. Never hardcode the label string.

Privilege escalation sub-patterns

There are four distinct privilege escalation patterns. Choose based on the attack type:

Sub-patternTargetpath_target shapeExample
Self-escalationPrincipal's own policies(aws)--(target_policy:AWSPolicy)--(principal)IAM-001
Lateral to userOther IAM users(aws)--(target_user:AWSUser)IAM-002
Assume-role lateralAssumable roles(aws)--(target_role:AWSRole)<-[:STS_ASSUMEROLE_ALLOW]-(principal)IAM-014
PassRole + serviceService-trusting roles(aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(...)EC2-001

Self-escalation (e.g., IAM-001)

The principal modifies resources attached to itself. path_target loops back to principal:

AWS_{QUERY_NAME} = AttackPathsQueryDefinition(
    id="aws-{kebab-case-name}",
    name="{Human-friendly label} ({REFERENCE_ID})",
    short_description="{Brief explanation, no technical permissions.}",
    description="{Detailed description of the attack vector and impact.}",
    attribution=AttackPathsQueryAttribution(
        text="pathfinding.cloud - {REFERENCE_ID} - {permission}",
        link="https://pathfinding.cloud/paths/{reference_id_lowercase}",
    ),
    provider="aws",
    cypher=f"""
        // Find principals with {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) = '{permission_lowercase}'
                OR toLower(action) = '{service}:*'
                OR action = '*'
            )

        // Find target resources attached to the same principal
        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
            )

        WITH collect(path_principal) + collect(path_target) AS paths
        UNWIND paths AS p
        UNWIND nodes(p) AS n

        WITH paths, collect(DISTINCT n) AS unique_nodes
        UNWIND unique_nodes AS n
        OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL'}})

        RETURN paths, collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr
    """,
    parameters=[],
)

Other sub-pattern path_target shapes

The other 3 sub-patterns share the same path_principal, deduplication tail, and RETURN as self-escalation. Only the path_target MATCH differs:

// Lateral to user (e.g., IAM-002) - targets other IAM users
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)

// Assume-role lateral (e.g., IAM-014) - targets roles the principal can assume
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)

// PassRole + service (e.g., EC2-001) - targets roles trusting a service
MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {arn: '{service}.amazonaws.com'})
WHERE any(resource IN stmt.resource WHERE resource = '*' OR target_role.arn CONTAINS resource OR resource CONTAINS target_role.name)

Multi-permission: PassRole queries require a second permission. Add MATCH (principal)--(policy2:AWSPolicy)--(stmt2:AWSPolicyStatement) with its own WHERE before path_target, then check BOTH stmt.resource AND stmt2.resource against the target. See IAM-015 or EC2-001 in aws.py for examples.

Network exposure pattern

The Internet node is reached via CAN_ACCESS through the already-scoped resource, not via a standalone lookup:

AWS_{QUERY_NAME} = AttackPathsQueryDefinition(
    id="aws-{kebab-case-name}",
    name="{Human-friendly label}",
    short_description="{Brief explanation.}",
    description="{Detailed description.}",
    provider="aws",
    cypher=f"""
        // Match exposed resources (MUST chain from `aws`)
        MATCH path = (aws:AWSAccount {{id: $provider_uid}})--(resource:EC2Instance)
        WHERE resource.exposed_internet = true

        // Internet node reached via path connectivity through the resource
        OPTIONAL MATCH (internet:Internet)-[can_access:CAN_ACCESS]->(resource)

        WITH collect(path) AS paths, head(collect(internet)) AS internet, collect(can_access) AS can_access
        UNWIND paths AS p
        UNWIND nodes(p) AS n

        WITH paths, internet, can_access, collect(DISTINCT n) AS unique_nodes
        UNWIND unique_nodes AS n
        OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL'}})

        RETURN paths, collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr,
            internet, can_access
    """,
    parameters=[],
)

Register in query list

Add to the {PROVIDER}_QUERIES list at the bottom of the file:

AWS_QUERIES: list[AttackPathsQueryDefinition] = [
    # ... existing queries ...
    AWS_{NEW_QUERY_NAME},  # Add here
]

Step-by-step creation process

1. Read the queries module

FIRST, read all files in the queries module to understand the structure, type definitions, registration, and existing style:

api/src/backend/api/attack_paths/queries/
├── __init__.py      # Module exports
├── types.py         # AttackPathsQueryDefinition, AttackPathsQueryParameterDefinition
├── registry.py      # Query registry logic
└── {provider}.py    # Provider-specific queries (e.g., aws.py)

DO NOT use generic templates. Match the exact style of existing queries in the file.

2. Fetch and consult the Cartography schema

This is the most important step. Every node label, property, and relationship in the query must exist in the Cartography schema for the pinned version. Do not guess or rely on memory.

Check api/pyproject.toml for the Cartography dependency, then fetch the schema:

grep cartography api/pyproject.toml

Build the schema URL (ALWAYS use the specific tag, not master/main):

# Git dependency (prowler-cloud/cartography@0.126.1):
https://raw.githubusercontent.com/prowler-cloud/cartography/refs/tags/0.126.1/docs/root/modules/{provider}/schema.md

# PyPI dependency (cartography = "^0.126.0"):
https://raw.githubusercontent.com/cartography-cncf/cartography/refs/tags/0.126.0/docs/root/modules/{provider}/schema.md

Read the schema to discover available node labels, properties, and relationships for the target resources. Internal labels (_ProviderResource, _AWSResource, _Tenant_*, _Provider_*) exist for isolation but should never appear in queries.

4. Create query definition

Use the appropriate pattern (privilege escalation or network exposure) with:

  • id: {provider}-{kebab-case-description}
  • name: Short, human-friendly label. For sourced queries, append the reference ID: "EC2 Instance Launch with Privileged Role (EC2-001)".
  • short_description: Brief explanation, no technical permissions.
  • description: Full technical explanation. Plain text only.
  • provider: Provider identifier (aws, azure, gcp, kubernetes, github)
  • cypher: The openCypher query with proper escaping
  • parameters: Optional list of user-provided parameters (parameters=[] if none)
  • attribution: Optional AttackPathsQueryAttribution(text, link) for sourced queries. The text includes source, reference ID, and permissions. The link uses a lowercase ID. Omit for non-sourced queries.

5. Add query to provider list

Add the constant to the {PROVIDER}_QUERIES list.


Query naming conventions

Query ID

{provider}-{category}-{description}

Examples: aws-ec2-privesc-passrole-iam, aws-ec2-instances-internet-exposed

Query constant name

{PROVIDER}_{CATEGORY}_{DESCRIPTION}

Examples: AWS_EC2_PRIVESC_PASSROLE_IAM, AWS_EC2_INSTANCES_INTERNET_EXPOSED


Query categories

CategoryDescriptionExample
Basic ResourceList resources with propertiesRDS instances, S3 buckets
Network ExposureInternet-exposed resourcesEC2 with public IPs
Privilege EscalationIAM privilege escalation pathsPassRole + RunInstances
Data AccessAccess to sensitive dataEC2 with S3 access

Common openCypher patterns

Match account and principal

MATCH path_principal = (aws:AWSAccount {id: $provider_uid})--(principal:AWSPrincipal)--(policy:AWSPolicy)--(stmt:AWSPolicyStatement)

Check IAM action permissions

WHERE stmt.effect = 'Allow'
    AND any(action IN stmt.action WHERE
        toLower(action) = 'iam:passrole'
        OR toLower(action) = 'iam:*'
        OR action = '*'
    )

Find roles trusting a service

MATCH path_target = (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal {arn: 'ec2.amazonaws.com'})

Find roles the principal can assume

Note the arrow direction - STS_ASSUMEROLE_ALLOW points from the role to the principal:

MATCH path_target = (aws)--(target_role:AWSRole)<-[:STS_ASSUMEROLE_ALLOW]-(principal)

Check resource scope

WHERE any(resource IN stmt.resource WHERE
    resource = '*'
    OR target_role.arn CONTAINS resource
    OR resource CONTAINS target_role.name
)

Internet node via path connectivity

The Internet node is reached through CAN_ACCESS relationships to already-scoped resources. No standalone lookup needed:

OPTIONAL MATCH (internet:Internet)-[can_access:CAN_ACCESS]->(resource)

Multi-label OR (match multiple resource types)

MATCH path = (aws:AWSAccount {id: $provider_uid})-[r]-(x)-[q]-(y)
WHERE (x:EC2PrivateIp AND x.public_ip = $ip)
   OR (x:EC2Instance AND x.publicipaddress = $ip)
   OR (x:NetworkInterface AND x.public_ip = $ip)
   OR (x:ElasticIPAddress AND x.public_ip = $ip)

Include Prowler findings

Deduplicate nodes before the ProwlerFinding lookup to avoid redundant OPTIONAL MATCH calls on nodes that appear in multiple paths:

WITH collect(path_principal) + collect(path_target) AS paths
UNWIND paths AS p
UNWIND nodes(p) AS n

WITH paths, collect(DISTINCT n) AS unique_nodes
UNWIND unique_nodes AS n
OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL'}})

RETURN paths, collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr

For network exposure queries, aggregate the internet node and relationship alongside paths:

WITH collect(path) AS paths, head(collect(internet)) AS internet, collect(can_access) AS can_access
UNWIND paths AS p
UNWIND nodes(p) AS n

WITH paths, internet, can_access, collect(DISTINCT n) AS unique_nodes
UNWIND unique_nodes AS n
OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL'}})

RETURN paths, collect(DISTINCT pf) as dpf, collect(DISTINCT pfr) as dpfr,
    internet, can_access

Prowler-specific labels and relationships

These are added by the sync task, not part of the Cartography schema. For all other node labels, properties, and relationships, always consult the Cartography schema (see step 2 below).

Label/RelationshipDescription
ProwlerFindingFinding node (status, severity, check_id)
InternetInternet sentinel node
CAN_ACCESSInternet-to-resource exposure (relationship)
HAS_FINDINGResource-to-finding link (relationship)
TRUSTS_AWS_PRINCIPALRole trust relationship
STS_ASSUMEROLE_ALLOWCan assume role (direction: role -> principal)

Parameters

For queries requiring user input:

parameters=[
    AttackPathsQueryParameterDefinition(
        name="ip",
        label="IP address",
        # data_type defaults to "string", cast defaults to str.
        # For non-string params, set both: data_type="integer", cast=int
        description="Public IP address, e.g. 192.0.2.0.",
        placeholder="192.0.2.0",
    ),
],

Best practices

  1. Chain all MATCHes from the root account node: Every MATCH clause must connect to the aws variable (or another variable already bound to the account's subgraph). An unanchored MATCH would return nodes from all providers. // WRONG: matches ALL AWSRoles across all providers MATCH (role:AWSRole) WHERE role.name = 'admin' // CORRECT: scoped to the specific account's subgraph MATCH (aws)--(role:AWSRole) WHERE role.name = 'admin' Exception: A second-permission MATCH like MATCH (principal)--(policy2:AWSPolicy)--(stmt2:AWSPolicyStatement) is safe because principal is already bound to the account's subgraph by the first MATCH. It does not need to chain from aws again.
  2. Include Prowler findings: Always add OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL'}}) with collect(DISTINCT pf).
  3. Comment the query purpose: Add inline comments explaining each MATCH clause.
  4. Never use internal labels in queries: _ProviderResource, _AWSResource, _Tenant_*, _Provider_* are for system isolation. They should never appear in predefined or custom query text.
  5. Internet node uses path connectivity: Reach it via OPTIONAL MATCH (internet:Internet)-[can_access:CAN_ACCESS]->(resource) where resource is already scoped by the account anchor. No standalone lookup.

openCypher compatibility

Queries must be written in openCypher Version 9 for compatibility with both Neo4j and Amazon Neptune.

Avoid these (not in openCypher spec)

FeatureUse instead
APOC procedures (apoc.*)Real nodes and relationships in the graph
Neptune extensionsStandard openCypher
reduce() functionUNWIND + collect()
FOREACH clauseWITH + UNWIND + SET
Regex operator (=~)toLower() + exact match, or CONTAINS/STARTS WITH. One legacy query uses =~ - do not add new usages
CALL () {UNION}Multi-label OR in WHERE (see patterns section)

Reference

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

36.42%
按下载量换算124

Claude

30.6%
按下载量换算104

Cursor

16.04%
按下载量换算55

Gemini CLI

8.78%
按下载量换算30

安全审计

Gen Agent Trust Hub

未通过

Socket

通过

Snyk

可疑

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills