新功能: 智能体审批、红队测试与模型扫描。 了解详情
Docs / 合规与洞察 / AI Risk Register

AI Risk Register

The risk register is where identified AI risks are written down: which agent or program they concern, how likely and how severe they are before and after mitigation, who owns them, what is relied on to mitigate them, and — where the organization decides to live with one — why.

Every entry keys on the shared risk catalog: bias, fairness, robustness, privacy, security, transparency, accountability, human oversight and safety. The same vocabulary is used by the framework libraries and by the governance assessment, which is what lets an assessment answer seed the register and a control cite a risk.

Scores

Likelihood and impact are each rated from 1 (lowest) to 5 (highest), inherent and residual. The score is likelihood × impact, computed by MITRITY when a row is saved; it cannot be typed, so the register, the API and every report agree about every number. The residual heat map on the page counts the entries listed below it — the current filter and page — by where their residual axes land, and the register is always sorted by residual score, highest first.

A new entry starts from the catalog's defaults for its risk class, with residual equal to inherent — nothing has been mitigated yet — and every value can be edited afterwards.

How the computed score works

Beside the residual you declare, every entry shows a computed residual: what the live signals say the risk looks like today. It is derived when the register is read — from signals at most a minute old — and again by a daily pass. It is never written into the entry and never changes the values you set. The declared score is a decision with a name on it; the computed score is an observation; a gap between them is what deserves a look.

The rule is simple enough to read off the page. Likelihood starts at the entry's inherent likelihood and moves by the steps each signal adds. Drift and DLP matches are read over the last 90 days; coverage, lifecycle and open findings as they stand now — except that lifecycle notes whether the agent acted in the window, and model findings count through the models the agent called in it:

SignalEffect on likelihood
Execution coveragegoverned −1 · partial 0 · degraded, unattested or unknown +1
Lifecycleproposed, under review or sent back +1 · approved 0 · blocked or retired with no activity in the window −1 · blocked or retired but still acting in the window +1
Drift+1 when the agent's average drift score reaches 0.5, or at least a tenth of its actions scored above 0.5 — the anomaly line
Open findingsa critical finding +2, otherwise a high one +1 — on security, robustness, safety and privacy entries; listed for context on the others. Counted: open execution-coverage, host-observer and red-team findings, SaaS posture warnings (as medium), and open findings on the models the agent called in the window
DLP matches+1 when matches went through with only an alert — on privacy and security entries; 0 when every match was blocked or redacted

The result stays on the 1–5 scale. Impact is the residual impact you set, unchanged — what a failure would cost is a judgment no runtime signal can make. The computed residual is likelihood × impact on the same 1–25 scale, and the Signals toggle under each score lists every step with the value behind it and a link to the record. A program-level entry reads every agent together: coverage −1 when at least 80% of the agents with a coverage state are governed, +1 when 20% or more are degraded, unattested or unknown; lifecycle +1 when any agent is proposed, under review or sent back, or blocked or retired but still acting; drift over all agents' actions at once; and every agent's open findings and DLP matches.

When there is nothing to compute from — no coverage state, no actions in the window, no open findings and no DLP matches — there is no computed score, only a note saying so. An empty window is not evidence of anything. The same applies to an entry whose agent is no longer registered.

Sort the register by widest gap first to see where the declared residual sits furthest below what the signals show. When an open or mitigating entry's computed residual sits six or more points — one band on the heat map — above its declared residual, MITRITY raises a Risk register drift notification: the first time the gap appears, again whenever it has widened, and otherwise as a weekly reminder while it holds. The condition is standing — an entry that is wrong stays wrong until you update it or accept the risk — and accepting the risk is what silences it. Accepted and closed entries never notify; a computed score below the declared one never does either.

Status and acceptance

StatusMeaning
OpenIdentified, not yet being treated.
MitigatingTreatment is under way.
AcceptedThe organization has decided to live with the residual risk. Requires a justification.
ClosedNo longer a risk.

Accepting a risk is its own action, for a manager or owner, and needs a justification of at least ten characters. The note, who accepted and when are recorded with the row and written to the audit trail as compliance.risk.accepted. A closed risk cannot be accepted.

Where entries come from

  • Manual — added on the page or through the API by any member.
  • Assessment — when a governance review is approved or attested, one entry is written per risk class the answered questions touched: likelihood starts at the catalog default and moves one step up when the answers for that class scored high, impact is the catalog default, and the catalog's mitigating capabilities are attached. Entries are pinned to the review, so resolving it again does not double the register. Every seeded value is a starting point for a person, not a score MITRITY asserts.
  • Finding — opened from a finding.

A user whose access scope is scoped sees the program-level risks and the risks of the agents granted to them, and adds agent risks only for those agents. A risk about any other agent answers 404 Not Found.

Mitigating capabilities

An entry can name the MITRITY capabilities relied on to mitigate it — the audit trail, human approval holds, DLP, injection scanning, the credential broker and the others in the catalog. Naming them is what lets the register say which mitigations are actually running rather than only written down: each capability is backed by an evidence probe, the same one the frameworks page uses.

From the API

The catalog of risk classes and capabilities:

curl https://api.mitrity.com/api/v1/compliance/risk-catalog \
  -H "Authorization: Bearer mk_your-api-key"

List the register, highest residual score first, or widest gap first with sort=gap. Filters: subject_type (agent or tenant), subject_id, status, risk_slug, sort (residual or gap), limit, offset. Every entry carries computed; when the live signals cannot be read the entries are served without it and the response says signals_unavailable, and a gap sort over a very large register says truncated:

curl "https://api.mitrity.com/api/v1/compliance/risks?status=open&sort=gap&limit=50" \
  -H "Authorization: Bearer mk_your-api-key"
{
  "risks": [
    {
      "id": "6b0b7c0e-2a4d-4c8f-9a3e-1f2e3d4c5b6a",
      "subject_type": "agent",
      "subject_id": "0f1e2d3c-4b5a-4968-8776-5a4b3c2d1e0f",
      "subject_name": "triage-bot",
      "risk_slug": "privacy",
      "title": "Privacy",
      "inherent_likelihood": 4,
      "inherent_impact": 4,
      "inherent_score": 16,
      "residual_likelihood": 2,
      "residual_impact": 4,
      "residual_score": 8,
      "mitigating_capabilities": ["dlp", "credential_broker", "audit_trail"],
      "owner_name": "Ana Platform",
      "status": "mitigating",
      "source": "assessment",
      "review_id": "…",
      "created_at": "2026-09-21T14:02:11Z",
      "computed": {
        "residual_declared": 8,
        "residual_computed": 16,
        "computed_likelihood": 4,
        "computed_impact": 4,
        "gap": 8,
        "computed_at": "2026-09-24T09:00:00Z",
        "window_days": 90,
        "signals": [
          { "signal": "coverage_state", "value": "governed", "effect": -1, "summary": "Execution coverage is governed: every execution tool the runtime reported is hooked, so an action outside the mission scope is stopped rather than only seen.", "deep_link": "/app/agents/0f1e2d3c-4b5a-4968-8776-5a4b3c2d1e0f" },
          { "signal": "lifecycle_status", "value": "approved", "effect": 0, "summary": "The agent is approved.", "deep_link": "/app/agents/0f1e2d3c-4b5a-4968-8776-5a4b3c2d1e0f" },
          { "signal": "drift", "value": "0.14 average, 3% past the anomaly line", "effect": 0, "summary": "Drift is within the normal band over the last 90 days: 0.14 average, 0.61 peak, 27 of 900 actions past the anomaly line.", "deep_link": "/app/audit?agent_id=0f1e2d3c-4b5a-4968-8776-5a4b3c2d1e0f" },
          { "signal": "dlp_events", "value": "12 matched, 9 stopped", "effect": 1, "summary": "DLP matched 12 transfers in the last 90 days; 3 went through with only an alert.", "deep_link": "/app/agents/0f1e2d3c-4b5a-4968-8776-5a4b3c2d1e0f" }
        ]
      }
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0,
  "sort": "gap"
}

Add an entry (member and above). For an agent risk, subject_id names the agent; a program-level risk uses subject_type: "tenant" with no id. Omitted axes default from the catalog:

curl -X POST https://api.mitrity.com/api/v1/compliance/risks \
  -H "Authorization: Bearer mk_your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "subject_type": "agent",
    "subject_id": "0f1e2d3c-4b5a-4968-8776-5a4b3c2d1e0f",
    "risk_slug": "privacy",
    "title": "Personal data in support tickets",
    "inherent_likelihood": 4,
    "inherent_impact": 4,
    "residual_likelihood": 2,
    "residual_impact": 4,
    "mitigations": "PII patterns bound in enforce mode; credentials brokered.",
    "mitigating_capabilities": ["dlp", "credential_broker"],
    "owner_email": "ana@example.com"
  }'

Update an entry (member and above; every field optional; status moves between open, mitigating and closed):

curl -X PUT https://api.mitrity.com/api/v1/compliance/risks/6b0b7c0e-2a4d-4c8f-9a3e-1f2e3d4c5b6a \
  -H "Authorization: Bearer mk_your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"residual_likelihood": 1, "status": "mitigating"}'

Accept an entry (manager or owner):

curl -X POST https://api.mitrity.com/api/v1/compliance/risks/6b0b7c0e-2a4d-4c8f-9a3e-1f2e3d4c5b6a/accept \
  -H "Authorization: Bearer mk_your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"note": "Residual exposure is inside the agreed appetite for this review cycle."}'

Remove an entry (manager or owner):

curl -X DELETE https://api.mitrity.com/api/v1/compliance/risks/6b0b7c0e-2a4d-4c8f-9a3e-1f2e3d4c5b6a \
  -H "Authorization: Bearer mk_your-api-key"

Best practices

  • Give every entry an owner. The register counts as full evidence for the frameworks that ask for one only when every entry has an owner.
  • Let assessments seed it. Approving an agent's assessment produces the entries its answers imply; edit them rather than re-entering them.
  • Read the gap, not just the score. A declared residual well below the computed one means the mitigations you rely on are not showing up in the record — update the mitigations, or the residual, so the two agree.
  • Write the acceptance for a reader who was not in the room. The note is reproduced in reports.