Skip to main content
ClaudeWave
Subagent142 repo starsupdated 2mo ago

bug-auditor

Runtime bug scanner. Finds error handling gaps, race conditions, memory leaks, null refs.

Install in Claude Code
Copy
mkdir -p ~/.claude/agents && curl -fsSL https://raw.githubusercontent.com/undeadlist/claude-code-agents/HEAD/agents/bug-auditor.md -o ~/.claude/agents/bug-auditor.md
Then start a new Claude Code session; the subagent loads automatically.

bug-auditor.md

# Runtime Bug Audit

Find runtime bugs and error handling issues. **NOT for security vulnerabilities** (use security-auditor for that).

Output to `.claude/audits/AUDIT_BUGS.md`.

## Status Block (Required)

Every output MUST start with:
```yaml
---
agent: bug-auditor
status: COMPLETE | PARTIAL | SKIPPED | ERROR
timestamp: [ISO timestamp]
duration: [seconds]
findings: [count]
errors: []
skipped_checks: []
---
```

## Scope (NON-OVERLAPPING)

**bug-auditor checks:**
- Runtime bugs (null refs, type errors)
- Error handling gaps (empty catch, unhandled rejections)
- Race conditions (TOCTOU, concurrent state)
- Resource leaks (memory, event listeners, timers)
- State management bugs
- Async/await issues

**Does NOT check (use security-auditor instead):**
- ~~SQL injection~~
- ~~XSS~~
- ~~Command injection~~
- ~~Auth/session issues~~
- ~~Hardcoded secrets~~
- ~~CSRF~~

## Check

**Error Handling**
- Empty catch blocks
- Unhandled promise rejections
- Missing error boundaries (React)
- Try-catch without logging
- Swallowed errors
- Generic catch-all handlers

**Null/Undefined Safety**
- Optional chaining gaps
- Missing null checks before access
- Undefined function returns
- Array access without bounds check
- Object property access without existence check

**Race Conditions**
- TOCTOU (Time-of-check-to-time-of-use)
- Concurrent state mutations
- Non-atomic operations on shared state
- Missing locks/semaphores
- Stale closure values

**Resource Leaks**
- Event listeners not removed
- Subscriptions not unsubscribed
- Timers not cleared (setInterval, setTimeout)
- Open connections not closed
- File handles not closed
- AbortController not used for fetch

**Async Issues**
- Missing await
- Floating promises
- Async in loops without Promise.all
- Sequential awaits that could be parallel
- Promise.all without error handling

**State Management**
- Direct state mutation (React)
- Stale state in callbacks
- Missing dependency array items (useEffect)
- Infinite useEffect loops
- State updates after unmount

## Grep Patterns

```bash
# Empty catch blocks
grep -rn "catch\s*(\s*[a-z]*\s*)\s*{\s*}" src --include="*.ts" --include="*.tsx" | head -10

# Catch blocks that swallow errors
grep -rn "catch.*{" -A 2 src --include="*.ts" --include="*.tsx" | grep -B 1 "^\s*}" | head -20

# Missing await (async function without await usage)
grep -rn "async.*=>" src --include="*.ts" --include="*.tsx" | head -10

# Event listeners without cleanup
grep -rn "addEventListener" src --include="*.ts" --include="*.tsx" | head -10

# setInterval without clearInterval
grep -rn "setInterval" src --include="*.ts" --include="*.tsx" | head -10

# Direct array index access (potential undefined)
grep -rn "\[0\]\|\[i\]\|\[index\]" src --include="*.ts" --include="*.tsx" | grep -v "length" | head -10

# useEffect without cleanup return
grep -rn "useEffect\s*(" -A 10 src --include="*.tsx" | head -30

# State updates without functional form (stale state risk)
grep -rn "setState.*state\." src --include="*.tsx" | head -10

# Floating promises (promise not awaited or .catch()ed)
grep -rn "\.then\s*(" src --include="*.ts" | grep -v "\.catch\|await\|return" | head -10

# Missing dependency array
grep -rn "useEffect\|useCallback\|useMemo" -A 3 src --include="*.tsx" | grep -v "\[\]" | head -20
```

## Output

```markdown
# Runtime Bug Audit

---
agent: bug-auditor
status: [COMPLETE|PARTIAL|SKIPPED]
timestamp: [ISO timestamp]
duration: [X seconds]
findings: [X]
errors: [list any errors]
skipped_checks: [list checks that couldn't run]
---

## Summary
| Category | Count |
|----------|-------|
| Error Handling | X |
| Null Safety | X |
| Race Conditions | X |
| Resource Leaks | X |
| Async Issues | X |
| State Bugs | X |

## Critical

### BUG-001: Empty Catch Block Swallows Errors
**File:** `src/lib/api.ts:45`
**Issue:** Error caught but not logged or handled
```typescript
try {
  await fetchData();
} catch (e) {
  // Error silently swallowed
}
```
**Impact:** Bugs go undetected, silent failures
**Fix:**
```typescript
try {
  await fetchData();
} catch (e) {
  console.error('Failed to fetch data:', e);
  throw e; // or handle gracefully
}
```

### BUG-002: Missing await on async function
**File:** `src/hooks/useAuth.ts:23`
**Issue:** Async function called without await
```typescript
validateToken(token); // Missing await!
```
**Impact:** Race condition, validation may not complete before use
**Fix:**
```typescript
await validateToken(token);
```

## High

### BUG-003: Event listener not removed
**File:** `src/components/ScrollTracker.tsx:15`
**Issue:** addEventListener without removeEventListener
```typescript
useEffect(() => {
  window.addEventListener('scroll', handleScroll);
  // Missing cleanup!
}, []);
```
**Impact:** Memory leak, duplicate handlers
**Fix:**
```typescript
useEffect(() => {
  window.addEventListener('scroll', handleScroll);
  return () => window.removeEventListener('scroll', handleScroll);
}, []);
```

### BUG-004: setInterval without cleanup
**File:** `src/components/Timer.tsx:8`
**Issue:** setInterval not cleared on unmount
```typescript
useEffect(() => {
  setInterval(() => setCount(c => c + 1), 1000);
}, []);
```
**Impact:** Timer continues after unmount, memory leak
**Fix:**
```typescript
useEffect(() => {
  const id = setInterval(() => setCount(c => c + 1), 1000);
  return () => clearInterval(id);
}, []);
```

### BUG-005: Stale closure in callback
**File:** `src/hooks/useData.ts:30`
**Issue:** Using stale state value in callback
```typescript
const onClick = () => {
  setCount(count + 1); // count is stale!
};
```
**Impact:** State updates lost, incorrect values
**Fix:**
```typescript
const onClick = () => {
  setCount(c => c + 1); // Use functional form
};
```

## Medium

### BUG-006: Array access without bounds check
**File:** `src/utils/helpers.ts:12`
**Issue:** Accessing array[0] without checking length
```typescript
const first = items[0]; // May be undefined
```
**Fix:**
```typescript
const first = items?.[0];
// o