ExonaExona API
Guides

Guide: Understanding Risk Scores

How to read and use Exona's AI risk assessment output in an underwriting context.

What you get

Every completed scan includes a risk_assessment block with:

  • Six scored dimensions (each with a numeric score, a label, and evidence-backed rationale)
  • A regulatory_exposure narrative
  • A composite overall_risk_level

This guide explains how to interpret these together.


Start with the overall level

overall_risk_level gives you the first-pass signal:

LevelIndicative meaning
LowAI is peripheral; failures have limited impact; coverage is generally straightforward.
MediumSome AI risk factors present; underwriting may require additional information or endorsements.
HighSignificant AI autonomy or domain risk; warrants detailed review and likely specific exclusions or conditions.
Very HighCore autonomous AI in a consequential domain with governance gaps; may require specialist underwriting or declination.

Use this to route applications efficiently: Low and Medium risks can follow a streamlined path; High and Very High warrant senior underwriter review.


Read the dimensions together, not in isolation

The dimensions interact. The most important combinations:

High AI Intensity + High Autonomy = systemic risk If a company's AI is both central to the product (ai_intensity: 4) and operates without human oversight (autonomy: 3), errors cannot be caught before they affect users. This combination is a primary indicator of systemic loss potential.

High Blast Radius + Weak Controls = accumulation risk A large user base (blast_radius: 3) with weak governance (control_governance: 3) means that a single model failure could affect a very large number of people before anyone notices. This is an accumulation concern: especially relevant for cyber and E&O books.

High Domain Risk + Weak Controls = regulatory risk Insurance, healthcare, and credit decisions are often regulated specifically for AI (EU AI Act, FCA Consumer Duty, US state regulations). A company operating in these domains with weak controls (control_governance: 2–3) and no published compliance posture is a regulatory enforcement risk for the insured: and potentially a coverage trigger.


Use the rationale for narrative underwriting

The rationale field for each dimension contains the specific evidence the AI used. This is structured for an underwriter to use directly:

result = client.scan_and_wait("Acme AI", "https://acme.ai")
assessment = result["risk_assessment"]
 
print("=== UNDERWRITING SUMMARY ===")
print(f"Overall: {assessment['overall_risk_level']}")
print()
 
dimensions = [
    ("ai_intensity", "AI Intensity"),
    ("autonomy", "Autonomy"),
    ("domain_risk", "Domain Risk"),
    ("blast_radius", "Blast Radius"),
    ("data_content_ip_risk", "Data Risk"),
    ("control_governance", "Control & Governance"),
]
 
for key, label in dimensions:
    dim = assessment[key]
    print(f"{label}: {dim['score']}: {dim['label']}")
    print(f"  {dim['rationale']}")
    print()
 
print(f"Regulatory Exposure:")
print(f"  {assessment['regulatory_exposure']}")

Use matched incidents as a sanity check

Matched incidents tell you what has gone wrong with comparable companies. A similarity_score above 0.80 means the incident is closely analogous. Use them to:

  • Ask targeted application questions ("We see that similar systems have faced bias claims: do you conduct regular fairness audits?")
  • Set appropriate exclusions ("Exclusion for regulatory fines arising from automated decision-making in excess of £50,000")
  • Brief your risk engineer on what to look for in a site visit

Worked example: two companies, different profiles

Company A: Low concern

ai_intensity:       2  (AI-Enhanced)
autonomy:           1  (Human-on-the-Loop)
domain_risk:        1  (Moderate)
blast_radius:       1  (Limited)
data_content_risk:  1  (Basic Personal Data)
control_governance: 1  (Adequate)
overall:            Low

Interpretation: AI is a feature, not the product. A human reviews outputs before they matter. The domain is not particularly sensitive. A standard tech E&O policy with AI language is likely appropriate with no special conditions.


Company B: High concern

ai_intensity:       4  (Autonomous Core)
autonomy:           3  (Fully Autonomous)
domain_risk:        3  (High: insurance claims decisions)
blast_radius:       2  (Medium: 40,000 users/month)
data_content_risk:  2  (Medium: medical records)
control_governance: 2  (Partial: review only above £10k)
overall:            High

Interpretation: This is a company where the AI is the product and operates without meaningful human oversight on most decisions. The domain (insurance claims) means errors are not just inconvenient: they carry direct financial and regulatory consequences. Possible underwriting responses:

  • Require an independent AI audit as a condition of coverage
  • Sub-limit for regulatory fines arising from automated decisions
  • Require the insured to implement human review below a defined threshold
  • Request evidence of bias testing and model monitoring

Exporting risk scores to your system

If you are integrating scan results into a policy management or triage system, map the dimension scores directly:

def map_to_internal_triage(scan_result):
    assessment = scan_result["risk_assessment"]
    return {
        "exona_scan_id": scan_result.get("id"),
        "overall_risk": assessment["overall_risk_level"],
        "ai_intensity_score": assessment["ai_intensity"]["score"],
        "autonomy_score": assessment["autonomy"]["score"],
        "domain_risk_score": assessment["domain_risk"]["score"],
        "blast_radius_score": assessment["blast_radius"]["score"],
        "data_risk_score": assessment["data_content_ip_risk"]["score"],
        "governance_score": assessment["control_governance"]["score"],
        "regulatory_summary": assessment["regulatory_exposure"],
        "incident_count": len(scan_result.get("matched_incidents", [])),
        "top_incident_similarity": (
            scan_result["matched_incidents"][0]["similarity_score"]
            if scan_result.get("matched_incidents")
            else None
        ),
        "data_as_of": scan_result["data_freshness"]["sources_last_checked"],
    }