List Findings
List every detected security finding for a domain, with CVE/CVSS/EPSS data, full affected-asset detail, and a sector-aware EUR financial-impact estimate.
/api/domain/{domain_name}/findingsBearer <token>API key authentication — use your Cyborux API key as a Bearer token.
Overview
Returns every security finding the analysis engine has persisted for a domain. Each row carries:
- Classification —
severity(critical/high/medium/low/info),category(vulnerability, infrastructure, email_security, …), and the rule-enginefinding_type. - Status timeline —
status(new/acknowledged/false_positive/resolved/ignored),detected_at,verified_at. - Affected asset — polymorphic reference (
type+identifier). Theidentifieris always returned; it isnullonly for domain-level findings that have no specific asset. - CVE block — when the underlying finding is vulnerability-class, a flat
cveobject is surfaced with theidentifier(CVE / GHSA / OSV / WPSCAN id), CVSS score and vector, EPSS probability + percentile, and exploit/patch availability flags. - Estimated EUR impact — a per-finding monetary estimate (
estimated_impact_eur) derived from the user's sector and employee-size bucket.
The response also includes a summary block (faceted counts — see below) and a financial_impact aggregate so a dashboard can render risk distribution and total exposure without paginating through every row.
Asset visibility
Affected-asset identifiers and identifier-bearing evidence keys (subdomain names, email addresses, file paths, usernames, person names, internal IPs, phone numbers, CNAME targets) are returned in full to any user with access to the domain — everything the platform surfaces is public OSINT, so there is no ownership wall.
Per-row title and description come from the localised findings catalog (see language), not from the DB. That keeps the copy generic and produces natural Spanish/Catalan copy when language=es|ca.
CVE, CVSS, EPSS, technology name + version, breach counts, and externally observable signals (server header, TLS posture, DMARC/SPF reasons, etc.) are likewise visible.
Facet counts
Each facet's chip counts ignore that facet's own selection, so a UI can render counts that mean "what the list would become if I picked this filter":
summary.by_severityandsummary.with_cveignore theseverityandwith_cveselections — they count over the domain +status+q+categoryset.summary.by_categoryignores thecategoryselection — it counts over the domain +status+q+severity+with_cveset.summary.totaland the paginatedfindings[]reflect the fully-filtered set.
Financial-impact methodology
Methodology version: ibm-2025-eur-v2.
Each finding gets a per-row EUR contribution computed as:
baseline_eur(sector, employees) × severity_fraction[severity]- Sector baselines come from the IBM Cost of a Data Breach Report 2025 per-industry average breach cost, mapped to NIS2 sectors. Unknown / unmapped user-supplied sectors fall back to the global average (
other). - Employee-size multiplier scales the sector baseline by the user's employees bucket. Unknown / unmapped buckets fall back to 1.00.
- Severity → fraction-of-baseline:
critical0.20,high0.075,medium0.02,low0.003,info0. A single finding's contribution is therefore bounded at 20 % of the sector baseline.
Employee-size multiplier
| Employees bucket | Multiplier | Tier label |
|---|---|---|
1-10 | 0.20 | micro |
11-50 | 0.20 | micro |
51-100 | 0.45 | small |
101-500 | 0.45 | small |
501-1000 | 0.75 | mid |
1000+ | 1.00 | enterprise |
| unknown / missing | 1.00 | unknown |
Aggregation — per_finding_type_capped
financial_impact.total_eur does not add the per-row EUR for every finding. Instead:
- Group findings by
finding_type. - Within each group, take the highest severity fraction — duplicates of the same risk class collapse to a single contribution (an attacker only needs to exploit one instance of a class to realise that risk).
- Sum the per-type contributions.
- Clip the total at one full sector baseline (
baseline_eur).by_severity_euris scaled proportionally when the cap fires so the breakdown still sums to the cap.
The per-row estimated_impact_eur stays as the unaggregated severity × baseline value — useful for ranking individual rows by exposure.
Figures are model-derived estimates, not actuarial losses — they exclude regulatory fines (GDPR / NIS2: up to EUR 10 M or 2 % of turnover) and ransom payments, which can dwarf the recovery cost the catalog represents.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
domain_name | string | The domain name (e.g. example.com). |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
severity | string | none | Comma-list, allow-listed against critical,high,medium,low,info. Garbage values return 422. |
category | string | none | Comma-list of categories. One of: vulnerability, infrastructure, exposure, authentication, email_security, credential_exposure, encryption, web_security, dns_security, misconfiguration, reconnaissance. |
status | string | active | active ≡ new+acknowledged. all disables filtering. Any single status value also accepted. |
with_cve | boolean | false | Restrict to findings whose evidence carries a vulnerability_id (CVE / GHSA / OSV / WPSCAN). |
language | string | en | Output language for findings[].title and findings[].description. One of en, es, ca. Unknown values fall back to en. |
q | string | none | Case-insensitive substring match on the finding title (max 200 chars). |
limit | integer | 100 | Page size, clamped to [1, 500]. |
offset | integer | 0 | Number of rows to skip from the start of the filtered set. |
Response
{
"findings": [
{
"id": 18342,
"finding_type": "subdomain_takeover",
"severity": "high",
"category": "infrastructure",
"title": "Subdomain Takeover Risk",
"description": "One or more subdomains point to external services that are no longer claimed or have been decommissioned. These dangling DNS records can be exploited by attackers to take control of the subdomain.",
"status": "new",
"detected_at": "2026-05-01T10:00:00Z",
"verified_at": "2026-05-05T08:00:00Z",
"affected_asset": { "type": "subdomain", "identifier": "legacy.example.com" },
"cve": null,
"evidence": {
"cname": "abandoned.s3.amazonaws.com",
"is_external_cname": true
},
"conditions_met": ["cname_external", "no_active_target"],
"estimated_impact_eur": 383640
}
],
"summary": {
"total": 87,
"by_severity": { "critical": 5, "high": 12, "medium": 30, "low": 30, "info": 10 },
"by_category": { "vulnerability": 14, "email_security": 10, "infrastructure": 18 },
"with_cve": 14,
"page": { "limit": 100, "offset": 0, "next_offset": null }
},
"financial_impact": {
"sector_key": "finance",
"sector_label": "Finance",
"sector_known": true,
"employee_tier": "1000+",
"employee_tier_label": "enterprise",
"employee_multiplier": 1.00,
"baseline_eur": 5115200,
"total_eur": 2438700,
"by_severity_eur": {
"critical": 1023040,
"high": 1151670,
"medium": 263990,
"low": 0,
"info": 0
},
"currency": "EUR",
"methodology_version": "ibm-2025-eur-v2",
"source": "IBM Cost of a Data Breach Report 2025; NIS2 sector mapping",
"aggregation_method": "per_finding_type_capped",
"caveats": [
"estimate-not-actuarial",
"excludes-fines-and-ransom",
"usd-to-eur-2025-ecb",
"per-finding-type-aggregation"
]
}
}| Status | Detail |
|---|---|
401 | Not authenticated. |
403 | Forbidden — you do not have access to this domain. |
404 | Domain not found. |
422 | Validation error — e.g. severity contained a non-allow-listed value. |
Response Fields
findingsarrayPage of finding rows, ordered by severity (critical first) then detected_at desc.
findings[].idintegerStable identifier for the finding row.
findings[].finding_typestringRule-engine identifier (e.g. vulnerable_technology, subdomain_takeover, email_spoofable). Stable across analyses.
findings[].severitystringOne of critical, high, medium, low, info.
findings[].categorystringOne of the 12 categories listed under Query Parameters.
findings[].statusstringnew, acknowledged, false_positive, resolved, or ignored.
findings[].affected_assetobject{ type, identifier }. identifier is always populated, except for domain-level findings with no specific asset, where it is null.
findings[].cveobject | nullPresent when the finding's evidence carries a vulnerability identifier. Fields: identifier, cvss_score, cvss_vector, epss_score, epss_percentile, exploit_available, patch_available. null otherwise.
findings[].evidenceobject | nullStructured supporting context — identifier-bearing keys (subdomain, email, filename, username, person_name, cname, phones, private_ips, …) alongside CVE-bearing keys and externally observable signals (server header, breach names, TLS posture, DMARC reasons, etc.). All keys are returned.
findings[].conditions_metarray | nullRule conditions that triggered the finding. null when the finding records none.
findings[].estimated_impact_eurintegerPer-finding EUR contribution to the overall risk exposure. See the Financial-impact methodology section above.
summaryobjectAggregate counts over the filtered result set (so filter chips and histograms stay coherent).
summary.totalintegerTotal number of findings matching the filters.
summary.by_severityobjectCount per severity. Keys: critical, high, medium, low, info.
summary.by_categoryobjectCount per category present in the filtered set.
summary.with_cveintegerCount of findings whose evidence carries a vulnerability identifier.
summary.pageobject{ limit, offset, next_offset }. next_offset is null when the last page is reached.
financial_impactobjectSector-aware EUR exposure aggregate. See methodology section for derivation. Fields: sector_key, sector_label, sector_known, employee_tier, employee_tier_label, employee_multiplier, baseline_eur, total_eur, by_severity_eur, currency, methodology_version, source, aggregation_method, caveats. The sector_known flag tells honest "exact estimate" apart from "global-average fallback".
curl -X GET "https://api.cyborux.com/api/domain/example.com/findings?severity=critical,high&with_cve=true" \
-H "Authorization: Bearer YOUR_API_KEY"const url = new URL(
"https://api.cyborux.com/api/domain/example.com/findings"
);
url.searchParams.set("severity", "critical,high");
url.searchParams.set("with_cve", "true");
const res = await fetch(url, {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { findings, summary, financial_impact } = await res.json();import requests
response = requests.get(
"https://api.cyborux.com/api/domain/example.com/findings",
params={"severity": "critical,high", "with_cve": True},
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
payload = response.json()
findings = payload["findings"]
total_eur = payload["financial_impact"]["total_eur"]