This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
securitycritical PriorityID: openfga-contextual-tuple-cycle-guardrail

OpenFGA 1.8 Contextual Tuple Cycle and Recursion DoS Prevention

Enforces strict validation, topological cycle pre-checks, and cardinality bounds on dynamic contextual tuples passed into OpenFGA Check and ListObjects operations. Prevents graph recursion loops, depth-exhaustion denial of service (DoS), and unbounded Zanzibar subproblem expansion.

Prohibited Anti-Pattern: Blind forwarding of unvalidated contextual tuples enabling cyclic graph recursion and authorization engine denial of service

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: OpenFGA 1.8 Contextual Tuple Cycle and Recursion DoS Prevention - Enforces strict validation, topological cycle pre-checks, and cardinality bounds on dynamic contextual tuples passed into OpenFGA Check and ListObjects operations. Prevents graph recursion loops, depth-exhaustion denial of service (DoS), and unbounded Zanzibar subproblem expansion.
globs: src/**/*.{ts,tsx}, lib/**/*.{ts,tsx}, services/**/*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/openfga-contextual-tuple-cycle-guardrail"
---

# OpenFGA 1.8 Contextual Tuple Cycle and Recursion DoS Prevention

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Blind forwarding of unvalidated contextual tuples enabling cyclic graph recursion and authorization engine denial of service

## System Constraints
You are a Principal Engineer enforcing the OpenFGA 1.8 Contextual Tuple Cycle Detection Standard. Mandate that all dynamically supplied ephemeral relationship tuples are bounded, topologically verified for acyclicity, and handled fail-closed to prevent algorithmic complexity attacks against Zanzibar authorization resolution engines.

## Strict Guidelines
- Engineers MUST ALWAYS validate that contextual tuples form a strict Directed Acyclic Graph (DAG) before forwarding them to OpenFGA client SDK calls.
- Engineers MUST NOT forward raw, client-supplied relation tuples directly into `contextualTuples` of `check`, `expand`, or `listObjects` calls.
- Services MUST enforce strict hard limits on the maximum number of contextual tuples allowed per request (e.g., maximum 10-20 tuples).
- Services MUST handle OpenFGA cyclic evaluation and resolution depth limit errors fail-closed, returning explicit 403 Forbidden rather than leaking engine traversal states or falling back to permissive defaults.
- Components NEVER allow client-controlled contextual tuples targeting self-referential or transitive relations (e.g., `parent`, `member`, `contains`) without server-side tenancy boundary checks.

## Bad vs Good Implementations
### Contextual Tuple Validation and Cycle Detection Guardrail

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Directly feeding client-supplied tuples into contextualTuples allows attackers to construct arbitrary cycles across transitive hierarchies (like parent-child folder graphs). This causes the OpenFGA query planner to expend maximum resolution depth or fail with unhandled internal errors, inducing CPU exhaustion and availability loss.
```typescript
import { OpenFgaClient } from '@openfga/sdk';
import { Request, Response } from 'express';

const fgaClient = new OpenFgaClient({
  apiUrl: process.env.FGA_API_URL!,
  storeId: process.env.FGA_STORE_ID!,
});

export async function authorizeDocumentAccess(req: Request, res: Response) {
  const { userId, documentId, ephemeralTuples } = req.body;

  // BAD: Untrusted ephemeral tuples forwarded directly to OpenFGA Check.
  // An attacker can send cyclical relationships (e.g., folder:A parent folder:B, folder:B parent folder:A)
  // triggering unbounded recursion or resolution depth exhaustion DoS.
  const { allowed } = await fgaClient.check({
    user: `user:${userId}`,
    relation: 'can_read',
    object: `document:${documentId}`,
    contextualTuples: ephemeralTuples,
  });

  if (!allowed) {
    return res.status(403).json({ error: 'Access denied' });
  }
  return res.status(200).json({ status: 'ok' });
}
```

#### Production Standard (Correct)
> **Standard**: Enforces a strict maximum cardinality limit, restricts allowable ephemeral relations to non-structural types, executes DFS-based cycle pre-detection to guarantee a Directed Acyclic Graph, and handles evaluation or engine cycle errors fail-closed.
```typescript
import { OpenFgaClient, ClientCheckRequest } from '@openfga/sdk';
import { Request, Response } from 'express';

const MAX_CONTEXTUAL_TUPLES = 10;
const ALLOWED_EPHEMERAL_RELATIONS = new Set(['temporary_viewer', 'approver']);

interface RawTuple {
  user: string;
  relation: string;
  object: string;
}

function validateAcyclicContextualTuples(tuples: RawTuple[]): void {
  if (tuples.length > MAX_CONTEXTUAL_TUPLES) {
    throw new Error(`Contextual tuple limit exceeded: max ${MAX_CONTEXTUAL_TUPLES}`);
  }

  const adjacency = new Map<string, string[]>();
  for (const tuple of tuples) {
    if (!ALLOWED_EPHEMERAL_RELATIONS.has(tuple.relation)) {
      throw new Error(`Forbidden ephemeral relation: ${tuple.relation}`);
    }
    const neighbors = adjacency.get(tuple.user) ?? [];
    neighbors.push(tuple.object);
    adjacency.set(tuple.user, neighbors);
  }

  // Cycle detection using DFS with recursion stack tracking
  const visited = new Set<string>();
  const inStack = new Set<string>();

  function hasCycle(node: string): boolean {
    visited.add(node);
    inStack.add(node);
    const neighbors = adjacency.get(node) ?? [];
    for (const neighbor of neighbors) {
      if (!visited.has(neighbor) && hasCycle(neighbor)) return true;
      if (inStack.has(neighbor)) return true;
    }
    inStack.delete(node);
    return false;
  }

  for (const node of adjacency.keys()) {
    if (!visited.has(node) && hasCycle(node)) {
      throw new Error('Cyclic contextual dependency detected');
    }
  }
}

export async function authorizeDocumentAccess(req: Request, res: Response, fgaClient: OpenFgaClient) {
  const { userId, documentId, ephemeralTuples = [] } = req.body;

  try {
    validateAcyclicContextualTuples(ephemeralTuples);

    const checkPayload: ClientCheckRequest = {
      user: `user:${userId}`,
      relation: 'can_read',
      object: `document:${documentId}`,
      contextualTuples: ephemeralTuples.map((t: RawTuple) => ({
        user: t.user,
        relation: t.relation,
        object: t.object,
      })),
    };

    const response = await fgaClient.check(checkPayload);
    if (!response.allowed) {
      return res.status(403).json({ error: 'Access denied' });
    }
    return res.status(200).json({ status: 'ok' });
  } catch (err: unknown) {
    // Fail closed on evaluation cycle or depth limits
    return res.status(403).json({ error: 'Authorization validation failed' });
  }
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: OpenFGA 1.8 Contextual Tuple Cycle and Recursion DoS Prevention

OpenFGA 1.8 Contextual Tuple Cycle and Recursion DoS Prevention defines an industrial-grade behavioral standard for security engineering. Enforces strict validation, topological cycle pre-checks, and cardinality bounds on dynamic contextual tuples passed into OpenFGA Check and ListObjects operations. Prevents graph recursion loops, depth-exhaustion denial of service (DoS), and unbounded Zanzibar subproblem expansion. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Blind forwarding of unvalidated contextual tuples enabling cyclic graph recursion and authorization engine denial of service Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftBlind forwarding of unvalidated contextual tuples enabling cyclic graph recursion and authorization engine denial of serviceCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS validate that contextual tuples form a strict Directed Acyclic Graph (DAG) before forwarding them to OpenFGA client SDK calls.

Engineers MUST ALWAYS validate that contextual tuples form a strict Directed Acyclic Graph (DAG) before forwarding them to OpenFGA client SDK calls.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT forward raw, client-supplied relation tuples directly into `contextualTuples` of `check`, `expand`, or `listObjects` calls.

Engineers MUST NOT forward raw, client-supplied relation tuples directly into `contextualTuples` of `check`, `expand`, or `listObjects` calls.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Services MUST enforce strict hard limits on the maximum number of contextual tuples allowed per request (e.g., maximum 10-20 tuples).

Services MUST enforce strict hard limits on the maximum number of contextual tuples allowed per request (e.g., maximum 10-20 tuples).

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Services MUST handle OpenFGA cyclic evaluation and resolution depth limit errors fail-closed, returning explicit 403 Forbidden rather than leaking engine traversal states or falling back to permissive defaults.

Services MUST handle OpenFGA cyclic evaluation and resolution depth limit errors fail-closed, returning explicit 403 Forbidden rather than leaking engine traversal states or falling back to permissive defaults.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Components NEVER allow client-controlled contextual tuples targeting self-referential or transitive relations (e.g., `parent`, `member`, `contains`) without server-side tenancy boundary checks.

Components NEVER allow client-controlled contextual tuples targeting self-referential or transitive relations (e.g., `parent`, `member`, `contains`) without server-side tenancy boundary checks.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is OpenFGA 1.8 Contextual Tuple Cycle and Recursion DoS Prevention critical for AI coding assistants?

Enforces strict validation, topological cycle pre-checks, and cardinality bounds on dynamic contextual tuples passed into OpenFGA Check and ListObjects operations. Prevents graph recursion loops, depth-exhaustion denial of service (DoS), and unbounded Zanzibar subproblem expansion. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Blind forwarding of unvalidated contextual tuples enabling cyclic graph recursion and authorization engine denial of service) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

OpenFGA