Query your attack surface with Advanced Query
Copy link

Attack Surface Management (Surface Command) builds your attack surface as a graph database, which maps, stores, and queries data using entities, relationships, and properties. You can use Advanced Query to explore and analyze the graph of your attack surface with Cypher, a graph query language based on openCypher .

This page explains how Advanced Query works in Attack Surface Management (Surface Command), summarizes the Cypher concepts you need to get started, and provides practical examples you can adapt for common use cases.

Before you begin
Copy link

Before writing with Advanced Query, make sure you understand the Unified Asset Model, particularly unified types and unified properties, and what Advanced Query supports. Advanced Query typically work best when you filter on unified types and properties. To learn more about unified types and properties, review Explore unified properties.

Advanced Query syntax support
Copy link

Attack Surface Management (Surface Command) supports a broad subset of Cypher syntax for querying data, including:

  • Clauses such as MATCH, WHERE, and RETURN.
  • Scalar functions like size() and length().
  • Aggregation functions like count(), avg(), and collect().

Cypher keywords aren’t case sensitive, but using uppercase keywords (such as MATCH and RETURN) improves readability.

⚠️

OpenCypher is not the same as Advanced Query Cypher

OpenCypher Resources  explains language syntax, but it doesn’t describe Attack Surface Management (Surface Command)’s object model or custom functions. For Rapid7–specific structure, rely on this page, the Unified Asset Model, Query Builder, and property inspection tools.

Learn the Advanced Query basics
Copy link

Advanced Query is a pattern-matching language. You describe how objects relate to each other, and Advanced Query returns the matching portions of the graph. Most Attack Surface Management (Surface Command) queries follow the same core pattern:

MATCH <pattern> WHERE <conditions> RETURN <results>

Your <pattern> is composed of nodes, labels, and relationships:

  • Nodes represent objects in the Attack Surface Management (Surface Command) unified model, such as Asset, Exposure, Vulnerability, or Software.
  • Labels define the object type and are written after a colon, for example (a:Asset).
  • Relationships connect nodes and are written with dashes and arrows, for example (a:Asset)-->(e:Exposure).
ℹ️

Arrows in Advanced Query indicate traversal direction

Arrows in Advanced Query indicate traversal direction, not ownership, causality, or priority. In Attack Surface Management (Surface Command), many relationships can be traversed in either direction. Direction mainly matters when you want to control how the query engine expands the graph. For example:

(a)--(b) // Traverse in either direction (a)-->(b) // Traverse outward from a to b (a)<--(b) // Traverse inward to a from b

To improve the performance of your queries, always include directional arrows.

Virtual edges
Copy link

Attack Surface Management (Surface Command) computes virtual edges from one or more paths between attack surface components (for example, findings, assets, exposures, identities) to simplify traversal across the unified model and improve query performance. Virtual edges don’t always exist as explicit references in the underlying source data. This abstraction allows you to traverse common relationships without needing to understand how each connector models its data.

For example, instead of writing a query that explicitly traverses findings and exposures:

MATCH (a:Asset)<--(:Finding)-->(:Exposure)-->(v:Vulnerability) RETURN a, v

You can write:

MATCH (a:Asset)-->(v:Vulnerability) RETURN a, v

Virtual edges are used most heavily for vulnerability and exposure analysis but are not limited to those cases. Any connector can define virtual edges to fulfill reference properties, and some connectors use them in other contexts. Because connectors can define virtual edges dynamically, it is not possible to enumerate all available virtual edges in documentation.

ℹ️

Virtual edges may not be optimal

Because virtual edges are derived, they may not expose all of the metadata available on the underlying objects. For example, properties such as first_seen, last_seen, or other lifecycle attributes often exist only on findings or exposures.

If your query requires this information, you may need to traverse findings or exposures explicitly, even though doing so may be slower.

Source types
Copy link

Some properties only exist as connector-specific source types, such as Rapid7IVMVulnerability, AzureAdDevice, or AutomoxOrg. You can find all connector-specific source types in the unified asset model. To learn more about source types, unified types, and the unified asset model, review Explore unified properties.

To review source types:

  1. Go to Assets & Identities > Workspace, then click Unified asset model.
  2. Click a unified type in the model. Example: Software.
  3. Click Source types (blocks).

Querying a unified type (for example, Vulnerability) may be slow or incomplete, so using the connector-specific source type instead can be more efficient and expose additional properties. These additional properties can be queried directly within the unified types. For example:

MATCH (v:Vulnerability) RETURN v.`MicrosoftDefenderVulnerability:cvssV3` AS `cvssV3`, v

Unified properties
Copy link

When you query unified types, Attack Surface Management (Surface Command) evaluates property values across all contributing sources. You can use the top() and every() functions to force a query to return the best or all fulfilling properties, respectively. Review Example Advanced Queries for details.

String and array properties

For string and array properties, filters evaluate all fulfilling values by default. A match succeeds if any source value matches the condition. This behavior helps you find assets even when different sources report slightly different values. To learn more about setting the best value, review Explore unified properties.

Example scenario 1:

A user appears in two sources with different name values:

  • Christopher
  • Chris

If the best value is Chris, a filter on user.name that matches either value still returns the user.

Example scenario 2:

A machine appears in two sources with different operating systems:

  • Windows
  • Linux

If the best value is Linux, a filter on asset.os_family that matches Linux only will return that machine.

Boolean properties and null values

If no source fulfills a boolean property, the value is treated as FALSE in filters. For example, if machine.active is never set:

  • NOT machine.active matches the asset

To explicitly check for missing or false values, use:

  • machine.active IS NULL
  • machine.active = FALSE

Get started with Advanced Query
Copy link

You can write Advanced Queries from the Workspace.

ℹ️

Advanced Query does not support write or delete operations

Advanced Query is read-only, which means you can’t create, update, or delete data.

To use Advanced Query:

  1. Log in to the Command Platform .
  2. Go to Attack Surface Management (Surface Command) > Workspace.
  3. Click + Query.
  4. Click Advanced Query. Note: After you switch to Advanced Query, you can’t switch back to Query Builder for the same query. To return to Query Builder, you need to start a new query.
  5. Enter an Advanced Query.
  6. Click Execute query.

Example Advanced Queries
Copy link

Find assets by operating system

This query returns machines running a Windows operating system:

MATCH (m:Machine) WHERE m.os_family ICONTAINS 'Windows' RETURN m

Traverse relationships

This query finds Windows machines that are associated with vulnerabilities that have a CVSS score greater than 7.0:

MATCH (m:Machine)--(v:Vulnerability) WHERE m.os_family ICONTAINS 'Windows' AND v.cvss > 7 RETURN m

Filter on the best value only

To filter only on the best fulfilling value of a string property, use the top() function:

MATCH (a:Asset) WHERE top(a.name) = 'some_name' RETURN a

For single-value properties, such as numbers, booleans, enumerations, and dates, filters always use the best value.

Match across all fulfilling values

To require that all fulfilling values meet a condition, use the every() function:

MATCH (a:Asset) WHERE TRUE IN every(a.active) RETURN a

Reference a saved query

The INCLUDE statement injects the results of the saved query into the current query context. First, you’ll need to create and save a query. Then reference it from another query:

INCLUDE '<query-name>' MATCH (a)-->(v:Vulnerability) RETURN a, v

Tips for writing effective queries
Copy link

View Query Builder queries as Advanced Queries to copy and learn syntax

You can view any query made with the Query Builder as an Advanced Query to see the exact syntax in Cypher.

To view a Query Builder query as an Advanced Query:

  1. Log in to the Command Platform .
  2. Go to Attack Surface Management (Surface Command) > Saved Queries.
  3. Find a Query Builder query (look for the rocket icon).
  4. Click Edit.
  5. Click Advanced Query.

The Query Builder query as an Advanced Query loads. You can copy the Cypher or convert the query to an Advanced Query.

Start simple and inspect results

If a query returns no results, remove filters and return the nodes you’re matching to confirm what data exists and how it’s shaped. For example, before adding asset filters or version constraints, start with:

MATCH (s:Software) RETURN s

Then gradually add conditions to narrow the result set. This approach helps you identify mismatched property names, unexpected values, or missing relationships.

Use auto-complete to discover types and relationships

As you type in the Advanced Query editor, auto-complete suggests valid types and relationships based on the unified model. If no relationship appears between two types, that relationship isn’t currently modeled or available from your connected data sources.

  • To browse auto-complete suggestions, use the arrow keys.
  • To auto-complete the currently selected suggestion, press Tab or Enter.

Add comments

Use comments to explain complex logic:

  • Single-line comments: // comment
  • Multi-line comments: /* comment */

Format for readability

  • Use Shift + Enter to add a new line without running the query.
  • Break long queries across multiple lines.

Quote string values

Use single or double quotes for string values, especially when they contain spaces:

MATCH (m:Machine)--(s:Storage) WHERE m.operating_system = 'Ubuntu Linux 18.04' AND NOT s.encrypted = true RETURN m

Reuse previous queries

Use the up and down arrow keys in the editor to cycle through recent Advanced Query statements.

FAQs
Copy link

Why does a Software query return results, but not when I join it to assets?

In Attack Surface Management (Surface Command), Software nodes can exist without a direct relationship to assets. Some connectors (for example, ServiceNow) populate software inventory data but don’t provide asset-to-software associations.

As a result:

  • A query like this can return results:

    MATCH (s:Software) WHERE s.name ICONTAINS 'java' AND s.version ISTARTS WITH '8.' RETURN s
  • But adding an asset relationship may return no results:

    MATCH (a:Asset)-->(s:Software) RETURN a, s

This behavior is expected when the connected sources don’t supply asset–software linkage data.

Are relationships between all major asset types supported?

No. You can only traverse relationships that exist in the unified model and are fulfilled by your connected sources.

Relationships between common types, such as Asset, Vulnerability, and Network, are widely supported. Software relationships are more limited and depend heavily on the data source. If a relationship isn’t available:

  • Auto-complete won’t suggest it in the query editor.
  • Pattern matches that rely on it will return no results.

How do relationships work in Advanced Query?

Advanced Query expresses relationships using arrows between nodes:

(a)--(b) // Relationship exists in either direction (a)-->(b) // Outbound relationship from a to b (a)<--(b) // Inbound relationship to a from b

In Attack Surface Management (Surface Command):

  • Arrow direction represents graph traversal direction, not ownership or causality.
  • Many relationships are effectively bidirectional for querying.

You can optionally target a specific relationship:

MATCH (a)-[:RELATIONSHIP_NAME]->(b) RETURN a, b

Relationship names aren’t exhaustively documented because availability depends on the unified model and connected sources.

How can I discover which relationships exist?

Use one or more of the following:

  1. Graphical Query Builder: The relationship picker shows all supported outbound paths for a selected type.
  2. Unified model explorer: Open the unified model explorer.
  3. Advanced Query auto-complete: Suggested relationship names appear as you type.
  4. Inspect generated Advanced Query: Switch a Query Builder query to Advanced Query to see the exact relationship syntax.

Can I reuse the results of one query inside another query?

Yes. Attack Surface Management (Surface Command) supports an INCLUDE statement that lets you reuse the results of a saved query as input to another query. This is useful when:

  • You maintain a frequently changing definition (for example, critical assets).
  • You want to reuse that definition across multiple queries.

Important considerations when using INCLUDE:

  • INCLUDE only works with saved queries. You can’t include an unsaved or ad-hoc query.
  • Changes to the included query don’t automatically update everywhere. If you use an included query in dashboards, widgets, or reports, those views may require a manual refresh after the included query changes.
  • Performance depends on the included query.
    • Keep included queries focused and efficient as the included queries will run before the main query can run.
    • Avoid returning unnecessary nodes or properties in the included query.

INCLUDE is best used to modularize stable logic (like asset groups) while keeping base queries simple and consistent.

Can I search or enumerate all properties for a type?

Currently, there is no way to list and search attributes in query-ready form. However, you can:

  • Use the unified model explorer to understand available properties and fulfillment.
  • Rely on editor auto-complete to discover valid property names while writing queries.
  • Return entire nodes (for example, RETURN a) to inspect which properties are populated.
    • Note: this returns the default properties for the type, not all properties.