Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Data model and vocabularies

Several fields are closed vocabularies. The strings below are the ones stored in the database and accepted by the API, and they are a contract: they will not be renamed under you.

Vocabularies

FieldValues
Membership roleowner, member
Pentest statusplanned, in_progress, completed, archived
Finding severitycritical, high, medium, low, info
Finding statusopen, confirmed, remediated, accepted, false_positive
Asset kinddomain, ip, url, api, mobile
Asset reachabilityup, down, blocked, or absent for not yet determined
IP range kindin, out
API protocolrest, graphql, soap, grpc
Phase statuspending, in_progress, done, na, blocked
Check statusnot_tested, in_progress, tested, not_applicable, blocked
Graph node typeobservation, asset, finding

Parsing is case-insensitive and trims whitespace, so Up and OWNER are accepted. Anything outside the list is a 400 whose message lists the valid values.

Reachability has no “unknown” member on purpose: that state is the absence of a value, not a value.

Observation kinds

Unlike the vocabularies above, an observation’s kind is free text, lowercased on write. The panel offers these:

port, service, dns_record, tech, cert, whois, email, employee, credential_leak, secret, screenshot, asn, takeover_candidate, default_cred_portal, wayback_url, js_endpoint, other

Sticking to them keeps the Recon drawer’s grouping and the cross-engagement views useful, but nothing stops you inventing one when you genuinely need it.

port is special: observations of that kind dedupe on <host>:<port>/<proto>, so re-importing a host after a service scan merges into the existing row rather than stacking a second one.

The check catalogue

The catalogue holds 135 checks, materialised per asset the first time you open that asset’s methodology tab. Each catalogue entry declares which asset kinds it applies to, which is why a domain gets 114 checks and an API asset gets 67.

The catalogue is re-synced from the binary on every startup, so upgrading picks up new and revised checks. Codes that have been withdrawn are deactivated rather than deleted, which leaves the check results you already recorded against them intact.

By standard:

StandardChecks
OWASP Web Security Testing Guide95
CIS quick wins10
OWASP API Security Top 1010
PTES3
No external standardthe remainder

By category:

CategoryChecks
config24
input21
recon20
auth18
client14
business_logic10
session9
authz7
crypto4
cloud4
others (scanner, network, osint_paid, and the phase categories)the remainder

Each entry carries a code, title, description, category, standard and reference, an optional CWE, an optional suggested severity, and reference links.

Tag conventions

Finding tags are a comma-separated string. Two prefixes are understood by the panel:

TagEffect
asset:<value>The finding appears on that asset’s Findings tab.
check:<code>The finding appears under that check in the workspace.

Tag matching is exact on the comma-separated token, so asset:foo does not match asset:foo.bar.

Everything else is free. manual, unverified, retest-passed and client-confirmed are all reasonable, and they are searchable from the findings list and the organization-wide Findings page.

Identifiers

Organization slug: lowercase letters, digits, hyphen and underscore. Fixed after creation because it names a directory.

Pentest code: 2 to 64 characters, starting with an alphanumeric, then letters, digits, hyphen and underscore. Fixed after creation for the same reason. Auto-generated as PT-YYYY-MM-DD-<slug> from the name, with a numeric suffix if that is taken.

API key: rcl_<prefix>_<secret>. Only the prefix and a hash of the secret are stored.

The attack graph

An edge links two nodes, each identified by a type (observation, asset or finding) and an id, with a free-form relation string. Direction matters.

neighbors walks out from a node up to a depth (default 1, maximum 5) in a direction (out, in or both). attack_paths finds paths between two nodes up to a maximum depth (default 5, maximum 8).

Relations are free text, so resolves_to, hosts, credential_for, pivots_to and same_owner_as are all valid without registering them anywhere.

Stored representation

Vocabulary values are stored as their text spelling, not as integers, so a database opened with any SQLite tool reads as critical rather than 0. A stored value outside the vocabulary fails loudly on read rather than being coerced to something plausible.