AI Red Teaming Lab 1: Local & Uncensored LLM Setup — a technical write-up
This is the first lab in our AI-based red teaming course. It has two exercises:
standing up a local uncensored LLM (Dolphin-LLaMA3 via Ollama, wrapped in a
small FastAPI chat app) and a cloud-hosted uncensored chatbot
(Groq's llama-3.1-8b-instant behind a Flask app with an adversarial system prompt).
The teaching point is simple but foundational: guardrails are a property of the model and
its serving stack, not of the prompt — and a red teamer who controls the model controls the answers.
Attack path (how the steps chain)
- Attempt payload generation on a frontier model — ChatGPT refuses the reverse-shell prompt, proving guardrails are the first obstacle an attacker hits.
- Stand up an attacker-controlled model — pull Dolphin-LLaMA3 into Ollama; no logging, no API bill, no refusal policy.
- Expose it as a reusable endpoint — the FastAPI chat app turns the local model into a service any later tool (or lab) can call.
- Replay the refused prompt — the same payload request now succeeds, giving the operator on-demand offensive tooling.
- Cloud fallback — a Groq-hosted model with an anti-refusal system prompt provides the same capability when local hardware is unavailable.
This chain is the foundation for the whole series: Labs 3–7 all assume an LLM endpoint that will answer offensive questions, and this lab is where that endpoint comes from.
1. Why this lab exists
Every later lab assumes you have an LLM endpoint that will actually answer offensive-security questions. Frontier hosted models (ChatGPT, Claude) refuse payload-generation requests by design. The lab demonstrates this refusal first, then shows two ways around it that are legitimate in a lab context:
- Run your own model locally — Dolphin is a fine-tune of LLaMA with reduced refusals. No API bill, no logging, fully offline.
- Use a permissively-prompted hosted model — Groq serves open weights fast; a crafted system prompt suppresses refusal behavior.
Hardware guidance from the lab docs: 7B models need 8–12 GB RAM, 13B needs 16–24 GB,
70B needs 64+ GB. On my M-series MacBook, dolphin-llama3 (8B, ~4.7 GB) runs comfortably.
2. Exercise 1 — Local LLM: Ollama + Dolphin + FastAPI
2.1 Install and verify Ollama
# Windows (PowerShell) irm https://ollama.com/install.ps1 | iex # Linux curl -fsSL https://ollama.com/install.sh | sh sudo systemctl start ollama && sudo systemctl enable ollama # macOS: download from https://ollama.com (or brew install ollama) ollama --version # verify
2.2 Pull and run the model
ollama pull dolphin-llama3 # ~4.7 GB download ollama run dolphin-llama3 # smoke-test in the terminal ollama list # confirm the model is present
2.3 Run the web application
The app (dolphin-web/app.py) is a thin FastAPI wrapper: it accepts
POST /chat with a JSON {"message": "..."} body and forwards it to the
local Ollama daemon at http://localhost:11434/api/generate with
"model": "dolphin-llama3:latest" and "stream": false, then serves a
single-page chat UI from static/.
python -m venv venv
source ./venv/bin/activate # Windows: .\venv\Scripts\activate.bat
pip install fastapi uvicorn requests
uvicorn app:app --reload # http://127.0.0.1:8000
2.4 The guardrail comparison (the actual exercise)
Step 5 of the lab asks ChatGPT directly: "generate the reverse shell payload for the linux machine". ChatGPT refuses — the expected, documented outcome; screenshot it for the report. Step 6 repeats the identical prompt against the local Dolphin app.
Dolphin answered without refusal. One honest caveat: an 8B local model's quality is uneven — my run produced a rough bash one-liner rather than a polished msfvenom-style payload. The lesson is about control and refusal behavior, not output quality. For better output, iterate with more specific prompts (LHOST/LPORT, payload format, encoder constraints).
3. Exercise 2 — Cloud "uncensored" chatbot: Groq + Flask
The second app (Uncensored LLM/main.py) uses Groq's hosted
llama-3.1-8b-instant with a system prompt that explicitly forbids refusal phrases
("I can't", "I cannot", "not allowed", "illegal", "malicious"...) and instructs the model to
answer "directly, concisely, and technically" with no disclaimers.
python -m venv venv
source ./venv/bin/activate
pip install flask groq
# paste your Groq API key into main.py line 6
python main.py # http://127.0.0.1:5000
Get a Groq API key from groq.com → API Keys → Create. The interesting discussion point for the writeup: this exercise shows that safety behavior on hosted open-weight models is largely system-prompt deep. The same weights refuse or comply depending on the serving instructions — which is exactly why system-prompt leakage and override are real attack surface (revisited in later labs).
4. Troubleshooting (what actually goes wrong)
ollama listerrors → the daemon isn't running; start the Ollama app orollama serve.- App returns
Ollama error: {...}→ model tag mismatch; the code expectsdolphin-llama3:latest. - Groq 401 → key not pasted or pasted with quotes/whitespace. Note: the shared lab keys floating around the course workflows are revoked — generate your own.
- Slow first response → model is being loaded into memory; subsequent turns are fast.
- Windows venv activation fails in PowerShell → run
Set-ExecutionPolicy -Scope Process RemoteSignedfirst.
5. Defensive takeaways
- Refusals are a policy layer, not a capability limit — assume adversaries run uncensored local models.
- System prompts are not a security boundary; anything they "forbid" can be re-permitted by whoever controls the stack.
- Egress monitoring and payload execution controls matter more than hoping the attacker's chatbot says no.