Skip to main content

Risk Acceptance

Overview

Risk Acceptance allows you to formally acknowledge that certain security controls are not detected — and that this is an accepted risk rather than a gap to fix.

Accepting Risk

  1. In the Execution Table or Defense Score breakdown, find the unprotected control
  2. Click the Accept Risk button on the row
  3. Choose the scope using the toggle:
    • All Hosts (default) — excludes the test/control from Defense Score across the entire organization
    • This Host Only — scopes the exclusion to the specific hostname where the failure occurred
  4. Provide a justification (required)
  5. The control is marked as "Risk Accepted" and excluded from the Defense Score calculation

Risk acceptance dialog — justification form with scope selection over the executions table

Audit Trail

All risk acceptance decisions are tracked with:

  • Who accepted the risk (Clerk user ID)
  • When the decision was made
  • Why (the justification provided)

Revoking Acceptance

Risk acceptance can be revoked at any time, which returns the control to the "Unprotected" category and recalculates the Defense Score.

Acceptance Scope

The Accept Risk dialog provides a scope toggle with two options:

ScopeBehaviorExample Use Case
All Hosts (global)Excludes the test/control from Defense Score across all endpointsA test that triggers false positives everywhere, or a CIS control that conflicts with business requirements
This Host Only (host)Excludes only on the specific hostname where the failure occurredA legacy server that cannot be patched, while other endpoints should still be tracked

The hostname is always stored for audit trail regardless of scope. When choosing scope, prefer This Host Only unless the business justification applies organization-wide.

Legacy Records

Risk acceptances created before the scope toggle was added fall back to current behavior: records with a hostname are treated as host-scoped, records without are treated as global.

Risk Scoring Model

Accepted risks are excluded from the Defense Score calculation through an Elasticsearch exclusion filter. The flow works as follows:

The exclusion filter generates Elasticsearch must_not clauses that match the test_name, control_id, and hostname fields of each active acceptance. This means:

  • Accepted tests no longer count as "Unprotected" in the Defense Score
  • Heatmap cells for accepted risks show a distinct visual state
  • Treemap tiles for accepted controls are grouped separately
Performance

Active acceptances are cached in memory for 60 seconds to avoid hitting Elasticsearch on every Defense Score query. The cache is automatically invalidated when a new acceptance is created or revoked.

Heatmap Integration

Accepted risks appear as a distinct state in the MITRE ATT&CK heatmap:

Heatmap ColorMeaning
GreenProtected (test passed)
RedUnprotected (test failed)
Yellow/AmberRisk Accepted (excluded from scoring)
GrayNot tested

This visual distinction ensures that accepted risks are visible to the team without inflating the "unprotected" count.

Acceptance Workflow

The full lifecycle of a risk acceptance:

Data Model

Each risk acceptance is stored as an immutable document in the achilles-risk-acceptances Elasticsearch index:

FieldTypeDescription
acceptance_idkeywordUnique UUID
test_namekeywordSecurity test name
control_idkeywordBundle control ID (optional)
hostnamekeywordTarget hostname (always stored for audit)
scopekeywordglobal (all hosts) or host (this host only)
justificationtextBusiness justification (required)
accepted_bykeywordClerk user ID
accepted_by_namekeywordDisplay name
accepted_atdateISO timestamp
statuskeywordactive or revoked
revoked_atdateRevocation timestamp (if revoked)
revoked_bykeywordRevoker user ID (if revoked)
revoked_by_namekeywordRevoker display name (if revoked)
revocation_reasontextReason for revocation (if revoked)
Immutable Records

Revoking an acceptance does not delete the original record. Instead, the document is updated with status: 'revoked' and the revocation metadata fields are populated. This preserves the complete audit trail for compliance reporting.

Audit Trail

The audit trail captures every risk decision with full context:

  • Who accepted or revoked the risk (Clerk user ID and display name)
  • When the action was taken (ISO timestamp)
  • What was accepted (test name, control ID, hostname)
  • Why the decision was made (justification or revocation reason)

Use the Risk Acceptances table in the Analytics dashboard to review all active and historical acceptances. Filter by status (active / revoked), test name, or date range.