# Unbounded per-session state exhausts resources

Per-session files, sockets or buffers created without a cap or error-path cleanup

_Area: Network devices and IoT. Seen in 3 disclosed reports; latest 2021-03-15. Updated 2026-11-01._

## How it works
A server allocates a resource per session or per connection — a file, a socket/file descriptor, a buffer — and assumes the peer will either behave or go away cleanly. When the peer misbehaves (never reads the reply, sends an oversized line, sends endless unique session ids), the cleanup path never runs or the allocation is never bounded. Each new session adds state that is never reclaimed, so the process or the filesystem fills up and the service stops responding. The broken assumption is "every session eventually ends and frees its state"; an attacker controls whether that happens.

## Where it shows up
- Error paths that write a response to a socket and wait for the peer, with no timeout or destroy fallback [E1](https://bugbountylibrary.com/r/h1%3A1043360.md).
- Session middleware that persists one file per session id into a directory with no count limit or expiry [E3](https://bugbountylibrary.com/r/h1%3A406614.md).
- Buffer-growth loops where a helper returns "too long" but does not report the required size back to the caller [E2](https://bugbountylibrary.com/r/h1%3A113424.md).
- Two implementations of the same helper behind `#ifdef`; one honors the caller's contract, the other does not [E2](https://bugbountylibrary.com/r/h1%3A113424.md).
- Error pages that echo a full filesystem path when input is oversized [E3](https://bugbountylibrary.com/r/h1%3A406614.md).

## How to review
For every per-session or per-connection allocation, find the release path and ask what happens if the peer never cooperates. The invariant: each allocated resource (fd, buffer, file) is bounded in count and is released on every exit path, including error and peer-disconnect paths. Check that error responses have a timeout or forced destroy [E1](https://bugbountylibrary.com/r/h1%3A1043360.md); that buffer-growth helpers write back the required size so the caller's loop terminates [E2](https://bugbountylibrary.com/r/h1%3A113424.md); and that session stores cap the number of entries and expire them [E3](https://bugbountylibrary.com/r/h1%3A406614.md).

## How finders spotted it
- Ran a vulnerability scanner against an http2 port, saw fd/memory growth, and traced it to the `unknownProtocol` handler [E1](https://bugbountylibrary.com/r/h1%3A1043360.md).
- Read the line-fetch loop and noticed the bufferevent branch returned -1 without setting `*data_len`, unlike the sibling helper [E2](https://bugbountylibrary.com/r/h1%3A113424.md).
- Saw a 250+ char session id produce a path-disclosure error, then noticed valid ids became `.cache` files in a tmpfs directory [E3](https://bugbountylibrary.com/r/h1%3A406614.md).

## Variants seen
- Socket/fd leak on an error event where the peer never reads the reply [E1](https://bugbountylibrary.com/r/h1%3A1043360.md).
- Infinite loop in a buffer-growth routine due to a missing size write-back [E2](https://bugbountylibrary.com/r/h1%3A113424.md).
- Unbounded file creation per unique session id filling a tmpfs mount [E3](https://bugbountylibrary.com/r/h1%3A406614.md).

## Impact and severity
Denial of service. Impact rose when the leak reached a shared resource: filling `/run` cascaded into `/var/log` and took the whole device offline, not just the web portal [E3](https://bugbountylibrary.com/r/h1%3A406614.md); a local-only control-port bug became web-triggerable via a browser request to localhost [E2](https://bugbountylibrary.com/r/h1%3A113424.md). Scanner traffic alone was enough to trigger the leak [E1](https://bugbountylibrary.com/r/h1%3A1043360.md).

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A1043360.md
- E2: https://bugbountylibrary.com/r/h1%3A113424.md
- E3: https://bugbountylibrary.com/r/h1%3A406614.md
