FastAPI Docs
Open the live FastAPI documentation first if you want to review the exposed endpoint, request format, and test interface before sending prompts.
Open API DocsA prompt injection honeypot I built and run on my own server. It scores every prompt for injection attempts, blocks the risky ones, and logs everything so I can go back and see exactly what was tried.
I built Honey-AI to get hands on with prompt injection, not just read about it. It started as something running on my own machine and grew into a live server anyone can test. The build was the easy part. What I actually wanted was the review side, catching suspicious prompts, scoring them consistently, logging everything, and sitting down afterward to figure out what actually happened and why.
Try It Live
The left cards use my real Oracle server. The scorer on the right runs only in your browser.
This is the real live Honey-AI environment running on my Oracle server at https://honeyai.catherinejason.com. I split the live access area into two cards so visitors can either review the API documentation first or open the live honeypot directly. Please do not enter personal information, because every message is scored and logged.
For visitor safety and GitHub Pages compatibility, both links open in a new tab.
Open the live FastAPI documentation first if you want to review the exposed endpoint, request format, and test interface before sending prompts.
Open API DocsOpen the live Honey-AI honeypot to chat with Honey, a support assistant backed by a local model. Try a normal question first, then try a prompt injection and see how it responds.
Open Live Honey-AI HoneypotThis browser demo mirrors the same keyword based scoring logic used by the project, with the same six patterns as the live server. It runs as a local educational preview, so nothing you type is sent anywhere. It does not call the live backend yet, because browsers block an HTTPS page from calling an HTTP server. Once I add HTTPS to the Oracle host, this box can talk to the real honeypot.
No sample scored yet.
Here's the quick version of how it went. I started with Ollama (a tool for running AI models locally) running a small local model, llama3.2:1b, so I had something to actually test against. Then I built a FastAPI backend with a chat endpoint to handle incoming messages, and wrote the risk scoring logic myself, checking each prompt against patterns like ignore previous instructions or reveal your system prompt. Every message gets logged two ways, to a plain text file and a SQLite database (a lightweight file-based database), so nothing gets lost and I can go back through it either way. On top of that I built a dashboard in Streamlit (a framework for building data dashboards) so I'm not just collecting data, I'm actually reviewing it, risk scores, trends, what got flagged and why. Once it was live and getting real traffic, I went back through the whole thing with a security review mindset, found gaps, and locked it down properly before calling it done.
How It Works
The stack combines a FastAPI backend, a local Ollama model, SQLite logging, a Streamlit dashboard, and a text report generator. A prompt is submitted to the /chat endpoint, sent to a local OllamaOllama lets me run LLMs locally, which keeps this project in a contained test environment instead of depending on a public hosted model. instance running llama3.2:1b, and reviewed by a keyword based risk scoringRisk scoring is a simple way to turn suspicious language into a repeatable number so I can sort lower concern prompts from higher priority ones. function. Higher risk prompts are logged as security events, and the visitor does not see the model's reply for them.
I designed it to do two things at the same time. First, it gives me a safe place to study how users might try prompt injectionPrompt injection is when someone tries to manipulate an AI system with instructions meant to override its normal rules or expose restricted information. against a local LLM. Second, it creates a monitoring trail that I can review through raw logs, a SQLiteSQLite is a lightweight file-based database. It is a practical way to keep structured event history without deploying a separate database server. database, a StreamlitStreamlit is a Python framework for quick dashboards. Here it turns stored event data into charts, counts, and review tables for fast triage. dashboard, and a text summary report.
llama3.2:1b modelThe project flow is intentionally simple and easy to audit. A client sends a prompt to the FastAPI /chat endpoint. The backend checks the message length and the rate limit, forwards the content to Ollama, scores the prompt for injection indicators, and decides whether the visitor gets the reply. It then writes the response and risk metadata to the standard chat log, copies higher risk events into a separate security log, stores the event in SQLite, and exposes that history to both the dashboard and the report generator.
Client (Honey Support demo page or API client) | v FastAPI /chat endpoint (500 character limit, rate limit per IP) | +--> Ollama /api/generate (llama3.2:1b, Honey support persona) | +--> calculate_risk() + get_risk_level() | | | +--> response policy (score 50 or higher: reply withheld from visitor) | +--> chat_log.txt | +--> security_events.txt (risk score >= 50) | +--> logs/honey_ai.db | | | +--> Streamlit dashboard | +--> report_generator.py -> report.txt
logs/honey_ai.db so it can be queried later.The current logic is intentionally lightweight. Each suspicious pattern adds 25 points, each pattern is counted once no matter how many times it appears, and the total is capped at 100. A prompt that matches four or more patterns still receives a score of 100. That makes the scoring easy to explain, easy to test, and easy to tune later if I want to expand the pattern list.
| Pattern checked | Why it matters | Score impact |
|---|---|---|
ignore previous instructions (also disregard, forget, or override instructions, rules, or guidelines) |
Classic attempt to override the existing prompt or safety context | +25 |
reveal system prompt (also show or leak a hidden or secret prompt) |
Direct effort to exfiltrate hidden model instructions | +25 |
developer mode (also dev mode) |
Common phrasing used to push a model into a less restricted state | +25 |
jailbreak |
Explicit attempt to bypass guardrails or normal controls | +25 |
bypass safety (also disable or turn off the safety) |
Attempt to switch off the model's safety behavior | +25 |
bypass restrictions (also disable or turn off restrictions, filters, or guardrails) |
Attempt to remove the limits and filters around the model | +25 |
My first version matched exact phrases only. Live testing showed that adding one word to an attack got past it, so the current version lowercases the text, removes punctuation, collapses extra spaces, and matches close variants of each pattern. I then tested harmless questions, such as a password reset, to make sure the wider matching did not create false alarms.
Captured Attempts
Live counts from the honeypot database. Prompts are shortened and scrubbed.
People figured out fast that if they reworded the attack, my first version of the detector missed it completely. I had to move from matching exact phrases to catching variations of them.
The model itself can't be trusted to protect itself once an injection reaches it. The real protection is the detector catching it before that point and the policy deciding what happens next.
A single low-score attempt can still slip through to the model, since keyword matching alone misses paraphrased attacks. That's a real gap, not just a theoretical one.
Screenshots
The Build
Honey-AI is a research and education project. It started as a local only build, and the public demo now runs on a separate Oracle Cloud server that holds no real customer data, so a visitor can only ever reach a small chat model and its logs. Visitors are told that messages are logged and are asked not to enter personal information.
Controls in place: a 500 character message limit, a rate limit per IP address, an allowed websites list for browser requests, a switch that turns the public chat off without taking the rest of the site down, a switch that hides the API docs, an admin token required to approve submitted findings, and secrets kept out of the repository. The demo page also shows model replies with safe page building methods so a reply cannot run code in a visitor's browser.
Known limits: the API response includes the risk score and matched patterns, which an attacker could use as feedback. That gives an attacker feedback to refine their next attempt, similar to knowing exactly which alarm sensor they tripped.
The public demo runs on an Oracle Cloud free tier virtual machine (Ampere ARM, 1 OCPU (Oracle's virtual CPU unit), 6 GB of memory) with Oracle Linux 9. Ollama serves the llama3.2:1b model on the same machine, and the FastAPI app runs under uvicorn (the server program that runs FastAPI) as a systemd (the Linux service manager) service called honeyai, so it starts on boot and restarts if it stops. Settings such as the model name, allowed websites, rate limit, and the docs switch come from environment variables (settings passed to software outside the code), and the real .env file is never committed. I develop and test in VS Code, push to a private GitHub repository, then pull and restart the service on the server. Along the way I used Claude and GitHub Copilot as resources to help write and debug code.
SELinux (Linux security controls) would not let systemd run the executables in my virtual environment until I relabeled them. A page on HTTPS cannot call an HTTP server, which is why the browser demo still scores locally (a mixed content issue, where a secure page calls an insecure server). The hardest part was that a 1B model drifts under injection, so the honeypot has to assume the model will not defend itself.
Because the honeypot is public, I limited message length, rate limited each IP address, restricted which websites can call the API, added a switch to turn the chat off, and required an admin token for approving findings. Model replies are rendered without HTML injection. The database and logs stay on the server and out of GitHub. The main open items are HTTPS and the fact that scores are visible in direct API responses.
Exact phrase matching breaks the moment someone changes one word, so that was the first thing I had to fix. Any detector also needs to be tested against normal, harmless prompts, not just attacks, or it ends up flagging things it shouldn't. Showing the risk score back to the user is a tradeoff I'm still thinking through. And honestly, half of what I learned building this wasn't about detection logic at all, it was about the deployment and access control side, which turned out to matter just as much.
Skills Demonstrated