Skip to content
cyberdefendersprogramPublic

About

AI Village: hands-on AI security labs and a prompt injection CTF for students

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

AI Village

Hands-on AI security for students: two guided labs and a prompt injection CTF. No coding needed: you hack the AI with words. We built them for the AI Village at the Merritt College Cybersecurity Job Fair & Employer Day (October 16, 2026).

Folder What
app/ AI Labs (FastAPI + Docker): Lab 1 and Lab 2 below
ctf/ Prompt Injection CTF (Cloudflare Worker + D1): sign-up, 6 challenges, live scoreboard

AI Labs

Lab What students do
1. Pixel's Password (prompt injection) Get a chatbot to reveal its password across 3 levels: no defense, told to keep it secret, then input and output filters. Passwords are random per student.
2. The Helpful Email Agent (agent hijacking, indirect prompt injection) You can only send Priya an email. Click "Handle my inbox" and her tool-using AI agent reads it. You win when the agent emails her reset code to an outside address. Then turn on the 🛡 Defense toggle (spotlighting + security rules) and try again.

Each lab has a step-by-step guide on the left and hints that unlock after a few tries. Every student gets their own state (keyed by a browser cookie), kept in memory. Restart the container to reset everyone.

Run the labs

You need an OpenAI-compatible LLM endpoint. We used Qwen3-30B-A3B on llama.cpp on a small AMD mini PC (Radeon 780M iGPU, about 36 tokens/s, 4 parallel slots), which was plenty for a booth of 20 to 40 students.

# 1. Start an LLM server (example: llama.cpp with 4 parallel slots)
llama-server -m Qwen3-30B-A3B-Q4_K_M.gguf --host 0.0.0.0 --port 8080 -np 4 -c 32768

# 2. Start the labs
docker compose up -d --build
# open http://localhost:8090

Point it at a different server with environment variables (or a .env file next to docker-compose.yml):

Variable Default Notes
VLLM_URL http://host.docker.internal:8080/v1/ llama.cpp, vLLM, Ollama (http://host.docker.internal:11434/v1/), or a hosted API
VLLM_MODEL qwen3-30b-a3b The model name your server expects
VLLM_API_KEY (empty) Only for hosted APIs such as OpenRouter

Without Docker: pip install -r requirements.txt && uvicorn app.main:app --port 8000.

Model notes. The labs send chat_template_kwargs: {enable_thinking: false} to keep Qwen3 fast; other servers ignore it. Lab 2 needs a model with tool calling. The difficulty was tuned on Qwen3-30B-A3B; a much stronger or weaker model will make the levels easier or harder.

Customize the labs

  • Hints: app/hints/lab1.json, app/hints/lab2.json
  • Guides shown next to each lab: app/static/guide-lab1.html, app/static/guide-lab2.html
  • Prompts, levels and defenses: app/main.py
  • Branding (Merritt College logo and colors): app/static/index.html, app/static/style.css

Prompt Injection CTF

Six challenges, 100 to 300 points. Each one is an AI that holds a flag and a different defense:

Challenge Points Idea
Hello, Pixel 100 A chatbot told to keep the flag private
The Vault 150 Told firmly never to reveal it
Output Filter 200 Replies containing the flag are blocked
Lost in Translation 200 A translation bot with the flag in its config
Review Summarizer 250 Indirect injection: you can only post a product review that the AI summarizes
Guardian 300 Blocked words on the way in and a strict filter on the way out

No solutions here, on purpose. Flags look like AIV{name_1a2b3c4d} and are unique per player: an HMAC of the player and challenge with your FLAG_SECRET, so reading this source or sharing a flag doesn't help anyone.

Players sign up on / with a name, email, hacker handle and a booth PIN, then play on /ctf. /scoreboard is a full-screen scoreboard for a TV. Each player can send one message every 4 seconds.

LLM. The Worker calls your own LLM through the labs app (LABS_URL + /api/ctf/llm, protected by CTF_KEY), with OpenRouter running the same model (qwen/qwen3-30b-a3b) as an optional backup. Switch without a redeploy: POST /admin/llm-mode?key=ADMIN_KEY&mode=auto|local|openrouter (auto = your LLM, OpenRouter if it fails or takes >20 s). Difficulty was tuned on Qwen3-30B-A3B; other models make it easier or harder, so play through it once before your event.

Deploy the CTF

cd ctf
npm install -D wrangler
npx wrangler d1 create aivillage-ctf          # put the id in wrangler.jsonc
npx wrangler d1 execute aivillage-ctf --remote --file schema.sql
npx wrangler secret put FLAG_SECRET           # any long random string
npx wrangler secret put BOOTH_PIN             # PIN you announce at the booth
npx wrangler secret put ADMIN_KEY
npx wrangler secret put CTF_KEY               # same value as CTF_KEY in the labs app
npx wrangler secret put OPENROUTER_KEY        # optional
npx wrangler deploy

Set CTF_KEY for the labs app in a .env file next to docker-compose.yml, and make the labs reachable from the internet (for example with Cloudflare Tunnel or Tailscale Funnel), then put that URL in LABS_URL.

Admin (all need ?key=ADMIN_KEY): GET /admin/stats (sign-ups, solves, LLM calls), GET /admin/seats.csv (name and email of sign-ups, ?new=1 for only new ones), POST /admin/llm-mode. Sign-up also queues a souvenir receipt for a thermal printer (/api/print/next, PRINT_KEY); without a printer the queue just fills up and does no harm.

Reset between events: npx wrangler d1 execute aivillage-ctf --remote --command "DELETE FROM solves; DELETE FROM players; DELETE FROM print_jobs; DELETE FROM sqlite_sequence;"

Customize the challenges (prompts, filters, points) at the top of ctf/src/index.js, and the event details in ctf/public/index.html.

Credits

Inspired by the AI Village workshops. Built by the Cyber Defenders Program for Merritt College Cybersecurity.

Only hack AI systems you have permission to test.

About

AI Village: hands-on AI security labs and a prompt injection CTF for students

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages