CyboruxCyborux API
Domains

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.

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, 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_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.

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: critical 0.20, high 0.075, medium 0.02, low 0.003, info 0. A single finding's contribution is therefore bounded at 20 % of the sector baseline.

Employee-size multiplier

Employees bucketMultiplierTier label
1-100.20micro
11-500.20micro
51-1000.45small
101-5000.45small
501-10000.75mid
1000+1.00enterprise
unknown / missing1.00unknown

Aggregation — per_finding_type_capped

financial_impact.total_eur does not add the per-row EUR for every finding. Instead:

  1. Group findings by finding_type.
  2. 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).
  3. Sum the per-type contributions.
  4. Clip the total at one full sector baseline (baseline_eur). by_severity_eur is 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

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 carries a vulnerability_id (CVE / GHSA / OSV / WPSCAN).
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"],
      "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"
    ]
  }
}
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 }. identifier is always populated, except for domain-level findings with no specific asset, where it is null.

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, patch_available. null otherwise.

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.

findings[].conditions_metarray | null

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

findings[].estimated_impact_eurinteger

Per-finding EUR contribution to the overall risk exposure. See the Financial-impact methodology section above.

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 carries a vulnerability identifier.

summary.pageobject

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

financial_impactobject

Sector-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"]