# UNDF: UNDF-2026-000000441
## Classification

| Field       | Value |
|-------------|-------|
| CWE         | CWE-407 Inefficient Algorithmic Complexity |
| Severity    | HIGH |
| Component   | `src/compiler/checker.ts:13029` |
| Function    | `hasBaseType` / inner `check()` |
| Hot path    | Type narrowing (instanceof), type compatibility, union reduction — called on every `instanceof` check and every type subtype query involving class/interface hierarchies |
| Status      | PATCHED (unit test PASS) |

## Defect

`hasBaseType` contains an inner recursive function `check()` that traverses
the class/interface base-type graph with **no visited set**.  TypeScript
interfaces support multiple inheritance (`interface A extends B, C {}`), so
the base-type graph is a DAG, not a tree.  On a diamond — four types
`A extends B,C; B extends D; C extends D` — `check(D)` is evaluated
**twice**.  At depth D the call count is **2^D**.

```typescript
// src/compiler/checker.ts:13029
function hasBaseType(type: Type, checkBase: Type | undefined) {
    return check(type);
    function check(type: Type): boolean {
        if (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference)) {
            const target = getTargetType(type) as InterfaceType;
            // getBaseTypes() caches the resolved base array on `target`,
            // but check() itself has NO per-node result cache.
            // On a diamond, inner nodes are re-entered 2^(their depth) times.
            return target === checkBase || some(getBaseTypes(target), check);
        }
        else if (type.flags & TypeFlags.Intersection) {
            return some((type as IntersectionType).types, check);
        }
        return false;
    }
}
```

**Call sites (hot paths):**

| Line | Caller | When triggered |
|------|--------|----------------|
| 13377 | `resolveBaseTypesOfClass` | class base resolution (compile-time) |
| 13426 | `resolveBaseTypesOfInterface` | interface base resolution (compile-time) |
| 21334 | `isTypeDerivedFrom` | `instanceof` narrowing, every instanceof expression |
| 25226 | `checkPropertyAccessibility` | property access on class instances |
| 25242 | `isClassDerivedFromDeclaringClasses` | protected property access |
| 34614 | `getContainingClass` | various declaration checks |

The hottest path is `isTypeDerivedFrom` at line 21334, called for every
`instanceof` type guard and union/intersection reduction.  In a codebase with
a 5-level diamond interface hierarchy (realistic in large TS frameworks with
mixin patterns), `hasBaseType` performs 2^5 = 32 redundant calls to `check()`
per type query.

**Blowup table (diamond depth D):**

| D (depth) | Nodes visited | Without fix |
|-----------|---------------|-------------|
| 3         | 4             | 8 calls     |
| 5         | 6             | 32 calls    |
| 7         | 8             | 128 calls   |
| 10        | 11            | 1,024 calls |

In pathological but valid TypeScript (generated code, DTO hierarchies,
mixin tower patterns), D can reach 10+.

## Fix

Add a `Set<Type>` (keyed by the `target` canonical type) to `check()` so each
node is visited at most once:

```typescript
function hasBaseType(type: Type, checkBase: Type | undefined) {
    // CWE-407 fix: memoize to avoid 2^D traversal on diamond interface graphs
    const seen = new Set<Type>();
    return check(type);
    function check(type: Type): boolean {
        if (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference)) {
            const target = getTargetType(type) as InterfaceType;
            if (target === checkBase) return true;
            if (seen.has(target)) return false;
            seen.add(target);
            return some(getBaseTypes(target), check);
        }
        else if (type.flags & TypeFlags.Intersection) {
            return some((type as IntersectionType).types, check);
        }
        return false;
    }
}
```

Complexity: **O(2^D) → O(N)** where N = number of distinct types in the
reachable base-type DAG.

Speedup at D=10: ~1,024x (1024 calls → 11 calls).
