# Exposed — Diamond Recursion CWE-407 Scan: CLEAN

**Pattern:** Recursive cycle/reachability without visited set (O(2^D) on diamond DAGs)
**Scan date:** 2026-03-29
**Scope:** `exposed-core/src/`, `exposed-jdbc/src/`, `exposed-r2dbc/src/`

## Method

Searched for `isCyclic`, `hasCycle`, `createsCycle`, `isReachable`, `canReach`,
`hasPath`, `detectCycle` across all Kotlin sources. Examined each recursive
function for missing visited-accumulator parameters.

## Key candidates reviewed

### `TableDepthGraph.hasCycle()`
`exposed-core/src/.../core/TableDepthGraph.kt` line 44.

Uses two mutable sets: `visited` and `recursion`. Both are `mutableSetOf<Table>()`.
The `recursion` set tracks the current DFS path (IN_PROGRESS nodes); `visited`
tracks completed nodes. Recursive `traverse()` checks both before proceeding.
Classic 3-state DFS cycle detection. CLEAN.

### `TableDepthGraph.sorted()`
`exposed-core/src/.../core/TableDepthGraph.kt` line 25.

Uses `visited: mutableSetOf<Table>()`. Recursive `traverse()` checks
`if (table !in visited)` before visiting. CLEAN.

### `fetchAllTables()`
`exposed-core/src/.../core/TableDepthGraph.kt` line 14.

Uses `result = HashSet<Table>()`. Recursive `parseTable()` checks
`if (result.add(table))` — the Set itself is the visited guard. CLEAN.

## Verdict

CLEAN for diamond recursion pattern. All table dependency graph traversals use
proper visited sets (mutableSetOf or HashSet). No unprotected recursive DAG
traversal found.
