DEV Community

문세환
문세환

Posted on

I scanned a "vibe-coded" Python repo. Found 137 security bugs.

I scanned KaletoAI/anima-verse — a Python LLM project that literally says "Vibe-coded experiment" in the README.

Result: 137 BLOCK-level security issues across 212 files.

Here's exactly what the AI generated.


What is anima-verse?

An LLM-driven character simulation app. FastAPI backend, SQLite, multi-channel chat. Real project, actively developed. Not a toy.

The README says:

"Vibe-coded experiment in LLM-driven character simulation."

So this is a perfect real-world test case.


Bug #1 — SQL Injection × 4 files

queue_cli.py L111:

def cmd_list(username):
    sql = f"SELECT * FROM queue WHERE user='{username}'"
    db.execute(sql)
Enter fullscreen mode Exit fullscreen mode

Same pattern in agent_loop.py, character_io.py (twice).

The AI generated parameterized queries in some places but reverted to f-string SQL in others — inconsistently, across the same codebase.

Fix:

db.execute("SELECT * FROM queue WHERE user=?", (username,))
Enter fullscreen mode Exit fullscreen mode

Bug #2 — CORS Wildcard + Credentials (Critical)

app/server.py L373:

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,  # ← this is the problem
)
Enter fullscreen mode Exit fullscreen mode

allow_origins=["*"] with allow_credentials=True is explicitly forbidden by the CORS spec — browsers block it. But more importantly: if you relax this in production (which developers often do to "fix" the browser error), any website can make authenticated requests to your server.

This is a classic AI pattern. It copies the CORS middleware boilerplate without understanding the credential interaction.


Bug #3 — SSRF × 2

app/core/channel_health.py L131:

def _check_backend(url):
    response = httpx.get(url)
    return response.status_code
Enter fullscreen mode Exit fullscreen mode

url comes from config — but config is user-editable. No allowlist, no scheme validation, no internal IP check.

An attacker who can edit config (or MITM the config source) can make this server probe internal services: http://169.254.169.254/ (AWS metadata), http://localhost:5432/ (Postgres), etc.


Bug #4 — Path Traversal × 5

app/core/config.py, five separate functions:

def _seed_default_marketplace_catalogs(config_path):
    with open(config_path) as f:   # ← no validation
        data = json.load(f)
Enter fullscreen mode Exit fullscreen mode

config_path is constructed from user-controlled input in some call paths. No pathlib.Path.resolve(), no directory boundary check.


Full count

Issue Count Severity
SQL Injection 4 BLOCK
Path Traversal 5 BLOCK
SSRF 2 BLOCK
CORS Wildcard + Credentials 1 BLOCK
Unreachable Return 1 BLOCK
Others 124 BLOCK
Warnings 69 WARN
Total 206

Why does this happen?

AI models learn from open source code — which contains both good and bad patterns. When generating a new file, the model picks patterns based on frequency, not correctness.

SQL injection via f-strings appears millions of times in training data. CORS with wildcard appears everywhere. So the model generates it.

The fix isn't to stop using AI — it's to scan every file the AI generates before it goes to production.


How to scan your own vibe-coded project

# Scan a single file (free, no signup)
curl -X POST https://pleasing-transformation-production-90c2.up.railway.app/v1/scan \
  -H "X-API-Key: vg_free_test" \
  -F "file=@app.py"
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "passed": false,
  "block_count": 3,
  "issues": [
    {
      "kind": "SQL_INJECTION_RISK",
      "severity": "BLOCK",
      "line": 111,
      "detail": "unsafe SQL formatting in execute() — use parameterized queries"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Or add it to your GitHub Actions pipeline so every PR gets scanned automatically:

- uses: Moonsehwan/aina-vibeguard-action@v1
  with:
    api-key: ${{ secrets.VIBEGUARD_KEY }}
    fail-on-block: 'true'
Enter fullscreen mode Exit fullscreen mode

Links

The scanner is deterministic AST — no LLM, same result every time, CI-safe.

Top comments (0)