CyboruxCyborux API
Domains

List Findings

List every detected security finding for a domain, with CVE/CVSS/EPSS data, full affected-asset detail, and the sector's average breach cost as industry context.

https://api.cyborux.com
GET/api/domain/{domain_name}/findings
Path Parameters
string
string
string
string
boolean
string
string
integer
integer
Authorizationheader
Bearer <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:

  • Classificationseverity (critical/high/medium/low/info), category (vulnerability, infrastructure, email_security, …), and the rule-engine finding_type.
  • Status timelinestatus (new/acknowledged/false_positive/resolved/ignored), detected_at, verified_at.
  • Affected asset — polymorphic reference (type + identifier). The identifier is always returned; it is null only for domain-level findings that have no specific asset.
  • CVE block — when the underlying finding is vulnerability-class, a flat cve object is surfaced with the identifier (CVE / GHSA / OSV / WPSCAN id), CVSS score and vector, EPSS probability + percentile, CISA KEV membership (in_kev), and exploit/patch availability flags. The response also includes a summary block (faceted counts — see below) and a financial_impact block carrying the average cost of a breach in the organization's sector, so a dashboard can render the risk distribution and its industry context without paginating through every row. Findings carry no monetary value of their own.

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_severity and summary.with_cve ignore the severity and with_cve selections — they count over the domain + status + q + category set.
  • summary.by_category ignores the category selection — it counts over the domain + status + q + severity + with_cve set.
  • summary.total and the paginated findings[] reflect the fully-filtered set.

Sector-average breach cost

Methodology version: ibm-2025-eur-v3.

financial_impact.sector_average_eur is the average cost of a breach that the IBM Cost of a Data Breach Report 2025 published for the organization's sector, converted at the ECB 2025 average USD→EUR rate (0.92) and rounded to the nearest EUR 100,000:

sector_average_eur = round(baseline_eur(sector))

One lookup, no multiplications. It is industry context, not a measurement of the domain's risk — no finding, no severity and no headcount enters it, so it is invariant across this endpoint's filters and identical for two domains in the same sector. Findings themselves carry no estimated_impact_eur: pricing a finding at a fraction of a sector baseline treated an ordinal severity as a probability that was never measured.

  • Sector baselines come from the IBM per-industry average breach cost, keyed by a sector taxonomy that collapses NIS2 Annex I + II onto IBM's industry buckets. A user-supplied sector is resolved by exact match or synonym.
  • Unresolved sectors read the global average across all sectors (other) and are flagged: sector_known is false and caveats carries sector-fallback-other. Surface that flag — the figure is then not the caller's sector's.
  • employee_tier is organization context for display only; it does not scale the figure.

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

ParameterTypeDescription
domain_namestringThe domain name (e.g. example.com).

Query Parameters

ParameterTypeDefaultDescription
severitystringnoneComma-list, allow-listed against critical,high,medium,low,info. Garbage values return 422.
categorystringnoneComma-list of categories. One of: vulnerability, infrastructure, exposure, authentication, email_security, credential_exposure, encryption, web_security, dns_security, misconfiguration, reconnaissance.
statusstringactiveactivenew+acknowledged. all disables filtering. Any single status value also accepted.
with_cvebooleanfalseRestrict to findings whose evidence names at least one advisory — exactly the findings that come back with a non-null cve block.
languagestringenOutput language for findings[].title and findings[].description. One of en, es, ca. Unknown values fall back to en.
qstringnoneCase-insensitive substring match on the finding title (max 200 chars).
limitinteger100Page size, clamped to [1, 500].
offsetinteger0Number 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"]
    }
  ],
  "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+",
    "sector_average_eur": 5100000,
    "currency": "EUR",
    "methodology_version": "ibm-2025-eur-v3",
    "caveats": [
      "estimate-not-actuarial",
      "excludes-fines-and-ransom",
      "usd-to-eur-2025-ecb"
    ]
  }
}
StatusDetail
401Not authenticated.
403Forbidden — you do not have access to this domain.
404Domain not found.
422Validation error — e.g. severity contained a non-allow-listed value.

Response Fields

findingsarray

Page of finding rows, ordered by severity (critical first) then detected_at desc.

findings[].idinteger

Stable identifier for the finding row.

findings[].finding_typestring

Rule-engine identifier (e.g. vulnerable_technology, subdomain_takeover, email_spoofable). Stable across analyses.

findings[].severitystring

One of critical, high, medium, low, info.

findings[].categorystring

One of the 12 categories listed under Query Parameters.

findings[].statusstring

new, acknowledged, false_positive, resolved, or ignored.

findings[].affected_assetobject

{ type, identifier, component }. identifier is always populated, except for domain-level findings with no specific asset, where it is null.

component names the part of that asset the finding is about — the technology on a host, such as openssl on app.example.com. It sits beside the identifier rather than inside it, because the identifier is rendered verbatim as the name of a thing you own. null for findings that are about the asset as a whole.

Findings of a type that carries a component are one row per (asset, component) pair: a host running two vulnerable technologies returns two rows, not one.

findings[].cveobject | null

Present when the finding's evidence carries a vulnerability identifier. Fields: identifier, cvss_score, cvss_vector, epss_score, epss_percentile, exploit_available, in_kev, patch_available. null otherwise. in_kev is membership of CISA's Known Exploited Vulnerabilities catalogue; together with epss_score at or above 0.7 it is what promotes a vulnerability finding to critical.

findings[].evidenceobject | null

Structured 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.

For a vulnerability-class finding, evidence.cves carries the full advisory population, worst first, in the same shape as the cve block above. Derived figures are not sent beside it: the number of advisories is the length of that list and a severity breakdown is a fold over it. Two undocumented fields, cve_count and severity_histogram, were emitted alongside it in earlier responses and have been removed — a second copy of a number is a second place for it to go stale. Count and group evidence.cves instead.

findings[].conditions_metarray | null

Rule conditions that triggered the finding. null when the finding records none.

summaryobject

Aggregate counts over the filtered result set (so filter chips and histograms stay coherent).

summary.totalinteger

Total number of findings matching the filters.

summary.by_severityobject

Count per severity. Keys: critical, high, medium, low, info.

summary.by_categoryobject

Count per category present in the filtered set.

summary.with_cveinteger

Count of findings whose evidence names at least one advisory — the same set with_cve=true returns.

summary.pageobject

{ limit, offset, next_offset }. next_offset is null when the last page is reached.

financial_impactobject

The organization's sector average breach cost — industry context, not the domain's risk. Fields: sector_key, sector_label, sector_known, employee_tier, sector_average_eur, currency, methodology_version, caveats. sector_known: false (with the sector-fallback-other caveat) means the sector did not resolve and the figure is the global average across all sectors.

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"]
sector_average_eur = payload["financial_impact"]["sector_average_eur"]