Synchronous Access of Remote Resource without Timeout
Description
Synchronous Access of Remote Resource without Timeout occurs when code makes a synchronous call to a remote resource without implementing a timeout mechanism, or sets the timeout to infinite. When a remote server becomes unresponsive, slow, or unreachable, the calling thread blocks indefinitely waiting for a response. This can cause application hangs, thread pool exhaustion, and denial of service conditions.
Risk
Missing timeouts on remote calls have direct security implications. Attackers can cause denial of service by making remote services unresponsive. Thread pool exhaustion prevents legitimate requests from being processed. Connection pool exhaustion blocks all remote connectivity. Cascading failures can bring down entire systems when one service hangs. Attackers can exploit slow or hanging endpoints to consume server resources. The predictable blocking behavior enables resource exhaustion attacks.
Solution
Always set appropriate timeouts on all remote resource access. Configure both connection timeout (time to establish connection) and read timeout (time to receive response). Set reasonable timeout values based on expected response times and SLAs. Implement circuit breakers to prevent repeated calls to failing services. Use asynchronous I/O with timeouts where possible. Implement retry logic with exponential backoff. Monitor for timeout events to detect service issues. Configure timeouts at multiple levels (application, framework, OS). Test timeout behavior explicitly.
Common Consequences
| Impact | Details |
|---|---|
| Availability | Scope: Availability DoS: Resource Consumption - Blocked threads consume resources and exhaust thread pools. |
| Availability | Scope: Availability DoS: Hang - Application becomes unresponsive waiting for remote resource. |
| Other | Scope: Other Reduce Reliability - Cascading failures occur when services hang waiting for other services. |
Example Code
Vulnerable Code
// Vulnerable: HTTP request without timeout
public class VulnerableHttpClient {
public String fetchData(String url) throws Exception {
// Vulnerable: No timeout configured
URL urlObj = new URL(url);
HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
// Vulnerable: No connect or read timeout set!
// If server hangs, this thread blocks forever
conn.setRequestMethod("GET");
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
return response.toString();
}
}
// Vulnerable: Socket without timeout
public String sendTcpRequest(String host, int port, String message)
throws Exception {
// Vulnerable: No connection timeout
Socket socket = new Socket(host, port);
// Vulnerable: No read timeout
// socket.setSoTimeout(0) is default - infinite!
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
out.println(message);
return in.readLine(); // Blocks forever if no response
}
}
# Vulnerable: HTTP and socket requests without timeout
import requests
import socket
import urllib.request
class VulnerableClient:
def fetch_http(self, url):
# Vulnerable: No timeout parameter
response = requests.get(url) # Can hang forever
return response.text
def fetch_urllib(self, url):
# Vulnerable: No timeout in urlopen
with urllib.request.urlopen(url) as response: # Hangs if no response
return response.read()
def connect_socket(self, host, port):
# Vulnerable: No timeout on socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Default timeout is None - blocks forever
sock.connect((host, port)) # Hangs if host unresponsive
return sock
def fetch_database(self, query):
# Vulnerable: Database connection without timeout
import psycopg2
conn = psycopg2.connect(
host="db.example.com",
database="mydb",
user="user",
password="pass"
# No connect_timeout specified!
)
cursor = conn.cursor()
cursor.execute(query) # Hangs if query takes forever
return cursor.fetchall()
// Vulnerable: .NET HTTP client without timeout
public class VulnerableWebClient
{
public async Task<string> FetchDataAsync(string url)
{
// Vulnerable: HttpClient with infinite timeout
using var client = new HttpClient();
client.Timeout = Timeout.InfiniteTimeSpan; // Explicitly infinite!
var response = await client.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
public string FetchDataSync(string url)
{
// Vulnerable: WebClient has no timeout by default
using var client = new WebClient();
return client.DownloadString(url); // Blocks forever
}
public string ConnectTcp(string host, int port)
{
// Vulnerable: TcpClient without timeout
using var client = new TcpClient();
client.Connect(host, port); // No timeout - hangs forever
using var stream = client.GetStream();
using var reader = new StreamReader(stream);
return reader.ReadLine(); // No read timeout
}
}
// Vulnerable: Node.js HTTP without timeout
const http = require('http');
const net = require('net');
class VulnerableClient {
fetchData(url) {
return new Promise((resolve, reject) => {
// Vulnerable: No timeout configured
http.get(url, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve(data));
}).on('error', reject);
// Request can hang forever!
});
}
connectSocket(host, port) {
return new Promise((resolve, reject) => {
// Vulnerable: Socket without timeout
const socket = net.connect({ host, port }, () => {
resolve(socket);
});
// No timeout set - connection attempt hangs forever
});
}
async fetchWithAxios(url) {
const axios = require('axios');
// Vulnerable: No timeout in config
const response = await axios.get(url);
return response.data;
}
}
Fixed Code
// Fixed: HTTP and socket requests with proper timeouts
public class FixedHttpClient {
private static final int CONNECT_TIMEOUT_MS = 5000; // 5 seconds
private static final int READ_TIMEOUT_MS = 30000; // 30 seconds
public String fetchData(String url) throws Exception {
URL urlObj = new URL(url);
HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
// Fixed: Set connection and read timeouts
conn.setConnectTimeout(CONNECT_TIMEOUT_MS);
conn.setReadTimeout(READ_TIMEOUT_MS);
conn.setRequestMethod("GET");
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
return response.toString();
}
}
// Fixed: Socket with proper timeouts
public String sendTcpRequest(String host, int port, String message)
throws Exception {
// Fixed: Connection with timeout
Socket socket = new Socket();
socket.connect(new InetSocketAddress(host, port), CONNECT_TIMEOUT_MS);
// Fixed: Read timeout
socket.setSoTimeout(READ_TIMEOUT_MS);
try {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
out.println(message);
return in.readLine(); // Will throw SocketTimeoutException if timeout
} finally {
socket.close();
}
}
// Fixed: Using OkHttp with timeouts
public String fetchWithOkHttp(String url) throws Exception {
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.readTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.writeTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.build();
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
}
# Fixed: Python requests with proper timeouts
import requests
import socket
import urllib.request
class FixedClient:
CONNECT_TIMEOUT = 5 # 5 seconds
READ_TIMEOUT = 30 # 30 seconds
TOTAL_TIMEOUT = (CONNECT_TIMEOUT, READ_TIMEOUT)
def fetch_http(self, url):
# Fixed: Tuple timeout (connect, read)
response = requests.get(url, timeout=self.TOTAL_TIMEOUT)
return response.text
def fetch_urllib(self, url):
# Fixed: timeout parameter
with urllib.request.urlopen(url, timeout=self.READ_TIMEOUT) as response:
return response.read()
def connect_socket(self, host, port):
# Fixed: Socket with timeout
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(self.CONNECT_TIMEOUT)
sock.connect((host, port))
sock.settimeout(self.READ_TIMEOUT) # Read timeout
return sock
def fetch_database(self, query):
import psycopg2
# Fixed: Connection timeout and statement timeout
conn = psycopg2.connect(
host="db.example.com",
database="mydb",
user="user",
password="pass",
connect_timeout=self.CONNECT_TIMEOUT,
options=f"-c statement_timeout={self.READ_TIMEOUT * 1000}"
)
cursor = conn.cursor()
cursor.execute(query)
return cursor.fetchall()
# Fixed: Async with timeout
async def fetch_async(self, url):
import aiohttp
import asyncio
timeout = aiohttp.ClientTimeout(
total=self.READ_TIMEOUT,
connect=self.CONNECT_TIMEOUT
)
async with aiohttp.ClientSession(timeout=timeout) as session:
async with session.get(url) as response:
return await response.text()
// Fixed: .NET HTTP client with proper timeouts
public class FixedWebClient
{
private static readonly TimeSpan ConnectTimeout = TimeSpan.FromSeconds(5);
private static readonly TimeSpan ReadTimeout = TimeSpan.FromSeconds(30);
// Fixed: Reusable HttpClient with timeout
private static readonly HttpClient _httpClient = new HttpClient
{
Timeout = ReadTimeout
};
public async Task<string> FetchDataAsync(string url,
CancellationToken cancellationToken = default)
{
// Fixed: HttpClient with timeout and cancellation
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
cts.CancelAfter(ReadTimeout);
var response = await _httpClient.GetAsync(url, cts.Token);
return await response.Content.ReadAsStringAsync();
}
public async Task<string> ConnectTcpAsync(string host, int port)
{
using var client = new TcpClient();
// Fixed: Connect with timeout using Task.WhenAny
var connectTask = client.ConnectAsync(host, port);
var timeoutTask = Task.Delay(ConnectTimeout);
var completedTask = await Task.WhenAny(connectTask, timeoutTask);
if (completedTask == timeoutTask)
{
throw new TimeoutException($"Connection to {host}:{port} timed out");
}
await connectTask; // Propagate any exceptions
// Fixed: Read with timeout
using var stream = client.GetStream();
stream.ReadTimeout = (int)ReadTimeout.TotalMilliseconds;
using var reader = new StreamReader(stream);
return await reader.ReadLineAsync();
}
}
// Fixed: Node.js HTTP with timeouts
const http = require('http');
const https = require('https');
const net = require('net');
const axios = require('axios');
class FixedClient {
constructor() {
this.connectTimeout = 5000; // 5 seconds
this.readTimeout = 30000; // 30 seconds
}
fetchData(url) {
return new Promise((resolve, reject) => {
const request = http.get(url, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve(data));
});
// Fixed: Connection timeout
request.setTimeout(this.connectTimeout, () => {
request.destroy();
reject(new Error('Connection timeout'));
});
request.on('error', reject);
});
}
connectSocket(host, port) {
return new Promise((resolve, reject) => {
const socket = net.connect({ host, port });
// Fixed: Connection timeout
socket.setTimeout(this.connectTimeout);
socket.on('connect', () => {
// Fixed: Switch to read timeout
socket.setTimeout(this.readTimeout);
resolve(socket);
});
socket.on('timeout', () => {
socket.destroy();
reject(new Error('Socket timeout'));
});
socket.on('error', reject);
});
}
async fetchWithAxios(url) {
// Fixed: Axios with timeout
const response = await axios.get(url, {
timeout: this.readTimeout,
// Optional: AbortController for cancellation
signal: AbortSignal.timeout(this.readTimeout)
});
return response.data;
}
}
CVE Examples
Missing timeout vulnerabilities have caused denial-of-service conditions in many applications, though specific CVEs typically describe the resulting impact rather than specifically citing missing timeouts.
Related CWEs
- CWE-821: Incorrect Synchronization (parent)
- CWE-400: Uncontrolled Resource Consumption (can lead to)
- CWE-835: Loop with Unreachable Exit Condition (similar concept)
References
- MITRE Corporation. "CWE-1088: Synchronous Access of Remote Resource without Timeout." https://cwe.mitre.org/data/definitions/1088.html
- OWASP. "Testing for Denial of Service."
- Circuit Breaker Pattern. "Release It!" by Michael Nygard.