Feb 15, 2026·5 min read·22 visits
The `fastapi-api-key` library (< 1.1.0) leaked the validity of API keys via timing differences. Successful verifications returned immediately, while failures slept for a random duration. Attackers could use this asymmetry to enumerate valid key IDs.
A classic implementation of 'security through obscurity' backfires in the python package `fastapi-api-key`. By attempting to slow down brute-force attacks with artificial delays on failures, the library inadvertently created a high-fidelity timing oracle. This allowed attackers to statistically distinguish between valid and invalid API keys based on response latency, turning a defensive measure into an enumeration vector.
In the world of API security, we often obsess over complex cryptographic failures or massive injection flaws. But sometimes, the most elegant vulnerabilities are born from good intentions. Enter fastapi-api-key, a Python library designed to handle API key management for FastAPI applications. It does what it says on the tin: verifies keys, manages scopes, and generally keeps the riff-raff out.
The developers, seemingly aware of brute-force risks, decided to implement a countermeasure. If someone sends an invalid key, the server shouldn't just reject it; it should stall. The logic is sound in principle: make the attacker wait, and you destroy their throughput. It's a tar pit for bots.
But here is the catch: they only applied the tar pit to the failures. If you presented a valid key, the server would enthusiastically usher you in without delay. This created a binary signal: Fast response = Valid Key. Slow response = Invalid Key. It’s like playing poker against an opponent who pauses for exactly 10 seconds every time they have a bad hand, but slaps their cards down instantly when they have a Royal Flush. You don't need to see their cards to know when to fold.
The vulnerability, tracked as CWE-208 (Observable Timing Discrepancy), resided in the verify_key method of the AbstractApiKeyService class. The code logic was deceptively simple: try to verify the key, and if it fails (raises an exception), sleep for a random interval before raising the error.
This is a textbook side-channel. In a perfect world, a secure comparison functions in 'constant time'—meaning it takes the exact same amount of CPU cycles to reject a fake key as it does to accept a real one. By explicitly injecting asyncio.sleep only into the exception handler, the developers introduced a massive temporal disparity.
While the delay was randomized (jittered), the absence of a delay on the success path created a statistical canyon. A valid request might return in 50ms (processing time). An invalid request might return in 250ms (processing time + sleep). Even across a noisy network (the internet), this 200ms gap is a neon sign blinking 'ACCESS GRANTED' to anyone with a stopwatch and a basic understanding of statistics.
Let's look at the diff. This is where the logic flaw becomes undeniable. In versions prior to 1.1.0, the code looked something like this (simplified for dramatic effect):
# THE VULNERABLE PATTERN
async def verify_key(self, api_key: str, ...):
try:
# If this works, we return IMMEDIATELY. Fast.
return await self._verify_key(api_key, required_scopes)
except Exception as e:
# If this fails, we wait. Slow.
wait = self._system_random.uniform(self.rrd, self.rrd * 2)
await asyncio.sleep(wait)
raise eThe fix in version 1.1.0 (Commit 310b2c5c...) was to ensure that everyone waits, regardless of whether they are a VIP or an intruder. It democratizes the suffering.
# THE PATCHED PATTERN
async def verify_key(self, api_key: str, ...):
try:
# Verify, but don't return yet
result = await self._verify_key(api_key, required_scopes)
except Exception as exc:
# Wait on failure
await self._apply_delay()
raise exc
# Wait on success too!
# Now both paths take (Processing + Delay)
await self._apply_delay()
return resultBy moving the delay logic (now encapsulated in _apply_delay) to execute in both the success path and the exception path, the timing signature is flattened. The server is now equally slow for everyone, destroying the oracle.
How does a hacker actually use this? You might think, "The internet is noisy; latency fluctuates." That is true. A single request is unreliable. But we aren't sending a single request. We are sending hundreds.
AAAAAA). They calculate the average response time. Let's say it's 300ms (network + processing + sleep).Because the sleep function was using uniform(rrd, rrd * 2), the jitter was substantial, but the minimum sleep time was essentially a floor. The success path would consistently perform under that floor. A standard Z-test or even a simple threshold check would reveal the valid keys with high confidence.
> [!NOTE]
> This vulnerability doesn't recover the secret part of the key if the key is a long random string. However, if the system uses KeyID:Secret format, this allows enumeration of valid KeyIDs, drastically reducing the search space for an offline or online brute-force of the secret component.
The CVSS score is a modest 3.7 (Low), mostly because the Attack Complexity is rated High (due to network noise). Don't let that fool you. In a targeted attack against a high-value API, this is a serious leak.
Information Disclosure: Knowing which users or accounts exist on a platform is the first step in a targeted campaign. If I know Company_A_Prod_Key exists, I focus my phishing or brute-force efforts there.
Denial of Wallet: Since the server is forced to sleep on invalid requests, an attacker can flood the server with garbage keys to exhaust thread pools or open connections, leveraging the application's own defense mechanism to cause a Denial of Service (DoS). By fixing the timing leak, the developers also inadvertently solidified the latency penalty for legitimate users, which is a trade-off often required for security.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
fastapi-api-key Athroniaeth | < 1.1.0 | 1.1.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-208 |
| Attack Vector | Network (Timing Analysis) |
| CVSS | 3.7 (Low) |
| Impact | Information Disclosure (Key Enumeration) |
| Exploit Status | Conceptual / PoC Possible |
| Fix Version | 1.1.0 |
The product performs a comparison or other operation that takes a variable amount of time depending on the value of the input, allowing an attacker to determine information about the input based on the elapsed time.
CVE-2024-29203 identifies a cross-site scripting (XSS) vulnerability in the content ingestion and parsing mechanics of TinyMCE rich text editor. Due to a failure to enforce sandbox attributes on dynamic iframe elements and safely handle legacy embed objects, unauthenticated attackers can inject malicious elements that execute scripts within the context of the parent application session.
A technical breakdown of the OS command injection vulnerability in the shell-quote NPM package (CVE-2026-9277 / GHSA-w7jw-789q-3m8p). The bug resides in the character-by-character backslash-escaping logic applied to the .op field of object-tokens within the quote() function, which fails to match and escape line terminators due to a regex matching oversight in JavaScript. This allows unauthenticated remote attackers to execute arbitrary shell commands if they can control inputs processed by this library.
A high-severity memory corruption vulnerability exists in the V8 JavaScript engine of Google Chrome before versions 149.0.7827.102/103. The flaw arises from an incorrect bounds-check elimination during JIT compilation by the TurboFan optimizer, allowing remote attackers to achieve out-of-bounds read and write access inside the sandboxed renderer process.
An improper authentication vulnerability (CWE-287) exists in the legacy, deprecated Internet Key Exchange version 1 (IKEv1) key exchange protocol implementation in Check Point Security Gateways. The vulnerability is caused by a logic flow weakness during the certificate validation process for Remote Access VPN and Mobile Access (SSL VPN) connections. An unauthenticated remote attacker can exploit this weakness to bypass user authentication entirely, establishing a fully functional Remote Access VPN connection without a valid password.
GeoNode versions prior to 4.4.5 and 5.0.2 are vulnerable to Server-Side Request Forgery (SSRF) in the service registration endpoint. Authenticated attackers with low privileges can exploit insufficient input validation in the Web Map Service (WMS) registration module to force the application server to make outbound network queries to loopback addresses, private RFC1918 subnets, link-local scopes, and cloud metadata endpoints. This technical report details the mechanics of the vulnerability, the underlying architectural flaw, and how to effectively remediate and mitigate the associated security risks.
CVE-2022-0492 is a high-severity missing authorization vulnerability in the Linux kernel's Control Groups (cgroups) v1 implementation. The flaw resides within the cgroup_release_agent_write function in kernel/cgroup/cgroup-v1.c, where the kernel fails to validate if the process writing to the release_agent file possesses administrative capabilities in the initial user namespace. This allows a local attacker inside a container with root privileges (UID 0) to abuse user namespaces, mount a cgroups v1 directory, modify the release_agent parameter, and execute arbitrary commands on the host system as host root, effectively achieving a complete container escape.