Skip to content

Server Crash

Overview

The API server closed the connection without returning any HTTP response. Usually, this means that the server crashed completely while processing the request.

API servers process requests until they are terminated deliberately by a server administrator or by your infrastructure. A request that results in an unhandled error should lead to a "500 Internal Server Error", and should not impact subsequent requests.

In some cases, unhandled errors may crash the entire API process, leading to an early and abrupt termination. All clients with in-flight requests being processed by the crashing API server will see their connection terminate early without seeing an HTTP response from the server.

This issue can lead to an efficient Denial-of-Service attack. An attacker can repeatedly send the problematic request, continuously taking down your APIs even as they attempt to restart.

Recommendation

Ensure that unhandled errors cannot take down the entire server and does not impact subsequent requests.

Examples

Most API frameworks make it difficult to cause this behavior by broadly converting uncaught exceptions into "500 Internal Server Error" HTTP responses.

As a result, you're more likely to see this sort of thing in code that sits outside of a framework, or bypasses it in some way. Here's a FastAPI example which bypasses the framework via os._exit:

from fastapi import FastAPI
import os

app = FastAPI()

@app.get("/test")
async def test():
    os._exit(1)

Our single endpoint, /test, unilaterally calls os._exit, terminating the program immediately. Let's try to call this endpoint a couple of times:

$ curl localhost:8000/test
curl: (52) Empty reply from server
$ curl localhost:8000/test
curl: (7) Failed to connect to localhost port 8000: Connection refused

The first attempt closed the connection abruptly, which curl reports as an "Empty reply", and is the behavior we're talking about on this page.

The second attempt completely failed to connect. The behavior of subsequent requests varies, but this is one common variation: the server has exited completely, so all subsequent connections fail.

Even if subsequent requests aren't affected at all, this kind of response almost always represents a disproportionate effort on your server's behalf (e.g. restarting processes and threads) which makes it a potential Denial-of-Service attack vector.

In rare cases, API developers deliberately use this kind of abruptly closed connection intentionally. If you're doing this, you can prevent mapi from generating these issues by passing --ignore-rule ServerCrash to the "mapi run" command.

References

  • Common Weakness Enumeration: CWE-730.