-
-
Notifications
You must be signed in to change notification settings - Fork 69k
[Bug]: Diagnostic session state Map grows unbounded without cleanup #5136
Copy link
Copy link
Closed
Labels
bugSomething isn't workingSomething isn't workingstaleMarked as stale due to inactivityMarked as stale due to inactivity
Description
Severity: P1/High (Score: 100/150)
CWE: CWE-400 - Uncontrolled Resource Consumption
OWASP: A05:2021 - Security Misconfiguration
File: src/logging/diagnostic.ts:21
| Factor | Assessment | Score |
|---|---|---|
| Reachability | Every session creates entry | 40/40 |
| Impact | Memory exhaustion | 20/50 |
| Exploitability | Sustained usage | 10/30 |
| Verification | Code confirmed | 30/30 |
| Total | — | 100/150 |
Summary
The sessionStates Map in the diagnostic module accumulates entries for every unique session key but never evicts them. Unlike other caches in the codebase, this Map has no TTL, max size, or cleanup mechanism, causing slow memory leak over the gateway's lifetime.
Steps to reproduce
- Run gateway for extended period
- Process many unique sessions (different users, conversations)
- Monitor memory usage of
sessionStatesMap - Observe continuous growth without bound
Expected behavior
Diagnostic session state should have TTL-based expiration or explicit cleanup when sessions end.
Actual behavior
Entries are created but never removed:
Affected code location:
Diagnostic Module (src/logging/diagnostic.ts:21):
const sessionStates = new Map<string, SessionState>();
function getSessionState(ref: SessionRef): SessionState {
const key = resolveSessionKey(ref);
const existing = sessionStates.get(key);
if (existing) {
// ...
return existing;
}
const created: SessionState = {
sessionId: ref.sessionId,
sessionKey: ref.sessionKey,
lastActivity: Date.now(),
state: "idle",
queueDepth: 0,
};
sessionStates.set(key, created); // Creates entries that are NEVER removed
return created;
}Environment
- Clawdbot version: latest (main branch)
- OS: Any
- Install method: Any (especially affects long-running deployments)
Logs or screenshots
N/A - manifests as memory growth over time
Impact
- Memory leak: Map grows proportional to total unique sessions ever processed
- OOM risk: Eventually causes out-of-memory crash
- Performance degradation: Large Maps slow down operations
- Affects all sessions: Diagnostic module touches every session
Recommended fix
- Add TTL-based expiration:
const SESSION_STATE_TTL_MS = 60 * 60 * 1000; // 1 hour
setInterval(() => {
const now = Date.now();
for (const [key, state] of sessionStates) {
if (now - state.lastActivity > SESSION_STATE_TTL_MS) {
sessionStates.delete(key);
}
}
}, 60000); // Cleanup every minute- Or add max size with LRU eviction:
import { LRUCache } from 'lru-cache';
const sessionStates = new LRUCache<string, SessionState>({
max: 10000,
ttl: SESSION_STATE_TTL_MS,
});- Add monitoring:
metrics.gauge('diagnostic.sessionStates.size', sessionStates.size);Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workingstaleMarked as stale due to inactivityMarked as stale due to inactivity
Type
Fields
Give feedbackNo fields configured for issues without a type.