CVE-2026-24767

Headless Horseman: NocoDB Blind SSRF via Premature HEAD Requests

Alon Barad
Alon Barad
Software Engineer

Jan 28, 2026·5 min read·2 visits

Executive Summary (TL;DR)

NocoDB checked file metadata (HEAD) before checking if the URL was safe (Validation). Attackers can abuse this to make the server ping internal IPs and cloud metadata endpoints. Fixed in v0.301.0.

A blind Server-Side Request Forgery (SSRF) vulnerability in NocoDB allows authenticated users to force the server to ping internal network resources. The flaw lies in the `uploadViaURL` feature, which validates the target URL only *after* performing an initial HTTP `HEAD` request to fetch file metadata. This architectural hiccup allows attackers to map internal infrastructure or interact with cloud metadata services before security controls kick in.

The Hook: Spreadsheet or Port Scanner?

NocoDB bills itself as an open-source Airtable alternative—a tool to turn your databases into smart spreadsheets. It's the kind of tool developers love to self-host, often sitting deep within a corporate network with access to sensitive internal APIs, databases, and cloud metadata services.

Like many modern applications, NocoDB allows users to upload files by providing a URL. This feature, uploadViaURL, is intended to fetch a cat photo from the public internet and store it in your database. However, to a security researcher, a "fetch from URL" feature is like a red rag to a bull. It screams SSRF (Server-Side Request Forgery).

The developers knew this. They implemented robust SSRF protections: blocklists for private IP ranges, DNS resolution checks, and logic to prevent the server from talking to localhost. But as we often see in complex systems, the devil isn't in the filter—it's in the order of operations.

The Flaw: A Premature Request

The root cause of CVE-2026-24767 is a classic case of "act first, think later." When a user submits a URL, the application needs to know two things before downloading the file: "How big is it?" (Content-Length) and "What is it?" (Content-Type).

To get this information efficiently, NocoDB decided to send a lightweight HTTP HEAD request to the target URL. The logic flow went roughly like this:

  1. Probe: Send axios.head(url) to get metadata.
  2. Validate: Check if the URL resolves to a forbidden IP (like 169.254.169.254 or 127.0.0.1).
  3. Download: If valid, perform the full GET request.

Do you see the problem? Step 2 is the bouncer, but Step 1 already let the guest into the club to check their coat. By the time the application realizes, "Hey, that IP belongs to the AWS Metadata Service!", the HEAD request has already been sent and processed by the destination server.

The Code: The Smoking Gun

The vulnerability lived in the storage handling logic. The code essentially trusted the input URL just enough to poke it, but not enough to download from it. In the world of SSRF, a poke is often all you need.

Here is a conceptual reconstruction of the vulnerable flow versus the fixed flow:

The Vulnerable Logic (Simplified):

// 1. Unprotected Probe
// The code fires a request BEFORE checking if the destination is safe.
const metadata = await axios.head(userProvidedUrl);
 
// 2. Security Check
// This runs too late. The packet has already left the server.
if (isInternalIP(userProvidedUrl)) {
  throw new Error("SSRF Detected!");
}
 
// 3. Download
download(userProvidedUrl);

The Fix (v0.301.0):

The patch, associated with commit 656e76bf8248e4bf034b9004c936030e158040da, refactored this logic. It moved the validation to the very top of the funnel, likely within the SDK's shared utilities.

// 1. Security Check First
// Now we validate the URL/IP before opening any socket.
if (isInternalIP(userProvidedUrl)) {
  throw new Error("Blocked");
}
 
// 2. Probe (Safe)
const metadata = await axios.head(userProvidedUrl);

It seems trivial, but moving that if statement up a few lines makes the difference between a secure application and a potential foothold for an attacker.

The Exploit: Blinding the Server

This vulnerability is classified as Blind SSRF. We don't get the HTTP response body back in the UI (since the app throws an error or fails to process the internal response as a valid file), but we can infer a lot.

Attack Scenario: Cloud Reconnaissance

  1. Target: AWS Metadata Service (http://169.254.169.254/latest/meta-data/).
  2. Payload: The attacker sends a request to /api/v2/storage/upload-by-url with {"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}.
  3. Execution: The server sends a HEAD request. The AWS service responds with 200 OK (and headers).
  4. Observation: The attacker watches the error message or response time. A quick response or a specific error regarding "invalid content type" confirms the service exists and is reachable.

Attack Scenario: Internal Port Scanning

  1. Target: Local Redis instance (http://127.0.0.1:6379).
  2. Execution: The server sends a HEAD request to the Redis port.
  3. Result: Redis might log a protocol error, but the TCP connection is established. By timing the response (open ports respond differently than closed/filtered ports), the attacker can map out the internal network topology.

The Impact: Why Panic?

While the CVSS score is a moderate 4.9 (mostly because of the "Blind" nature limiting data exfiltration), the real-world impact depends heavily on where NocoDB is hosted.

If this instance is running inside a Kubernetes cluster or on an EC2 instance with an attached IAM role, a Blind SSRF is a golden ticket for reconnaissance. Attackers can verify the existence of internal microservices, dashboards, or unauthenticated APIs.

Furthermore, some internal services perform actions on GET (or even HEAD) requests. While rare, "GET-based state changes" are a thing in legacy or poorly designed internal APIs. Triggering a HEAD request against http://internal-admin/delete?id=1 might not delete anything, but it proves the endpoint is live. It is a crack in the armor that turns the server into a proxy for the attacker.

The Fix: Closing the Window

The remediation is straightforward: Update to NocoDB v0.301.0. The maintainers have patched the order of operations to ensure validation occurs before any network IO.

If you cannot patch immediately, you must rely on Egress Filtering. Your database tool shouldn't be able to talk to the entire internet, and it certainly shouldn't be able to talk to your internal network or cloud metadata IPs.

Defense in Depth:

  • Firewall Rules: Block outbound connections from the NocoDB container to 169.254.169.254 and private ranges (10.0.0.0/8, etc.).
  • Network Policies: In Kubernetes, use NetworkPolicies to restrict egress to only necessary domains (e.g., S3 or specific webhooks).
  • Disable Feature: If you don't need to upload files via URL, disable the feature entirely via configuration if possible.

Fix Analysis (1)

Technical Appendix

CVSS Score
4.9/ 10
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:N

Affected Systems

NocoDB < 0.301.0

Affected Versions Detail

Product
Affected Versions
Fixed Version
NocoDB
NocoDB
< 0.301.00.301.0
AttributeDetail
CWE IDCWE-918 (SSRF)
Attack VectorNetwork
CVSS4.9 (Medium)
ImpactInternal Reconnaissance
Exploit StatusPoC Available
PlatformNode.js / Vue
CWE-918
Server-Side Request Forgery (SSRF)

Server-Side Request Forgery (SSRF) occurs when a web application is fetching a remote resource without validating the user-supplied URL. It allows an attacker to coerce the application to send a crafted request to an unexpected destination.

Vulnerability Timeline

Fix committed to repository
2026-01-13
CVE Published / Advisory Released
2026-01-28

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.