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
| Field | Values |
|---|---|
| Membership role | owner, member |
| Pentest status | planned, in_progress, completed, archived |
| Finding severity | critical, high, medium, low, info |
| Finding status | open, confirmed, remediated, accepted, false_positive |
| Asset kind | domain, ip, url, api, mobile |
| Asset reachability | up, down, blocked, or absent for not yet determined |
| IP range kind | in, out |
| API protocol | rest, graphql, soap, grpc |
| Phase status | pending, in_progress, done, na, blocked |
| Check status | not_tested, in_progress, tested, not_applicable, blocked |
| Graph node type | observation, 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:
| Standard | Checks |
|---|---|
| OWASP Web Security Testing Guide | 95 |
| CIS quick wins | 10 |
| OWASP API Security Top 10 | 10 |
| PTES | 3 |
| No external standard | the remainder |
By category:
| Category | Checks |
|---|---|
config | 24 |
input | 21 |
recon | 20 |
auth | 18 |
client | 14 |
business_logic | 10 |
session | 9 |
authz | 7 |
crypto | 4 |
cloud | 4 |
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:
| Tag | Effect |
|---|---|
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.