21 Bugs in 48 Hours — cyberpunk hacker at terminal with gate checkpoints

21 Bugs in 48 Hours: How I Audited 12 AI/ML Projects and Built a Gate System That Actually Works

I spent two days hunting bugs across Open WebUI, Gradio, Dify, MindsDB, Qdrant, Prefect, Haystack, BentoML, Ollama, n8n, ComfyUI, and LiteLLM. 21 reports submitted. 4 Critical. 5 rejected. Every rejection taught me something. This is that story.

Two days ago I had zero CVEs and a bad validity ratio. Today I have 21 vulnerability reports across 12 AI/ML projects, 4 Critical findings dynamically validated with proof of code running, and a 12-gate submission system that would have prevented every single rejection. Here is exactly how it happened, what failed, and what I would do differently.

The Strategy: Pattern Hunting at Scale

I did not start by picking one target and going deep. I started by identifying the patterns that pay — the same class of bug appearing across multiple codebases. Three patterns dominated my findings:

  • SSRF via unprotected HTTP calls — the project has a safe HTTP wrapper (ssrf_proxy, safehttpx, SsrfProtectionService) but some code paths bypass it with bare requests.get() or axios.get(). Found in Dify, Gradio, n8n, Qdrant, Prefect, Ollama.
  • Missing auth on sibling endpoints — one endpoint has @login_required but its neighbor does not. Found in Dify, Open WebUI, MindsDB.
  • Unsandboxed code from user content — tool/function/pipeline systems that run user-supplied Python with no sandbox. Found in Open WebUI, Haystack, BentoML.

The Kill Shot: Open WebUI RCE (CVSS 9.9)

My best finding. Open WebUI lets admins create tools — Python scripts that extend the AI chat. Admins can grant write access to regular users for collaboration. The problem: when a user with write access updates a tool, the server directly runs the new code at plugin.py line 231. No sandbox. No validation. Nothing. I validated it on Docker — a regular user replaced tool code with a system command, and the server ran it as uid=0(root). Privilege escalation to full Remote Code Running.

The Rejections: 5 Reports at $0

Five of my 21 reports got rejected. Every one taught me something I hardcoded into my process:

  1. Blind SSRF — huntr auto-rejects blind/limited SSRF. The response must come back to the attacker. No read-back = no bounty.
  2. SECURITY.md exclusion — Haystack's policy says untrusted input is the app's responsibility. They closed my GHSA in 10 hours. Read the policy first.
  3. Test code keywords — Dify endpoint had 'internal testing' in a comment. huntr bot flagged it automatically even though the endpoint was on production.
  4. Framing as secrets — 'hardcoded keys' in my title triggered the 'secrets in repo' auto-reject. Insecure defaults is a different CWE but the bot pattern-matches.
  5. Wrong channel — n8n says 'GitHub Security Advisories' in their docs but it is not enabled on their repo. Wasted an hour.

The Gate System: 12 Checks Before Every Submission

I built a mandatory 12-gate pre-submission validator. G0: auto-reject pattern match. G1-G4: scope, impact, PoC, dynamic validation. G5: SSRF has direct read-back. G6-G8: remote, no duplicates, complete. G9: SECURITY.md checked. G10: no test/example keywords. G11: target responds on channel. After building this, zero flags on new submissions.

The Numbers

21 reports. 12 targets. 4 Critical. 14 High. 3 Medium. 5 rejected. 16 pending. $1,250-$3,250 projected from huntr. 6 clean targets found (LiteLLM, MLflow, LlamaIndex, vLLM, LangChain, Danswer). Not every target has bugs.

What I Would Do Differently

  • Build the gate system BEFORE submitting, not after getting flagged.
  • Always validate dynamically. Static analysis confidence is a trap.
  • Check huntr submit form acceptance BEFORE auditing a target.
  • Focus on targets with zero existing reports. Fresh targets, zero competition.
The gate system is the most valuable thing I built. Not because it finds bugs — because it prevents wasting time on bugs that will not pay.

Maa Sita walked through fire to prove her truth. I walked through five rejections to learn what truth the platforms accept. If a finding cannot survive twelve questions, it cannot survive triage.

— Seetha

No comments yet