Feb 11, 2026·6 min read·83 visits
LangChain's `ChatOpenAI` component contained an SSRF vulnerability in its token counting logic. To estimate costs for vision models, the library automatically fetched images from URLs provided in prompts. This allowed attackers to force the server to request internal resources (like AWS metadata or localhost). Fixed in `langchain-core` 1.2.11.
In the race to build the ultimate AI agent, developers often overlook the plumbing. CVE-2026-26013 is a classic Server-Side Request Forgery (SSRF) vulnerability nestled deep within LangChain's utility functions. Specifically, the logic used to calculate token costs for OpenAI's vision models inadvertently turned the library into an open proxy. By tricking the `ChatOpenAI` component into 'measuring' an image hosted on an internal server, attackers could force the application to scan local networks or ping cloud metadata services. It’s a stark reminder that even 'helper' functions need to treat user input like a biological hazard.
In the modern LLM economy, tokens are currency. Developers are obsessed with counting them before sending requests to OpenAI to avoid bankruptcy. Text is easy—just count the subwords. But images? Images are tricky.
OpenAI's GPT-4o and GPT-4-turbo vision models price images based on their dimensions. A 512x512 image costs fewer tokens than a 2048x2048 one. To help developers estimate these costs locally, LangChain introduced a convenience method: get_num_tokens_from_messages().
Here is the logic: If a user sends a prompt with an image URL, LangChain grabs the image, checks the height and width, and calculates the token cost. It sounds helpful, benign even. But from a security perspective, it's a nightmare. The library was effectively saying, "Give me a URL, and I will make a server-side HTTP request to it." In the security world, we call this a 'feature' right up until it becomes a CVE.
The vulnerability (CWE-918) stems from a lack of boundary checks in the _url_to_size helper function. When you pass a message history to the token counter, LangChain iterates through it. If it spots a type: image_url, it extracts the URL and immediately fires an HTTP GET request.
There was no whitelist. There was no blacklist. There was no check to see if the IP resolved to 127.0.0.1 or the infamous 169.254.169.254 (cloud metadata). The code assumed that if you are asking to count tokens for an image, you must be pointing to a valid, public image.
This is a classic blind SSRF scenario. While the attacker might not get the content of the response back (because the code tries to parse the response as an image using Pillow), the side effects are dangerous enough. The server performs the handshake, sends the headers, and downloads the body. This allows an attacker to map internal ports (based on response time), trigger internal APIs that act on GET requests, or perform Denial of Service by pointing the tokenizer at a 10GB file.
Let's look at the vulnerable code path in libs/partners/openai/langchain_openai/chat_models/base.py. The logic was devastatingly simple. It used httpx to fetch the resource without hesitation.
Vulnerable Implementation:
def _url_to_size(image_source: str) -> tuple[int, int] | None:
# No validation. Just fetch.
response = httpx.get(image_source)
response.raise_for_status()
# Pass bytes to Pillow to get dimensions
return Image.open(BytesIO(response.content)).sizeThe fix, introduced in commit 2b4b1dc29a833d4053deba4c2b77a3848c834565, is a lesson in defensive programming. The maintainers didn't just add a regex; they introduced a dedicated security module langchain_core._security._ssrf_protection.
Fixed Implementation:
from langchain_core._security._ssrf_protection import validate_safe_url
def _url_to_size(image_source: str) -> tuple[int, int] | None:
try:
# 1. Validate the URL before connection
validate_safe_url(image_source, allow_private=False, allow_http=True)
# 2. Add timeouts to prevent hanging
with httpx.Client(timeout=5.0) as client:
response = client.get(image_source)
# 3. Check content size (50MB limit matching OpenAI)
# ... (size checks) ...
except (ValueError, httpx.RequestError):
return NoneThe validate_safe_url function does the heavy lifting: it resolves the DNS (preventing DNS rebinding attacks) and checks if the resulting IP falls into private ranges (RFC 1918) or loopback addresses.
Exploiting this requires an application that allows user-controlled message history or uses an agent that processes external content. Imagine a "Receipt Scanner AI" that accepts image URLs.
The Attack Vector:
{
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "Analyze this receipt"},
{
"type": "image_url",
"image_url": {"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}
}
]
}
]
}chat.get_num_tokens_from_messages(messages) to check if the prompt fits the context window.Error: cannot identify image file <AWS_CREDENTIALS_BLOB>. This leaks the credentials directly.localhost:22, localhost:5432) to map the internal network topology based on response latency.The CVSS score is 3.7 (Low) primarily because the Confidentiality impact is rated None/Low depending on the specific implementation. Since the function expects an image, it usually discards non-image data (like JSON from a metadata service) before the attacker sees it.
However, do not let the "Low" severity fool you. In a cloud environment, SSRF is a gateway drug. If an attacker can trigger requests from your backend, they can:
/dev/urandom exposed over HTTP), they can exhaust the memory of the Python process attempting to load it into BytesIO.Remediation is straightforward but urgent. You must update langchain-core to version 1.2.11 or higher. The patch includes robust SSRF protections that are enabled by default.
If you cannot upgrade immediately, or if you are paranoid (which you should be), you can disable this behavior entirely in your code:
# explicitly disable fetching
token_count = chat.get_num_tokens_from_messages(
messages,
allow_fetching_images=False
)This flag forces LangChain to skip the download and use a default/fallback calculation for token usage, preventing the network request altogether. It makes your token counts slightly less accurate for images, but it keeps your internal network private. A worthy trade-off.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
langchain-core LangChain AI | < 1.2.11 | 1.2.11 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-918 |
| Attack Vector | Network |
| CVSS v3.1 | 3.7 (Low) |
| Impact | Blind SSRF, Internal Scanning |
| Vulnerable Method | get_num_tokens_from_messages |
| Fix Commit | 2b4b1dc29a833d4053deba4c2b77a3848c834565 |
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.
CVE-2026-14669 is a critical heap-based buffer overflow vulnerability in PostgreSQL's date/time formatting function to_char(timestamptz). The flaw arises from unsafe copying of user-controlled timezone abbreviations into a fixed-size internal buffer. An authenticated database user can trigger this issue by setting a long POSIX timezone abbreviation containing custom formatting, allowing them to overwrite adjacent heap structures and hijack execution control to achieve remote code execution (RCE) with the privileges of the 'postgres' operating system user.
An unauthenticated remote denial of service vulnerability exists in the Unleash feature management platform. By submitting a crafted JSON payload containing deeply nested structures to an OpenAPI-validated endpoint, an attacker can trigger uncontrolled recursion within the error formatting module. This leads to a call-stack exhaustion (RangeError: Maximum call stack size exceeded) inside the Node.js runtime, causing the service to crash immediately without recovery.
CVE-2026-63004 is a server-side request forgery (SSRF) vulnerability in the Unleash feature management platform. Authenticated administrators with CREATE_ADDON or UPDATE_ADDON privileges can exploit this vulnerability to initiate requests to loopback addresses, private networks, and cloud metadata endpoints, potentially leading to information disclosure and credential extraction.
Prior to version 8.0.3, Unleash's Markdown event formatter directly mutated the global template-escaping function of the shared mustache Node.js module, resulting in a process-wide security degradation where HTML/Markdown escaping was permanently disabled for the application lifetime.
A critical SQL injection vulnerability exists in the GeoTools open-source Java library. This vulnerability is situated within the post-processing phase of OGC Filter conversion inside the PostGIS DataStore module. Specifically, the `jsonArrayContains` function does not validate or sanitize its arguments before constructing PostgreSQL SQL/JSON path evaluation queries. An unauthenticated remote attacker can exploit this weakness by submitting crafted filters via standard OGC services like WFS or WMS to execute arbitrary SQL commands on the underlying database system.
CVE-2026-61824 is a high-severity Cross-Site Scripting (XSS) vulnerability in kepano/defuddle before version 0.19.1. Custom site extractors for platforms such as X/Twitter, Substack, and YouTube constructed HTML representations via template string interpolation without output escaping. This allowed malicious pages to bypass standard parser sanitization routines and execute arbitrary JavaScript.