Abusing an Unauthenticated Local Server to Overwrite LLM Wiki

Search for a command to run...

No comments yet. Be the first to comment.
I. Introduction Coolify is an open-source, self-hostable PaaS that lets you deploy apps, databases, and pre-baked services on your own servers — the "Vercel/Heroku/Netlify replacement, but you own the

I. Introduction Kestra is an open-source event-driven workflow orchestration platform written in Java on top of Micronaut. It lets teams declare "flows" — task graphs that move data, call APIs, run sc

Disclosure status: Reported to vendor and coordinated through a private fix path. I. Introduction Warp is an agentic development environment, born out of the terminal. Use Warp's built-in coding agent
![[CVE-2026-48731] AI-Assisted Discovery of Command Injection in Warp Terminal](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fuploads%2Fcovers%2F699fec8cc9015c37f6e5364f%2Fe7817cef-a8af-45ec-b931-4e08225edeb6.png&w=3840&q=75)
Author: Anhlt91, Thuanhn Date: May 2026Tags: AI Claude Bug Hunting Closed-Source Security Research Overview I used Claude AI to find real security vulnerabilities in a closed-source enterprise produc
I. Introduction Filament is an open-source full-stack UI framework for Laravel built on top of Livewire. It lets developers compose admin panels, forms, tables, infolists, actions, and notifications a

Night-Wolf Team
58 posts
FPT Cyber Security Assurance Service
Local HTTP servers in desktop apps are easy to overlook during a security review. They don't show up in bug bounty scopes, they're not publicly routable, and developers rarely treat them as a trust boundary. LLM Wiki — a Tauri-based knowledge base app with close to 10k GitHub stars — has one running on port 19827.
LLM Wiki is a cross-platform desktop app built on Tauri (Rust backend, React frontend). Instead of traditional RAG, it reads your documents and uses an LLM to build a persistent, self-updating wiki — pages get created, linked, and revised automatically as you add sources. There's also a browser extension that lets you clip web content directly into your wiki.
That extension communicates with the app through the local HTTP server on port 19827. That's the attack surface.
Cloned the repo, opened src-tauri/src/clip_server.rs. Pure Rust HTTP server, no framework, handles requests manually.
First thing in the CORS section:
Header::from_bytes("Access-Control-Allow-Origin", "*").unwrap(), Wildcard. Every origin. No exceptions.
This alone confirms CSRF is possible — any website can send cross-origin requests to this server. The question is what those requests can do.
Read through the POST /clip handler — the endpoint that receives clipped content from the browser extension and saves it to the wiki. The projectPath handling:
} else {
project_path_from_body // taken directly from request body
};
let dir_path = std::path::Path::new(&project_path) .join("raw").join("sources");
std::fs::create_dir_all(&dir_path)?;
// writes file here
No validation. No allowlist. Pass in any path and it writes there.
That's arbitrary file write. And it's reachable cross-origin because of the wildcard CORS.
Before writing a PoC, I checked the other endpoints. GET /projects returns the full filesystem paths of every wiki project the user has. No authentication. No token. Just call it.
The complete attack chain:
Victim visits a page the attacker controls
Page calls GET http://127.0.0.1:19827/projects → returns full filesystem paths of all wiki projects
For each path, page calls POST /clip with projectPath set to that path and attacker-controlled content
Every wiki project gets overwritten — victim clicked nothing, saw nothing, lost everything
Three bugs. One page visit. The wildcard CORS makes the cross-origin requests possible, /projects provides the targets, /clip does the damage.
Most of this audit was done alongside Claude Code running in the terminal. Not to find bugs automatically — to read code faster.
234 TypeScript files solo would have taken days. With AI, the workflow became: point it at a file or a pattern, ask whether there's anything that processes user input, follow the data flow. The speed difference is real.
Where it saved the most time was filtering false positives. The TOCTOU in clip_server.rs looks alarming on first read — a while file_path.exists() check followed by a write, classic TOCTOU pattern. Walking through the context: race window is microseconds, no privilege escalation path, no reliable exploit. Low severity. Without AI helping reason through it, that analysis would have taken longer to feel confident about.
Two fixes were submitted in PR #272.
Replacing wildcard CORS with an allowlist:
const ALLOWED_ORIGINS: &[&str] = &[
"http://localhost:1420",
"tauri://localhost"
];
Requests from any other origin now receive Access-Control-Allow-Origin: null, which browsers treat as a blocked response.
Validating projectPath against registered projects:
let is_registered = current == normalized
|| projects.iter().any(|(_, p)| p == normalized);
if !is_registered {
return r#"{"ok":false,"error":"projectPath is not a registered project"}"# .to_string(); }
Any path not in the user's registered project list is rejected before the file write happens.
Any website a user visits can send requests to 127.0.0.1. Developers building desktop apps with local HTTP servers tend to treat localhost as a trusted zone — it isn't. As far as the browser is concerned, localhost is just another origin, and wildcard CORS removes the only enforcement mechanism that would otherwise protect it.
If you're building something similar: treat your local HTTP server like a public API. Enforce an origin allowlist on CORS. Validate every input parameter against what the application actually knows about.