Slow Loris Playground: Why Your HTTP Requests Need Timeouts

By Justin Mendez on 5/7/2025

Scanners

The Waiting Game: When Network Requests Go Bad

Modern applications are incredibly interconnected. Your backend talks to databases, third-party APIs, microservices; your frontend fetches data from your backend. These interactions happen over the network via HTTP requests using libraries like axios, node-fetch, got in Node.js, or the browser's native fetch API.

Most of the time, these requests complete quickly. But what happens when they don't? A remote server might be slow, unresponsive, or experiencing issues. Without proper precautions, your application could be left waiting... and waiting... and waiting.

This isn't just annoying; it's a security and reliability risk. Indefinitely hanging requests can tie up valuable server resources (memory, connections, process threads), potentially leading to performance degradation or even a complete Denial-of-Service (DoS), where your application becomes unavailable to legitimate users. Slow Loris-style attacks specifically exploit this by keeping connections open for as long as possible.

Timeouts: Your Application's Patience Limit

The primary defense against hanging network requests is implementing timeouts. A timeout sets a maximum duration your application is willing to wait for an HTTP request to complete (either connecting, receiving data, or the entire process).

If the request doesn't finish within the specified timeout period, the HTTP client library should automatically abort the request, freeing up resources and allowing your application to handle the failure gracefully (e.g., log an error, retry later, return an error to the user).

Why timeouts are crucial:

  • Resource Protection: Prevents hanging requests from consuming server resources indefinitely.
  • DoS Mitigation: Makes Slow Loris and similar resource exhaustion attacks much less effective.
  • Improved Reliability: Allows your application to fail fast and recover rather than getting stuck waiting for a non-responsive service.
  • Better User Experience: Prevents users from staring at loading spinners forever when a backend service is down.

Forgetting to set appropriate timeouts is a common oversight, especially in fast-paced "vibe coding" development where the focus might be purely on getting the request to work under ideal conditions.

How VibeSafe Spots Missing Timeouts

Manually checking every network request call in your codebase for proper timeout configuration is tedious. VibeSafe automates this with its 🌐 HTTP Client Scan:

  • Identifies HTTP Clients: VibeSafe recognizes common patterns used for making HTTP requests with popular libraries like axios, node-fetch, got, and the standard fetch API.
  • Checks for Timeout Configuration: It analyzes the configuration or options passed to these clients, looking for explicit timeout settings (e.g., timeout: 5000 in axios, or using AbortController with fetch).
  • Flags Missing Timeouts: If an HTTP request is made without any apparent timeout configuration, VibeSafe raises a warning.

Example VibeSafe Alert:

WARN: HTTP request using 'axios.get' appears to be missing a timeout configuration.
  File: src/services/apiClient.js
  Line: 25
  Suggestion: Add a 'timeout' option to axios requests to prevent hanging connections.

WARN: Fetch request missing AbortController or timeout signal.
  File: src/components/DataLoader.jsx
  Line: 12
  Suggestion: Use AbortController with setTimeout to implement timeouts for fetch API calls.

This proactive check helps ensure you haven't accidentally left your application vulnerable to hanging requests.

Best Practices for HTTP Timeouts

  • Set Reasonable Defaults: Configure default timeouts globally for your HTTP client instances whenever possible.
  • Context Matters: Adjust timeouts based on the specific API call. A quick internal service call might have a short timeout (e.g., 2-5 seconds), while a call to a potentially slower third-party API might need a longer one (e.g., 10-30 seconds). Avoid excessively long timeouts.
  • Use AbortController with fetch: The standard fetch API uses the AbortController pattern for timeouts. You typically create an AbortController, get its signal, pass the signal to fetch, and use setTimeout to call controller.abort() after your desired duration.
  • Handle Timeout Errors Gracefully: Implement try...catch blocks or promise rejection handlers to manage timeout errors. Decide whether to retry the request (with backoff), log the error, or return an appropriate error state to the user.
  • Scan Regularly: Use VibeSafe frequently to catch any new HTTP calls added without proper timeout settings.

Conclusion: Don't Get Stuck Waiting

Configuring timeouts on your outbound HTTP requests is a simple yet critical aspect of building resilient and secure applications. It protects your resources, mitigates DoS risks, and improves overall stability.

Don't let this detail slip through the cracks in your rapid "vibe coding" cycles. Leverage tools like VibeSafe to automatically scan for missing timeouts, ensuring your application doesn't get caught in an indefinite waiting game. Set those timeouts, handle the errors, and keep your application responsive and secure!

Quick Start

npm i -g vibesafe
vibesafe scan