Skip to content

[Bug]: Tlon/Urbit SSE client fetch calls lack timeout causing hangs #5266

Description

@coygeek

Summary

Severity: P1/High (Score: 75/150)
CWE: CWE-400 - Uncontrolled Resource Consumption
OWASP: A05:2021 - Security Misconfiguration
File: extensions/tlon/src/urbit/sse-client.ts

The Tlon extension's SSE client makes fetch requests without timeout or AbortSignal, causing connections to hang indefinitely if the Urbit server becomes unresponsive.

Why this is P1: Network partitions or server hangs cause permanent connection hangs, preventing auto-reconnect and causing resource leaks that accumulate over time.

Triage Assessment

Factor Value Score
Reachability Any Tlon extension user with network issues 20/40
Impact Connection exhaustion, unresponsive extension 25/50
Exploitability Network partition or unresponsive server 15/30
Verification file:line ✓, code ✓, attack steps ✓ 15/30
Total 75/150

Steps to reproduce

  1. Connect to an Urbit server via the Tlon extension
  2. Simulate network partition or server hang (e.g., firewall drop)
  3. The SSE client fetch calls wait indefinitely
  4. Auto-reconnect logic cannot trigger because initial fetch never returns

Expected behavior

All network requests should have timeouts. Use AbortSignal.timeout() or similar to bound wait times.

Actual behavior

8 fetch call locations have no timeout mechanism. Network issues cause permanent hangs.

Affected code locations:

File (extensions/tlon/src/urbit/sse-client.ts):

  • Line 110: fetch() in sendSubscription() - no timeout
  • Line 126: fetch() in connect() - no timeout
  • Line 139: fetch() in connect() - no timeout
  • Line 167: fetch() in openStream() - no timeout
  • Line 263: fetch() in poke() - no timeout
  • Line 282: fetch() in scry() - no timeout
  • Line 348: fetch() in close() - no timeout
  • Line 357: fetch() in close() - no timeout
// Line 167: No timeout, no abort signal
async openStream() {
  const response = await fetch(this.channelUrl, {
    method: "GET",
    headers: {
      Accept: "text/event-stream",
      Cookie: this.cookie,
    },
  });
  // If server never responds, this hangs forever
}

Environment

  • Version: latest (main branch)
  • OS: Any
  • Install method: Any

Logs or screenshots

N/A - issue is in code logic

Impact

  • Connection exhaustion: Hanging connections accumulate over time
  • Unresponsive extension: Tlon features become unavailable
  • Resource leak: Open sockets and memory not released
  • No recovery: Auto-reconnect cannot trigger if fetch never returns

Recommended fix

  1. Add AbortSignal.timeout: signal: AbortSignal.timeout(30000) to all fetch calls
  2. Use fetchWithGuard pattern: Adopt the guarded fetch pattern from other modules
  3. Implement proper cleanup: Ensure error handlers release resources
  4. Add connection health monitoring: Detect stale connections and force reconnect
  5. Consider fetch wrapper: Create a timeout-enabled fetch utility for the extension

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions