Skip to content

security

Intended Documentation

Fail-Closed Controls

Understand the fail-closed security model — how Intended behaves when services are unavailable, how defaults work, and circuit breaker behavior.

Fail-Closed Controls#

Intended operates on a fail-closed principle: when any component in the verification chain is unavailable or returns an ambiguous result, the system denies the request. No AI execution proceeds without an explicit, verified allow decision.

Fail-Closed vs. Fail-Open#

Most systems default to fail-open — if the authorization service is down, requests pass through. This prioritizes availability over security.

Intended takes the opposite approach:

ScenarioFail-Open (typical)Fail-Closed (Intended)
Policy engine unreachableAllowDeny
Decision token expiredAllow with warningDeny
Evaluation timeoutAllow with degraded loggingDeny
Unknown action typeAllow (no matching deny rule)Deny

Info

The fail-closed model means availability depends on the health of the verification chain. This is an intentional trade-off — Intended prioritizes security correctness over uptime of downstream AI services.

What Triggers a Fail-Closed Response#

The system returns a deny decision with a fail_closed reason code in the following scenarios:

Policy engine unavailable#

If the policy engine cannot be reached within the configured timeout (default: 3 seconds), the request is denied.

json
{
  "result": "deny",
  "reason": "fail_closed",
  "detail": "policy_engine_unreachable",
  "retry_after_ms": 5000
}

Evaluation timeout#

If policy evaluation exceeds the maximum duration (default: 5 seconds), the in-progress evaluation is abandoned and the request is denied.

Token signing failure#

If the decision token cannot be signed (key unavailable, HSM timeout), the evaluation result is discarded and the request is denied.

Enforcement point cannot verify#

If the enforcement point cannot validate a decision token (signature verification failure, clock skew beyond tolerance), the request is denied even if the token payload contains an "allow" result.

Circuit Breaker Behavior#

Intended implements a circuit breaker pattern to prevent cascading failures when a component is persistently unavailable.

Closed state (normal)

Requests flow through the authorization chain normally. Each failure increments a failure counter. The circuit breaker monitors the failure rate over a rolling 60-second window.

Open state (tripped)

When the failure rate exceeds the threshold (default: 50% of requests over 30 seconds), the circuit breaker trips. All subsequent requests receive an immediate deny response without attempting to reach the failing component. This reduces load on the recovering service.

Half-open state (probing)

After the cooldown period (default: 15 seconds), the circuit breaker allows a single probe request through. If the probe succeeds, the circuit breaker returns to the closed state. If the probe fails, it returns to the open state.

Circuit Breaker Configuration#

Circuit breaker thresholds are configurable per tenant:

yaml
circuit_breaker:
  failure_threshold_percent: 50
  window_seconds: 30
  cooldown_seconds: 15
  probe_count: 1

Warning

Setting failure_threshold_percent too high delays circuit breaker activation, causing request pile-ups. Setting it too low triggers false positives during normal latency spikes. The default of 50% is appropriate for most deployments.

Default Deny Semantics#

Intended uses default-deny semantics at every layer:

  • No matching policy — deny. Unlike permissive systems, the absence of a rule is not an implicit allow.
  • Ambiguous evaluation — deny. If the policy engine produces a result that is neither explicit allow nor explicit deny, the system treats it as deny.
  • Conflicting policies — deny. If multiple policies produce conflicting results for the same intent, deny takes precedence.

The Deny Hierarchy#

When multiple deny reasons apply, Intended reports the most specific one:

  1. Explicit policy deny (a rule actively denied the request)
  2. Fail-closed deny (a system component was unavailable)
  3. Default deny (no matching allow rule)

The deny hierarchy ensures that audit logs reflect the true reason for denial, which is critical for debugging and compliance.

Monitoring Fail-Closed Events#

Fail-closed events emit structured metrics and audit records. Key metrics to monitor:

MetricDescription
meritt.authorization.fail_closed.totalTotal fail-closed denials
meritt.authorization.fail_closed.by_reasonDenials broken down by reason code
meritt.circuit_breaker.stateCurrent state of each circuit breaker
meritt.circuit_breaker.tripsNumber of times the circuit breaker has tripped

Alerting Recommendations#

  • Alert on fail_closed.total exceeding baseline by 2x within 5 minutes
  • Alert immediately on circuit_breaker.state transitioning to open
  • Alert on sustained half_open state lasting longer than 60 seconds

Overriding Fail-Closed (Emergency Access)#

Danger

Intended does not provide a global fail-open override. This is by design. An override mechanism would become the target of every attack against the system.

For emergency scenarios, operators can:

  1. Deploy a permissive policy — create and activate a broad-allow policy through the standard policy pipeline. This is audited and reversible.
  2. Bypass at the connector level — individual connectors can be configured with a static allow list for specific actions. This requires operator-level access and produces a security audit event.
  3. Scale the failing component — address the root cause rather than bypassing authorization.