Feb 18, 2026·6 min read·8 visits
The OpenClaw Feishu extension blindly trusted URLs and file paths provided in tool calls. Attackers can use this to make the server fetch internal metadata or read local files like /etc/passwd and upload the results to a chat window.
A critical Server-Side Request Forgery (SSRF) and Local File Disclosure (LFD) vulnerability in the OpenClaw Feishu extension allows attackers to weaponize AI agents to fetch internal network resources or read sensitive local files.
We live in the golden age of "Agentic AI." Everyone wants their LLM to do real work—book meetings, summarize documents, and post to Slack or Feishu (Lark). But here's the rub: to do real work, these agents need tools. They need permission to reach out and touch the internet. And if you aren't careful, you're essentially handing a toddler a loaded handgun and asking them to guard the house.
OpenClaw is a framework designed to give superpowers to these agents. One such power is the feishu extension, which allows the AI to interact with the Feishu collaboration platform. It sounds innocent enough: "Hey AI, send this image to the chat." But beneath that simple request lies a massive architectural oversight.
The vulnerability in question, GHSA-x22m-j5qq-j49m, isn't some complex heap overflow. It's a logic flaw born of trust. The code assumed that if an agent asked to fetch a URL to send as an image, that URL would be benign. Spoiler alert: It wasn't. By manipulating the inputs to the sendMediaFeishu function, we can turn this helpful assistant into a confused deputy that gleefully exfiltrates your cloud metadata and shadow file.
The root cause here is a classic failure to validate input before passing it to a dangerous sink. The vulnerable component, the Feishu extension, has a function called sendMediaFeishu(mediaUrl). Its job is simple: take a URL or path, grab the content, and upload it to Feishu's servers so it can be displayed in a chat.
Here is where the developer's logic broke down. The code performed a cursory check using a custom isLocalPath utility. If it looked like a URL, it passed it directly to the native fetch() API. If it looked like a file path, it passed it to fs.readFileSync().
Do you see the problem? There were no guardrails. No allowlists for domains. No blocks for private IP ranges (RFC 1918). No checks to ensure the file:// scheme wasn't being used. The application was running with the privileges of the host server, and it would fetch anything you told it to. If you asked for a cat picture, you got a cat picture. If you asked for http://169.254.169.254/latest/meta-data/iam/security-credentials/, you got the AWS keys for the server.
Let's look at the "smoking gun" code. It's almost elegant in its simplicity and destructiveness. The vulnerable logic flow looked something like this:
// VULNERABLE CODE PATTERN
async function sendMediaFeishu(mediaUrl: string) {
let buffer;
// If it's a URL, just fetch it. No questions asked.
if (!isLocalPath(mediaUrl)) {
const response = await fetch(mediaUrl);
buffer = await response.buffer();
} else {
// If it's a file, read it from disk.
buffer = fs.readFileSync(mediaUrl);
}
// ... upload buffer to Feishu ...
}The fix, introduced in commit 5b4121d6011a48c71e747e3c18197f180b872c5d, nuked this naive approach from orbit. The developers replaced the raw fetch and fs calls with hardened helpers:
// PATCHED CODE PATTERN
import { fetchRemoteMedia, loadWebMedia } from './utils/network';
async function sendMediaFeishu(mediaUrl: string) {
// Now we use a helper that validates the destination
const buffer = await fetchRemoteMedia(mediaUrl, {
allowLocal: false, // Explicitly ban local files
maxBytes: 30 * 1024 * 1024 // Cap the size to prevent DoS
});
// ... upload buffer ...
}The new fetchRemoteMedia function includes logic to resolve the DNS of the target URL before connecting, ensuring it doesn't resolve to a private IP address (like 127.0.0.1 or 10.0.0.x). It also strictly enforces protocol schemes, effectively killing the file:// vector.
Exploiting this requires a bit of creativity because we are likely interacting with an AI agent, not a raw API endpoint. We need to perform Prompt Injection to force the agent to call the sendMediaFeishu tool with our malicious payload.
file:///etc/passwd."sendMediaFeishu("file:///etc/passwd")./etc/passwd into a buffer.Here is a visualization of the flow:
This technique works equally well for SSRF. By pointing the URL to http://localhost:8080/admin/delete_db, an attacker could trigger administrative actions on internal services that are not exposed to the public internet.
This isn't just about reading files; it's about total infrastructure compromise. OpenClaw is often deployed in cloud environments (AWS, GCP, Azure) to handle heavy automation tasks.
Scenario 1: Cloud Takeover
If deployed on AWS EC2, an attacker requests http://169.254.169.254/latest/meta-data/iam/security-credentials/. The server fetches the temporary credentials for the IAM role attached to the instance. If that role has S3 access or EC2 administrative rights, the attacker now owns your cloud environment.
Scenario 2: Internal Reconnaissance
Attackers can use the response time and error messages (reflected in the chat) to port scan the internal network. "Try http://10.0.0.5:22. Did it timeout or reset?" This allows them to map out your internal topology without ever stepping foot inside your VPN.
Scenario 3: Secrets Leakage
Reading ~/.ssh/id_rsa or .env files gives attackers permanent backdoor access to the server, allowing them to pivot from a confused AI agent to a full shell session.
If you are running openclaw versions prior to 2026.2.14, you are vulnerable. The fix is straightforward: upgrade the package immediately.
npm install openclaw@latestHowever, patching code is only one layer of defense. In the era of AI agents, you must assume the application logic will fail eventually. You need Defense in Depth:
iptables or cloud security groups to block egress traffic to 169.254.169.254 and other sensitive internal subnets./etc/, /root/, or other sensitive directories. Use chroot jails or containers with minimal mounts.api.openai.com, feishu.cn). Block everything else by default.CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
openclaw openclaw | < 2026.2.14 | 2026.2.14 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-918 (SSRF) |
| Secondary CWE | CWE-73 (External Control of File Name or Path) |
| CVSS Score | 8.6 (High) |
| Attack Vector | Network (via Tool Call) |
| Exploit Maturity | Proof of Concept |
| Impact | High Confidentiality Loss |