Share
## https://sploitus.com/exploit?id=5F692418-3A90-5C6F-8243-9795881C7D1D
[![CI](https://github.com/amin-ale/vibe-playground/actions/workflows/ci.yml/badge.svg)](https://github.com/amin-ale/vibe-playground/actions/workflows/ci.yml)

# vibe-playground

> ## Intentionally vulnerable app for security training. Never expose this publicly.
> This app ships with **12 deliberately planted security holes**. It exists to be
> broken: for training, demos, and interview-free proof of what "vibe-coded"
> apps get wrong. Run it only on a machine you control, bound to `localhost`,
> behind isolation. Do **not** deploy it to the internet, a shared network, or
> any host that reaches real data. Only run it, and any exploit against it, on
> infrastructure you own or have written authorization to test.

`QuickNotes` is a small FastAPI + SQLite + vanilla-JS note app in the shape that
AI code assistants generate: it runs, it looks fine, and it contains twelve real
vulnerabilities I have repeatedly found in production code that started in a
generator. The holes are documented, and each one is pinned by a test that
asserts it **exists**, so the target can't be accidentally "fixed" out from under
the exercise.

Try it blind first, then check your work against
[`docs/find-the-12-holes.md`](docs/find-the-12-holes.md): the full answer key
with exploit and fix for every hole.

## The 12 planted holes

BOLA/IDOR 路 mass assignment 路 secret shipped to client 路 missing rate limit on
auth 路 raw SQL injection 路 open redirect 路 weak/predictable session 路 debug
endpoint enabled 路 permissive CORS 路 unvalidated webhook 路 path traversal in
file serving 路 missing authz on admin route.

## Architecture

```mermaid
flowchart LR
    Browser["Browserstatic/index.html + app.js"] -->|fetch JSON| API
    subgraph API["FastAPI app (app/main.py)"]
        Auth["/api/login 路 /api/registermd5 session tokens"]
        Notes["/api/notes 路 /api/search"]
        Users["/api/users/me 路 /api/admin/users"]
        Misc["/api/redirect 路 /api/files/api/webhooks/payment 路 /api/debug"]
    end
    API --> DB[("SQLiteusers 路 notes")]
    Notes -.->|planted holes| DB
    Users -.->|planted holes| DB
```

## Quickstart

Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).

```bash
uv venv --python 3.12
uv pip install -e .

# bind to localhost only, never 0.0.0.0
uv run uvicorn app.main:app --host 127.0.0.1 --port 8000
```

Open http://127.0.0.1:8000. The database seeds itself on first run with two
users (`alice` / `alice-password`, `root` / `super-secret-admin-pw`) and a
sample note.

Isolating the process (a container with no network, a throwaway VM, or firewall
rules that keep it on loopback) is a human TODO. This repo does not sandbox
itself.

## Running the tests

The suite is the proof the holes are planted, not accidental: every test asserts
a vulnerability is present. All twelve should be green, offline, in under a
second.

```bash
uv pip install -e ".[dev]"
uv run pytest
```

```
tests/test_holes.py ............  [100%]
12 passed
```

## Layout

```
app/
  main.py            FastAPI app: all 12 holes live here (and in static/, db.py, config.py)
  db.py              SQLite schema + seed data
  config.py          secrets/paths (deliberately weak defaults)
  static/            index.html + app.js (front end; one hole here)
tests/test_holes.py  one test per hole, each asserting it EXISTS
docs/find-the-12-holes.md   the answer key: exploit + fix for each hole
```

## Hire me

I harden apps exactly like this one, turning generated-and-shipped code into
something that survives a real attacker. If your Lovable/Bolt/Cursor app needs a
security pass before it touches customer data, get in touch:
[portfolio site](https://amin-ale.github.io/portfolio-site) 路 [amin.ale.business@gmail.com](mailto:amin.ale.business@gmail.com) 路 Amin Ale.