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

OpenFGA Dynamic Contextual Tuple Circular Traversal and Recursion Boundary Invariant

Enforces strict structural validation, cycle detection, and hard traversal depth limits on dynamic contextual tuples injected into OpenFGA Check and Expand calls. Unbounded contextual graph expansion can induce path combinatorial explosions, circular reference deadlocks, and worker thread exhaustion in authorization engines.

Prohibited Anti-Pattern: Injecting unvalidated, cyclic dynamic contextual tuples without deterministic recursion boundaries into OpenFGA authorization checks

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: OpenFGA Dynamic Contextual Tuple Circular Traversal and Recursion Boundary Invariant - Enforces strict structural validation, cycle detection, and hard traversal depth limits on dynamic contextual tuples injected into OpenFGA Check and Expand calls. Unbounded contextual graph expansion can induce path combinatorial explosions, circular reference deadlocks, and worker thread exhaustion in authorization engines.
globs: src/**/authz/**/*.ts, src/**/fga/**/*.ts, src/**/permissions/**/*.ts, src/**/guards/**/*.ts
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/openfga-contextual-tuple-circular-traversal-boundary"
---

# OpenFGA Dynamic Contextual Tuple Circular Traversal and Recursion Boundary Invariant

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Injecting unvalidated, cyclic dynamic contextual tuples without deterministic recursion boundaries into OpenFGA authorization checks

## System Constraints
You are a Principal Software Architect enforcing authorization safety invariants for OpenFGA implementations. You must ensure that dynamic contextual tuples passed to OpenFGA Check and ListObjects operations are rigorously sanitized, cycle-free, bounded in total count, and restricted by a maximum relation traversal depth to prevent denial-of-service via algorithmic complexity attacks.

## Strict Guidelines
- Engineers MUST ALWAYS validate dynamic contextual tuples against an in-memory Directed Acyclic Graph (DAG) cycle checker before transmitting to the OpenFGA client.
- Engineers MUST NOT allow client-supplied or dynamically computed contextual tuples to exceed an explicit cardinality threshold (MAX_CONTEXTUAL_TUPLES <= 20).
- Services MUST enforce an explicit execution timeout (e.g., max 250ms) and configure OpenFGA's maxResolutionDepth (or request-level context deadline) to stop pathological graph expansions.
- Engineers MUST NEVER permit self-referencing contextual tuples (where user === object and relation matches a transitive definition) into an evaluation payload.
- Code SHOULD sanitize and deduplicate all contextual tuples using a deterministic set identity key format: `user#relation@object`.

## Bad vs Good Implementations
### Unsanitized Contextual Tuple Injection vs. Depth-Bounded Cycle-Guarded Evaluation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Contextual tuples are passed directly from the request context into OpenFGA without depth limiting, size limits, or cycle validation. Malicious or malformed inputs can define cyclic parent-child or group-membership edges that exhaust FGA resolution limits and block execution threads.
```typescript
import { OpenFgaClient } from '@openfga/sdk';

interface ClientRequestContext {
  dynamicRelations: Array<{ user: string; relation: string; object: string }>;
}

export async function evaluateAccess(
  fgaClient: OpenFgaClient,
  userId: string,
  relation: string,
  resourceId: string,
  reqCtx: ClientRequestContext
): Promise<boolean> {
  // VULNERABLE: Direct injection of untrusted, unbounded, and potentially cyclic contextual tuples.
  // A cyclic relation (e.g., folder:A parent folder:B and folder:B parent folder:A) will cause
  // deep recursive expansions, high latency spikes, and worker thread pool starvation.
  const response = await fgaClient.check({
    user: `user:${userId}`,
    relation,
    object: `document:${resourceId}`,
    contextualTuples: reqCtx.dynamicRelations
  });

  return response.allowed ?? false;
}
```

#### Production Standard (Correct)
> **Standard**: Implements defense-in-depth: caps contextual tuple counts to a strict ceiling, deduplicates inputs, uses DFS recursion tracking to fail fast on cycles or excessive hierarchy depth prior to engine dispatch, and configures OpenFGA client options (maxResolutionDepth and timeoutMillis) to bound server-side graph traversal.
```typescript
import { OpenFgaClient, ClientCheckRequest } from '@openfga/sdk';

const MAX_CONTEXTUAL_TUPLES = 20;
const MAX_TRAVERSAL_DEPTH = 5;

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

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

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

function validateNoCycles(tuples: TupleKey[]): void {
  const adj = new Map<string, string[]>();
  for (const t of tuples) {
    if (t.user === t.object) {
      throw new CycleDetectedError(`Self-referential tuple rejected: ${t.user}`);
    }
    const neighbors = adj.get(t.object) ?? [];
    neighbors.push(t.user);
    adj.set(t.object, neighbors);
  }

  const visited = new Set<string>();
  const recStack = new Set<string>();

  function dfs(node: string, depth: number): void {
    if (depth > MAX_TRAVERSAL_DEPTH) {
      throw new CycleDetectedError(`Max traversal depth exceeded (${MAX_TRAVERSAL_DEPTH})`);
    }
    visited.add(node);
    recStack.add(node);

    for (const neighbor of adj.get(node) ?? []) {
      if (!visited.has(neighbor)) {
        dfs(neighbor, depth + 1);
      } else if (recStack.has(neighbor)) {
        throw new CycleDetectedError(`Cycle detected at boundary: ${node} -> ${neighbor}`);
      }
    }
    recStack.delete(node);
  }

  for (const node of adj.keys()) {
    if (!visited.has(node)) {
      dfs(node, 1);
    }
  }
}

export async function evaluateAccessSecure(
  fgaClient: OpenFgaClient,
  userId: string,
  relation: string,
  resourceId: string,
  rawTuples: TupleKey[]
): Promise<boolean> {
  if (rawTuples.length > MAX_CONTEXTUAL_TUPLES) {
    throw new ContextualTupleLimitExceededError(`Exceeded maximum allowed contextual tuples: ${MAX_CONTEXTUAL_TUPLES}`);
  }

  // Deduplicate and validate acyclic boundary
  const uniqueTuples = Array.from(
    new Map(rawTuples.map(t => [`${t.user}#${t.relation}@${t.object}`, t])).values()
  );
  validateNoCycles(uniqueTuples);

  const checkPayload: ClientCheckRequest = {
    user: `user:${userId}`,
    relation,
    object: `document:${resourceId}`,
    contextualTuples: uniqueTuples
  };

  const response = await fgaClient.check(checkPayload, {
    maxResolutionDepth: MAX_TRAVERSAL_DEPTH,
    timeoutMillis: 250
  });

  return response.allowed ?? false;
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: OpenFGA Dynamic Contextual Tuple Circular Traversal and Recursion Boundary Invariant

OpenFGA Dynamic Contextual Tuple Circular Traversal and Recursion Boundary Invariant defines an industrial-grade behavioral standard for security engineering. Enforces strict structural validation, cycle detection, and hard traversal depth limits on dynamic contextual tuples injected into OpenFGA Check and Expand calls. Unbounded contextual graph expansion can induce path combinatorial explosions, circular reference deadlocks, and worker thread exhaustion in authorization engines. 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: Injecting unvalidated, cyclic dynamic contextual tuples without deterministic recursion boundaries into OpenFGA authorization checks 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 DriftInjecting unvalidated, cyclic dynamic contextual tuples without deterministic recursion boundaries into OpenFGA authorization checksCritical
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 dynamic contextual tuples against an in-memory Directed Acyclic Graph (DAG) cycle checker before transmitting to the OpenFGA client.

Engineers MUST ALWAYS validate dynamic contextual tuples against an in-memory Directed Acyclic Graph (DAG) cycle checker before transmitting to the OpenFGA client.

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 allow client-supplied or dynamically computed contextual tuples to exceed an explicit cardinality threshold (MAX_CONTEXTUAL_TUPLES <= 20).

Engineers MUST NOT allow client-supplied or dynamically computed contextual tuples to exceed an explicit cardinality threshold (MAX_CONTEXTUAL_TUPLES <= 20).

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 an explicit execution timeout (e.g., max 250ms) and configure OpenFGA's maxResolutionDepth (or request-level context deadline) to stop pathological graph expansions.

Services MUST enforce an explicit execution timeout (e.g., max 250ms) and configure OpenFGA's maxResolutionDepth (or request-level context deadline) to stop pathological graph expansions.

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

Engineers MUST NEVER permit self-referencing contextual tuples (where user === object and relation matches a transitive definition) into an evaluation payload.

Engineers MUST NEVER permit self-referencing contextual tuples (where user === object and relation matches a transitive definition) into an evaluation payload.

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

Code SHOULD sanitize and deduplicate all contextual tuples using a deterministic set identity key format

Code SHOULD sanitize and deduplicate all contextual tuples using a deterministic set identity key format: `user#relation@object`.

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 Dynamic Contextual Tuple Circular Traversal and Recursion Boundary Invariant critical for AI coding assistants?

Enforces strict structural validation, cycle detection, and hard traversal depth limits on dynamic contextual tuples injected into OpenFGA Check and Expand calls. Unbounded contextual graph expansion can induce path combinatorial explosions, circular reference deadlocks, and worker thread exhaustion in authorization engines. 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 (Injecting unvalidated, cyclic dynamic contextual tuples without deterministic recursion boundaries into OpenFGA authorization checks) 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