This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
securitycritical PriorityID: openfga-rebac-depth-limiting-standard

OpenFGA Recursive Tuple Graph Depth Limiting and Cycle Prevention Standard

Enforces strict invariants on OpenFGA authorization models and query evaluators to mitigate denial-of-service (DoS) and thread starvation caused by unbounded transitive evaluation and circular tuple hierarchies. Mandates pre-write cycle validation on directed acyclic graph (DAG) hierarchies, deterministic execution timeouts with circuit-breaking on OpenFGA client checks, and strict resolution depth constraints in both model configuration and test suites.

Prohibited Anti-Pattern: Unbounded Transitive ReBAC Evaluation and Unvalidated Cyclic Tuple Ingestion

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: OpenFGA Recursive Tuple Graph Depth Limiting and Cycle Prevention Standard - Enforces strict invariants on OpenFGA authorization models and query evaluators to mitigate denial-of-service (DoS) and thread starvation caused by unbounded transitive evaluation and circular tuple hierarchies. Mandates pre-write cycle validation on directed acyclic graph (DAG) hierarchies, deterministic execution timeouts with circuit-breaking on OpenFGA client checks, and strict resolution depth constraints in both model configuration and test suites.
globs: src/**/*.{ts,tsx}, src/auth/**/*.{ts,js}, fga/**/*.fga, fga/**/model.json, fga/**/tests.yaml
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/openfga-rebac-depth-limiting-standard"
---

# OpenFGA Recursive Tuple Graph Depth Limiting and Cycle Prevention Standard

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Unbounded Transitive ReBAC Evaluation and Unvalidated Cyclic Tuple Ingestion

## System Constraints
You are a Principal Software Architect enforcing the OpenFGA Recursive Tuple Graph Depth Limiting Standard. Your directive is to guarantee that all relationship-based access control (ReBAC) evaluations, tuple writes, and model definitions remain computationally bounded and immune to graph-recursion denial-of-service attacks. Prohibit any OpenFGA queries executed without strict client-side timeouts and abort controllers. Reject any tuple write for transitive relations (such as parent-child folders or nested group memberships) that bypasses pre-write cycle detection. Ensure all OpenFGA error handling specifically isolates depth evaluation exceptions without leaking server internals or exhausting thread pools.

## Strict Guidelines
- Engineers MUST ALWAYS implement pre-write cycle detection before inserting transitive hierarchical tuples (e.g., 'group:A#member -> group:B' or 'folder:X#parent -> folder:Y') to ensure the authorization graph remains a strict Directed Acyclic Graph (DAG).
- Engineers MUST NEVER execute OpenFGA client evaluation methods (e.g., 'check', 'expand', 'listObjects') without passing an explicit 'AbortSignal' bounded to a maximum timeout threshold (maximum 1500ms).
- Code MUST explicitly catch and isolate OpenFGA evaluation depth exceeded errors (HTTP 400 with 'FgaApiValidationError' or internal code matching evaluation depth limits), logging security alerts and failing closed to 'allowed: false' rather than rethrowing unhandled server errors.
- Services MUST limit the quantity of 'contextual_tuples' supplied in a single authorization evaluation to a strictly validated maximum (never exceeding 25 tuples per request) to prevent memory ballooning during graph expansion.
- OpenFGA authorization models MUST NOT define deeply recursive, multi-hop 'from' relationships across more than 3 continuous indirections without dedicated materialization or architectural depth boundaries.
- Engineers MUST validate model recursion depth limits using 'fga model test' with explicit negative tests containing circular relations to confirm engine-level cycle termination.

## Bad vs Good Implementations
### Cyclic Transitive Tuple Write vs. Guarded DAG Cycle-Check and Timed Evaluation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The code writes nested relationship tuples without checking if the child group is an ancestor of the parent group, allowing cyclic graphs. Furthermore, the check evaluation executes without an AbortSignal timeout, causing worker threads to hang or spin CPU when navigating deep or circular graphs.
```typescript
import { OpenFgaClient } from '@openfga/sdk';

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

// ANTI-PATTERN: Direct tuple write without cycle detection allows infinite recursive
// loops (e.g., group:A contains group:B contains group:A). Evaluation lacks timeout limits.
export async function addNestedGroup(parentGroupId: string, childGroupId: string): Promise<void> {
  await fgaClient.writeTuples([{
    user: `group:${childGroupId}#member`,
    relation: 'member',
    object: `group:${parentGroupId}`,
  }]);
}

export async function checkGroupAccess(userId: string, groupId: string): Promise<boolean> {
  // ANTI-PATTERN: No AbortSignal timeout, unconstrained evaluation depth can hang workers.
  const response = await fgaClient.check({
    user: `user:${userId}`,
    relation: 'member',
    object: `group:${groupId}`,
  });
  return response.allowed ?? false;
}
```

#### Production Standard (Correct)
> **Standard**: The solution prevents graph cycles before writing by validating the reverse relationship, enforces an AbortSignal timeout on both writes and checks, and handles FGA validation and timeout errors by safely failing closed.
```typescript
import { OpenFgaClient, FgaApiValidationError } from '@openfga/sdk';

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

const EVALUATION_TIMEOUT_MS = 1000;
const MAX_CONTEXTUAL_TUPLE_LIMIT = 20;

export class AuthorizationGraphCycleError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'AuthorizationGraphCycleError';
  }
}

// Cycle detection: Verify child is not already an ancestor of parent before linking
async function assertNoCycleExists(
  parentGroupId: string,
  childGroupId: string,
  signal: AbortSignal
): Promise<void> {
  const reverseCheck = await fgaClient.check({
    user: `group:${parentGroupId}#member`,
    relation: 'member',
    object: `group:${childGroupId}`,
  }, { signal });

  if (reverseCheck.allowed) {
    throw new AuthorizationGraphCycleError(
      `Cycle detected: cannot make group:${childGroupId} a member of group:${parentGroupId}`
    );
  }
}

export async function addNestedGroup(parentGroupId: string, childGroupId: string): Promise<void> {
  if (parentGroupId === childGroupId) {
    throw new AuthorizationGraphCycleError('Self-referencing relationship rejected.');
  }

  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), EVALUATION_TIMEOUT_MS);

  try {
    await assertNoCycleExists(parentGroupId, childGroupId, controller.signal);
    await fgaClient.writeTuples([{
      user: `group:${childGroupId}#member`,
      relation: 'member',
      object: `group:${parentGroupId}`,
    }], { signal: controller.signal });
  } finally {
    clearTimeout(timeout);
  }
}

export async function checkGroupAccess(userId: string, groupId: string): Promise<boolean> {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), EVALUATION_TIMEOUT_MS);

  try {
    const response = await fgaClient.check({
      user: `user:${userId}`,
      relation: 'member',
      object: `group:${groupId}`,
    }, {
      signal: controller.signal,
    });
    return response.allowed ?? false;
  } catch (error: unknown) {
    if (error instanceof Error && error.name === 'AbortError') {
      // Fail closed upon evaluation timeout
      return false;
    }
    if (error instanceof FgaApiValidationError) {
      // Evaluation depth exceeded or invalid graph structure fails closed
      return false;
    }
    throw error;
  } finally {
    clearTimeout(timeout);
  }
}
```

Recommended MCP Servers (mcp-serverlist.com)

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

Architectural Specification & Invariant Rationale

Architectural Invariant Design: OpenFGA Recursive Tuple Graph Depth Limiting and Cycle Prevention Standard

OpenFGA Recursive Tuple Graph Depth Limiting and Cycle Prevention Standard defines an industrial-grade behavioral standard for security engineering. Enforces strict invariants on OpenFGA authorization models and query evaluators to mitigate denial-of-service (DoS) and thread starvation caused by unbounded transitive evaluation and circular tuple hierarchies. Mandates pre-write cycle validation on directed acyclic graph (DAG) hierarchies, deterministic execution timeouts with circuit-breaking on OpenFGA client checks, and strict resolution depth constraints in both model configuration and test suites. 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: Unbounded Transitive ReBAC Evaluation and Unvalidated Cyclic Tuple Ingestion 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 DriftUnbounded Transitive ReBAC Evaluation and Unvalidated Cyclic Tuple IngestionCritical
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 implement pre-write cycle detection before inserting transitive hierarchical tuples (e.g., 'group

Engineers MUST ALWAYS implement pre-write cycle detection before inserting transitive hierarchical tuples (e.g., 'group:A#member -> group:B' or 'folder:X#parent -> folder:Y') to ensure the authorization graph remains a strict Directed Acyclic Graph (DAG).

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 NEVER execute OpenFGA client evaluation methods (e.g., 'check', 'expand', 'listObjects') without passing an explicit 'AbortSignal' bounded to a maximum timeout threshold (maximum 1500ms).

Engineers MUST NEVER execute OpenFGA client evaluation methods (e.g., 'check', 'expand', 'listObjects') without passing an explicit 'AbortSignal' bounded to a maximum timeout threshold (maximum 1500ms).

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

Code MUST explicitly catch and isolate OpenFGA evaluation depth exceeded errors (HTTP 400 with 'FgaApiValidationError' or internal code matching evaluation depth limits), logging security alerts and failing closed to 'allowed

Code MUST explicitly catch and isolate OpenFGA evaluation depth exceeded errors (HTTP 400 with 'FgaApiValidationError' or internal code matching evaluation depth limits), logging security alerts and failing closed to 'allowed: false' rather than rethrowing unhandled server errors.

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 limit the quantity of 'contextual_tuples' supplied in a single authorization evaluation to a strictly validated maximum (never exceeding 25 tuples per request) to prevent memory ballooning during graph expansion.

Services MUST limit the quantity of 'contextual_tuples' supplied in a single authorization evaluation to a strictly validated maximum (never exceeding 25 tuples per request) to prevent memory ballooning during graph expansion.

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

OpenFGA authorization models MUST NOT define deeply recursive, multi-hop 'from' relationships across more than 3 continuous indirections without dedicated materialization or architectural depth boundaries.

OpenFGA authorization models MUST NOT define deeply recursive, multi-hop 'from' relationships across more than 3 continuous indirections without dedicated materialization or architectural depth boundaries.

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.
6

Engineers MUST validate model recursion depth limits using 'fga model test' with explicit negative tests containing circular relations to confirm engine-level cycle termination.

Engineers MUST validate model recursion depth limits using 'fga model test' with explicit negative tests containing circular relations to confirm engine-level cycle termination.

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 Recursive Tuple Graph Depth Limiting and Cycle Prevention Standard critical for AI coding assistants?

Enforces strict invariants on OpenFGA authorization models and query evaluators to mitigate denial-of-service (DoS) and thread starvation caused by unbounded transitive evaluation and circular tuple hierarchies. Mandates pre-write cycle validation on directed acyclic graph (DAG) hierarchies, deterministic execution timeouts with circuit-breaking on OpenFGA client checks, and strict resolution depth constraints in both model configuration and test suites. 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 (Unbounded Transitive ReBAC Evaluation and Unvalidated Cyclic Tuple Ingestion) 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