Skip to content

[Bug]: ABORT_MEMORY Map grows unbounded without cleanup #6629

@coygeek

Description

@coygeek

CVSS Assessment

Metric Value
Score 6.5 / 10.0
Severity Medium
Vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

CVSS v3.1 Calculator

Summary

The ABORT_MEMORY Map in the auto-reply abort module stores abort state per session/user key and is never cleared. No .delete() or .clear() calls exist in the module. Over time with many unique sessions, this Map grows unbounded, causing gradual memory exhaustion.

Affected Code

File: src/auto-reply/reply/abort.ts:24

const ABORT_MEMORY = new Map<string, boolean>();

export function setAbortMemory(key: string, value: boolean): void {
  ABORT_MEMORY.set(key, value);
}

export function getAbortMemory(key: string): boolean | undefined {
  return ABORT_MEMORY.get(key);
}

// NO cleanup function exists - no .delete(), .clear(), or pruning logic

Attack Surface

How is this reached?

  • Network (HTTP/WebSocket endpoint, API call)

Authentication required?

  • Low (any authenticated user)

Entry point: Any auto-reply session that sets abort memory state.

Exploit Conditions

Complexity:

  • Low (no special conditions, works reliably)

User interaction:

  • None (automatic, no victim action needed)

Prerequisites: Normal usage over time - each unique session adds an entry that is never removed.

Impact Assessment

Scope:

  • Unchanged (impact limited to vulnerable component)

What can an attacker do?

Impact Type Level Description
Confidentiality None No data exposure
Integrity None No data modification
Availability High Memory exhaustion over time; process OOM crash in long-running deployments

Steps to Reproduce

  1. Deploy the application
  2. Generate many unique auto-reply sessions over time
  3. Each session calls setAbortMemory(key, value)
  4. Monitor memory usage - ABORT_MEMORY Map grows continuously
  5. No cleanup ever occurs - entries persist until process restart

Recommended Fix

Add cleanup when sessions end or implement a TTL-based eviction:

const ABORT_MEMORY = new Map<string, { value: boolean; timestamp: number }>();
const ABORT_MEMORY_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours

export function setAbortMemory(key: string, value: boolean): void {
  ABORT_MEMORY.set(key, { value, timestamp: Date.now() });
}

export function getAbortMemory(key: string): boolean | undefined {
  const entry = ABORT_MEMORY.get(key);
  if (!entry) return undefined;
  if (Date.now() - entry.timestamp > ABORT_MEMORY_TTL_MS) {
    ABORT_MEMORY.delete(key);
    return undefined;
  }
  return entry.value;
}

export function clearAbortMemory(key: string): void {
  ABORT_MEMORY.delete(key);
}

// Periodic cleanup
setInterval(() => {
  const now = Date.now();
  for (const [key, entry] of ABORT_MEMORY) {
    if (now - entry.timestamp > ABORT_MEMORY_TTL_MS) {
      ABORT_MEMORY.delete(key);
    }
  }
}, 60 * 60 * 1000); // Sweep every hour

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingstaleMarked as stale due to inactivity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions