Skip to main content

Unsafe Mutation Exposure Detection

Unsafe mutation exposure occurs when a write, delete, or mutate operation is annotated without adequate safety metadata — exposing the operation to unchecked agent execution.

Why It Matters

When an agent discovers a mutation operation without safety constraints, it may:

  • Execute destructive actions without confirmation
  • Trigger financial transactions without approval
  • Modify shared state without tenant boundaries
  • Invoke non-idempotent operations multiple times

These scenarios represent real production risk.

What Constitutes "Unsafe Exposure"

A mutation is considered unsafely exposed when any of these conditions are true:

ConditionRisk
action-type is write or delete but no risk-levelAgent cannot assess risk
risk-level is high or critical but confirmation-required is false or missingDangerous action without human check
action-type is delete but no preconditionsNo guard against invalid deletion
action-type is write with financial side effects but no approval-requiredFinancial risk without governance
idempotent is false or missing with no side-effects declarationAgent cannot predict consequences
scope is missing on tenant-sensitive mutationsCross-tenant data corruption risk

Detection Rules

AXAG-LINT-003: Unsafe Mutate Without Confirmation

Rule: AXAG-LINT-003
Severity: Error
Message: Mutation operation with risk-level high/critical lacks confirmation requirement
Fix: Add axag-confirmation-required="true"

Failing example:

❌ Unsafe — no confirmation on critical delete
<button
axag-intent="account.delete"
axag-entity="account"
axag-action-type="delete"
axag-risk-level="critical"
>Delete Account</button>

Passing example:

✅ Safe — full safety metadata
<button
axag-intent="account.delete"
axag-entity="account"
axag-action-type="delete"
axag-risk-level="critical"
axag-confirmation-required="true"
axag-preconditions='["no active subscriptions"]'
axag-postconditions='["account deactivated","data retention started"]'
axag-idempotent="true"
>Delete Account</button>

AXAG-LINT-008: Delete Without Preconditions

Rule: AXAG-LINT-008
Severity: Warning
Message: Delete operation has no preconditions declared
Fix: Add axag-preconditions with state requirements

AXAG-LINT-009: Financial Mutation Without Approval

Rule: AXAG-LINT-009
Severity: Error
Message: Mutation with financial side effects lacks approval requirement
Fix: Add axag-approval-required="true" and axag-approval-roles

Example — financial mutation:

<button
axag-intent="refund.process"
axag-entity="refund"
axag-action-type="write"
axag-required-parameters='["order_id","amount"]'
axag-risk-level="high"
axag-side-effects='["payment_refund","accounting_adjustment"]'
axag-confirmation-required="true"
axag-approval-required="true"
axag-approval-roles='["finance_manager"]'
axag-scope="tenant"
axag-idempotent="true"
>Process Refund</button>

AXAG-LINT-017: Missing Side Effects Declaration

Rule: AXAG-LINT-017
Severity: Warning
Message: Non-idempotent mutation has no side-effects declared
Fix: Add axag-side-effects listing observable state changes

Risk-Level Enforcement Matrix

Action TypeMinimum Required Safety Metadata
readNone (risk should be none or low)
write (low risk)risk-level
write (medium risk)risk-level, confirmation-required
write (high risk)risk-level, confirmation-required, preconditions
deleterisk-level, confirmation-required, preconditions
delete (critical)All of above + approval-required, approval-roles

CI Integration

- name: Check for unsafe mutations
run: npx axag-lint --rules unsafe-mutations --format=github

Next Steps