prowler-cloud/prowler/prowler-attack-paths-query
- community
Checking that the SKILL.md file is still in the repository.
Creates Prowler Attack Paths openCypher queries using the Cartography schema as the source of truth for node labels, properties, and relationships. Covers Prowler-specific additions (Internet node, ProwlerFinding, internal isolation labels), $provider_uid scoping, and list-property item nodes with typed `HAS_*` edges that run efficiently on both Neo4j and Amazon Neptune sinks. Trigger: When creating or updating Attack Paths queries.
Install
npx vskill@latest install prowler-cloud/prowler/prowler-attack-paths-querySKILL.md
Overview
Attack Paths queries are read-only openCypher queries over a Cartography-ingested cloud graph that detect privilege escalation chains, network exposure, and other graph-shaped security risks. Queries are written in openCypher Version 9 so they run on both Neo4j and Amazon Neptune sinks.
This skill is the concise, action-oriented reference for building queries. For the complete human-readable reference (graph model, list-typed and JSON-encoded properties, compatibility, and worked examples), see docs/developer-guide/attack-paths-queries.mdx.
Two query audiences
| Predefined queries | Custom queries | ||
|---|---|---|---|
| Where they live | api/src/backend/api/attack_paths/queries/{provider}.py | User-supplied via the custom query API endpoint | |
| Provider isolation | AWSAccount {id: $provider_uid} anchor + path connectivity | Automatic _Provider_{uuid} label injection by cypher_sanitizer.py | |
| What to write | Chain every MATCH from the aws variable | Plain Cypher, no isolation boilerplate | |
| Internal labels | Never use | Never use (system-injected) |
Predefined queries: every node must be reachable from the AWSAccount root via graph traversal. That is the isolation boundary.
Custom queries: write natural Cypher. The runner injects a _Provider_{uuid} label into every node pattern, and a post-query filter handles edge cases.
Input sources
Two sources for new queries:
- pathfinding.cloud ID (e.g.
ECS-001,GLUE-001), the Datadog research catalogue. The aggregatedpaths.jsonis too large for WebFetch:
```bash # Fetch a single path by ID curl -s https://raw.githubusercontent.com/DataDog/pathfinding.cloud/main/docs/paths.json \
# List all path IDs and names curl -s https://raw.githubusercontent.com/DataDog/pathfinding.cloud/main/docs/paths.json \
# Filter by service prefix curl -s https://raw.githubusercontent.com/DataDog/pathfinding.cloud/main/docs/paths.json \
```
If jq is unavailable, use python3 -c "import json,sys; ...".
- Natural language description from the requester.
Query structure
Provider scoping parameter
| Parameter | Property | Used on | Purpose | |
|---|---|---|---|---|
$provider_uid | id | AWSAccount | Scopes the query to a specific account |
The runner binds $provider_uid automatically. Every other node is isolated by path connectivity from the AWSAccount anchor.
Imports
Always use PROWLER_FINDING_LABEL via f-string interpolation, never hardcode "ProwlerFinding".
Definition fields
- id: kebab-case
{provider}-{description}, e.g.aws-ec2-privesc-passrole-iam. - name: short, human-friendly label. Sourced queries append the reference ID:
"EC2 Instance Launch with Privileged Role (EC2-001)". - short_description: one sentence, no technical permissions.
- description: full technical explanation, plain text.
- provider:
aws,azure,gcp,kubernetes, orgithub. - cypher: f-string Cypher body. Literal
{/}are escaped as{{/}}. - parameters:
parameters=[]if none. - attribution: optional
AttackPathsQueryAttribution(text, link)for sourced queries.linkuses the lowercase ID.
Append the constant to the {PROVIDER}_QUERIES list at the bottom of the provider file.
Predefined query template
The canonical shape combines a principal walk, an optional target walk, deduplicated nodes, and a typed finding overlay:
Key points:
- The principal walk types the
POLICYandSTATEMENThops. Both are low-fan-out (each principal has a handful of policies; each policy a handful of statements), so the typed edge lets the planner cost a cheap inline filter. - The
(aws)--hub hops stay anonymous.AWSAccountis a high-degree node that fans out to every principal, role, policy, and resource in the account; typing those edges forces the planner to enumerate from the hub and collapses performance on multi-tenant Neptune. - Other relationship types appear only where the file's existing queries already use one (
TRUSTS_AWS_PRINCIPAL,STS_ASSUMEROLE_ALLOW,MEMBER_AWS_GROUP,HAS_EXECUTION_ROLE). - The finding probe is typed
:HAS_FINDINGand left undirected. The type lets Neptune apply an inline edge filter; the lack of direction matches the convention of the rest of the file. - Collapse duplicate rows after each permission gate with
WITH DISTINCT, carrying only the variables needed by later clauses. - Each
HAS_*traversal is its ownMATCHclause with aWHEREon the child item node.WITH DISTINCT path_principal, path_targetprecedescollect(path...)to dedupe the row multiplication produced by the joins. - The
RETURNshapepaths, dpf, dpfris the contract the serializer and visualiser depend on. Do not change it.
Avoiding cartesian products
Matching a target set (AWSRole, AWSUser, AWSGroup) and then filtering each target against a statement's HAS_RESOURCE items in a separate, unconnected MATCH builds a cartesian product: every target is paired with every resource item before the filter runs. On accounts with many principals this errors or times out. Pre-aggregate the resource values into a list, then match each target once:
- Aggregate resources before matching targets; cost becomes
targets + resources, nottargets × resources. This is a pure rewrite, the result set is identical. ('*' IN res_values)short-circuits the wildcard grant so the list scan runs only when needed.- Bind
target.name/target.arnto locals so the list comprehension reads them once per target, not once per resource value. size([...]) > 0is the Neptune-compatible form ofany()(see "openCypher compatibility").- Two-statement queries aggregate each statement's resources into its own list (
res_values,res2_values) and combine the twosize([...]) > 0checks withAND. - Targets already constrained by a relationship (
STS_ASSUMEROLE_ALLOW,TRUSTS_AWS_PRINCIPAL) need no aggregation: the relationship already bounds the set.
Privilege escalation sub-patterns
Four path_target shapes cover the common attack types. Each shares the canonical template's path_principal, deduplication tail, and RETURN; only the path_target MATCH and its resource predicate differ.
| Sub-pattern | Target | path_target shape | Example | |
|---|---|---|---|---|
| Self-escalation | Principal's own policies | (aws)--(target_policy:AWSPolicy)--(principal) | IAM-001 | |
| Lateral to user | Other IAM users | (aws)--(target_user:AWSUser) | IAM-002 | |
| Assume-role lateral | Assumable roles | (aws)--(target_role:AWSRole)-[:STS_ASSUMEROLE_ALLOW]-(principal) | IAM-014 | |
| PassRole + service | Service-trusting roles | (aws)--(target_role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]-(:AWSPrincipal {arn: '{service}.amazonaws.com'}) | EC2-001 |
Multi-permission queries (e.g. PassRole plus a service-create action) add permission gates before path_target. Reuse the per-query counter for new variables (act2, policy2, stmt2) and collapse rows after each gate:
If a permission is an existence-only gate whose statement resource is not checked later, keep the policy and statement anonymous and carry only the variables still needed:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/prowler-attack-paths-query/SKILL.md
Popularity
- Repository stars
- 13,385
- Repository forks
- 2,051
- 7-day trend score
- 48
Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 24 Mar 2026, 7 months ago.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/prowler-cloud/prowler/prowler-attack-paths-query)