# Query Search

This page describes how P0's environment query searches work.

Query searches are controlled using two parts:

<figure><img src="/files/mKRu0Tm9XL7pZcO0OhNd" alt="" width="563"><figcaption></figcaption></figure>

* **show** - controls which kind of data are displayed
* **where** - controls which data to show

#### Show control

Currently, you can choose to "show" credentials (access keys or short-term authentication), principals (users, groups, machine identities, and so forth), grants (in Google Cloud, a role binding; in AWS, a policy attachment), or resources (projects, accounts, services, and individual resources such as storage buckets).

#### Where control

The "where" control is a free-form search box. You can enter any term here, and P0 will find the principals or grants that relate to your search term.

*Example*:

Searching for a permission (in this case `compute.instances.create` in a Google Cloud assessment) will show you all grants that provide that permission:

<figure><img src="/files/ZZUtoUBw9HdiIhqTLgVK" alt="" width="563"><figcaption></figcaption></figure>

To see *why* a search result matches your query, you can click on that result's "view" link. The details page will show an "Explanation" section at the bottom, describing how that result satisfies your query:

<figure><img src="/files/Ms91LSv5o6PkESNVbpEr" alt="" width="563"><figcaption></figcaption></figure>

### Query expressions

You can be more specific in your queries by writing query expressions. This section explains each type of query expression

Here's a summary of query expressions:

<table><thead><tr><th width="272.3333333333333">Expression</th><th width="218">See</th><th></th></tr></thead><tbody><tr><td>Key terms</td><td></td><td></td></tr><tr><td><code>keyword</code></td><td><a data-mention href="#contains-matches">#contains-matches</a></td><td>Match data substring</td></tr><tr><td><code>"keyword"</code></td><td><a data-mention href="#exact-matches">#exact-matches</a></td><td>Match data exactly</td></tr><tr><td><code>!keyword</code></td><td><a data-mention href="#inverted-matches">#inverted-matches</a></td><td>Invert keyword matches</td></tr><tr><td>Node terms</td><td></td><td></td></tr><tr><td><code>type:keyterm</code></td><td><a data-mention href="#type-matches">#type-matches</a></td><td>Match data types</td></tr><tr><td><code>type=keyterm</code></td><td><a data-mention href="#first-matches">#first-matches</a></td><td>Match first datum only</td></tr><tr><td><code>type:attribute:keyterm</code> or <code>type:{attribute1:keyterm1 attribute2:keyterm2 ...}</code></td><td><a data-mention href="#attribute-matches">#attribute-matches</a></td><td>Match data attributes</td></tr><tr><td>Path terms</td><td></td><td></td></tr><tr><td><code>keyterm->childpath</code></td><td>Child paths</td><td>Match a directed path in child direction</td></tr><tr><td><code>keyterm&#x3C;-parentpath</code></td><td>Parent paths</td><td>Match a directed path in parent direction</td></tr><tr><td><code>keyterm&#x3C;>eitherpath</code></td><td>Either paths</td><td>Match a directed path in either parent or child direction</td></tr><tr><td><code>childpath</code> | <code>parentpath</code> | <code>eitherpath</code></td><td><a data-mention href="#via-matches">#via-matches</a></td><td>Place multiple conditions on a data connection</td></tr><tr><td>Exclusion term</td><td></td><td></td></tr><tr><td><code>^pathterm</code></td><td><a data-mention href="#exclusion-matches">#exclusion-matches</a></td><td>Remove matches from results</td></tr><tr><td>Compound expression</td><td></td><td></td></tr><tr><td><code>expression term</code></td><td><a data-mention href="#multiple-matches">#multiple-matches</a></td><td>Require multiple data connections</td></tr></tbody></table>

*Cypher equivalents*

Each detailed explanation in the following sections also describes the equivalent statement in the Cypher query language (replace `{show}` with the corresponding label of the "show" control).

When displaying data as a table, the displayed data are the nodes matching the "show" type (represented by `s` in the equivalent queries); when displaying data as a graph visualization, the displayed data are the returned paths (represented by `p` in the equivalent queries).

#### "Contains" matches

In it's simplest usage, P0 matches IAM data as long as it includes your search keyword. In the above example, searching for `compute` will show you grants that allow access to any compute resource, provide any privileges with "compute" in their name, grant a permission set with "compute" in its name, or grant access to compute service principals.

"Contains" matches are case insensitive; use [#exact-matches](#exact-matches "mention") to find data with exact casing.

*Cypher equivalent*:

```cypher
CALL () {
    MATCH p=(s:{show})-[*]->(r)
    RETURN p, r, s
    UNION
    MATCH p=(r)-[*]->(s:{show})
    RETURN p, r, s
}
WITH p, r, s
WHERE ANY(k IN KEYS(r) WHERE r[k] =~ '(?i).*{keyword}.*')
RETURN p, s
```

#### Exact matches

To match data exactly, enclose your keyword in double quotes. E.g., searching for `compute.instances.get` in GCP will match additional permissions, such as `compute.instances.getEffectiveFirewalls`. Searching for`"compute.instances.get"` will limit results to only those grants that have that specific permission.

{% hint style="info" %}
When using exact matches with type and attribute matches, the quotes surround the keyword only: `type:attribute:"keyword"`.

You can also use quotes to search for data where the data includes a colon without triggering a type or attribute match. E.g., `risk:"exfiltration:data"` will return all results that yield a data exfiltration risk.
{% endhint %}

*Cypher equivalent*:

```cypher
CALL () {
    // per "contains" CALL statement
}
WITH p, r, s
WHERE ANY(k IN KEYS(r) WHERE r[k] = '{keyword}')
RETURN p, s
```

#### Inverted matches

You can search for grants and principals that are connected to data that *don't* match a keyword by typing a `!` in front of your search keyword.

Note that using an inverted match on its own usually won't do much, as grants and principals are connected to *many* data, and some of these data are likely to not match your keyword. Instead, inverted matches are usually best when combined with type or attribute matches, or with exclusion matches. For example, `principal:mfa:!enabled` will show you all users that have either disabled or unknown MFA status.

{% hint style="info" %}
When using inverted matches with type and attribute matches, the `!` comes *after* the type and attribute: `type:attribute:!keyword`.
{% endhint %}

*Cypher equivalent*:

```cypher
CALL () {
    // per "contains" CALL statement
}
WITH p, r, s
WHERE ANY(k IN KEYS(r) WHERE NOT ({keyterm condition}))
RETURN p, s
```

#### Exclusion matches

You can search for items that are *not* connected to data that match a term by typing a `^` in front of your entire search term.

For example, searching for `^usage:type:"unused"` will show all grants that have only used or unknown permission usage. Searching for `^usage:type:!"unused"` will show all grants where *all* permissions are unused.

{% hint style="info" %}
When using exclusion matches, the `^` comes *before* the type and attribute: `^type:attribute:keyterm`.
{% endhint %}

*Cypher equivalent*:

```cypher
MATCH (s1:{show})
WHERE (COUNT {
    // pathterm query w/out "RETURN"
    AND s=s1
}) = 0
RETURN s1
```

#### Type matches

Limit your search to a specific type of IAM data using a type prefix. For example, adding `risk:CRITICAL` in front of your search will limit your search to only showing grants that allow a critical IAM risk (as defined by the [IAM Privilege Catalog](https://catalog.p0.dev/scores)). See [Search Reference](/inventory/query-search/search-reference.md#search-types) for a list of all possible types.

{% hint style="info" %}
You can use a type match without a keyword to search for the presence of data.

For example, `condition:` will show you all conditional grants.
{% endhint %}

*Cypher equivalent*:

<pre class="language-cypher"><code class="lang-cypher"><strong>CALL () {
</strong>    // per "contains" CALL statement
}
WITH p, r, s
WHERE r:{type} AND ANY(k IN keys(r) WHERE r[k] =~ '(?i).*{keyword}.*')
RETURN p, s
</code></pre>

#### "First" matches

Data may be connected to a chain of items of the same type. For instance, a grant on a resource will give access to all that resource's children, and all those child resources' children, and so forth. Or, grants may be made to directory groups with nested group membership.

To restrict your search to only the first item in such a chain, use a first match. For example, `principal=alice@my.co` will show only the `alice@my.co` user, and not the groups to which that user belongs.

*Cypher equivalent*:

```cypher
CALL () {
    // per "contains" CALL statement
}
WITH p, r, s
WHERE NOT (p)-[*]->(:{type})-[*]->(r)
  AND NOT (r)-[*]->(:{type})-[*]->(p)
  AND ANY(k IN keys(r) WHERE r[k] =~ '(?i).*{keyword}.*')
RETURN p, s
```

#### Attribute matches

Attribute expressions allow you to make even more specific searches. For example, searching for `credential:last90:unused` will limit displayed principals to those with at least one credential that has not been used in the previous 90 days. See [Search Reference](/inventory/query-search/search-reference.md#search-attributes) for a list of all possible attributes.

{% hint style="info" %}
First and attribute matches may be combined using the syntax `{type}={attribute}:{keyterm}`.
{% endhint %}

*Cypher equivalent*:

```cypher
CALL () {
    // per "contains" CALL statement
}
WITH p, r, s
WHERE r:{type} AND r.{attribute} =~ '(?i).*{keyword}.*'
RETURN p, s
```

#### Multiple matches

Return items that are connected to multiple data by separating search terms using whitespace.

For instance, `resource:one resource:two` will show you grants that provide access to both resources "one" and "two".

*Cypher equivalent*:

```cypher
CALL () {
    // Result of first query
    RETURN p AS p1, s AS s1
}
WITH p1, s1
CALL () {
    // Result of second query
    RETURN p AS p2, s AS s2
}
WITH p2, s2
WHERE s1 = s2
RETURN s1, p1, p2
```

#### Via matches

Your IAM data are modeled as a directed graph. You can require data to be connected to your search results according to multiple search terms using a via match.

To use a via match, connect two or more terms using `->` (for child relationships), `<-` (for parent relationships), or `<>` (for either child or parent relationships).

For example, to find all entitlements that have unused permissions that create a data exfiltration risk, you can search for `usage:type:"unused"->risk:"exfiltration:data"`.

You can chain multiple terms together using additional `->`. For example `usage:type:"unused"->privilege:s3->risk:"exfiltration:data"`.

{% hint style="warning" %}
Paths must consistently use child, parent, or "either" relationship syntax. Mixed paths like `a->b<-c` are not currently supported.
{% endhint %}

You can reference how data are connected in this graph using [Search Reference](/inventory/query-search/search-reference.md#iam-graph).

{% hint style="info" %}
Exclusion matches combined with via matches will return results where one or more of the via conditions do not match.
{% endhint %}

*Cypher equivalent for* `s<>r`:

```cypher
CALL () {
    MATCH p=(s:{show})-[*]->(q)-[*]->(r)
    RETURN p, q, r, s
    UNION
    MATCH p=(r)-[*]->(q)-[*]->(s:{show})
    RETURN p, q, r, s
}
WITH p, q, r, s
WHERE
    // constraints on q
    AND
    // constraints on r
RETURN p, s
```

### Query examples

One of the best resources for constructing queries is to view the search queries for P0's built-in assessment monitors.

For instance, here's the query for detecting unused service account keys:

`show = credential`

```
credential=enabledKey:"true"
credential=last40:"unused"
principal=type:"service-account"
principal=status:"active"
```

This returns all service-account keys that have not been used in the last 40 days.

### Query links

You can also construct queries using tooltips in the displayed data. To do this, hover over an item you want to either include or exclude from your search:

<figure><img src="/files/iaSvAiBwTFlj7vV907o6" alt="" width="563"><figcaption></figcaption></figure>

Select the corresponding "show" or "hide" link to either include or exclude that item in your search results.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.p0.dev/inventory/query-search.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
