Ten 5-minute labs, each one vulnerability in the style an AI assistant actually generates, a guided fix, and an automatic check. Free labs are shown in full so you can judge accuracy before paying.
An assistant wired up OpenAI and Stripe by pasting the keys straight into the server file. Move them out of the code without breaking the app.
Scenario: server.js for a small Express app. It summarizes text with OpenAI and creates Stripe Checkout sessions. The keys below were pasted in while prototyping and the file is about to be committed.
import express from "express";
import OpenAI from "openai";
import Stripe from "stripe";
const app = express();
app.use(express.json());
const openai = new OpenAI({ apiKey: "sk-proj-4fJ9kQ2xR7tLmN8vB3cZ6wY1aE5dH0gP2sK9uX4iO7qT" });
const stripe = new Stripe("sk_test_51NxT2bKq8RmYv4LpQ7wE3cZ9aB1");
app.post("/api/summarize", async (req, res) => {
const completion = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: "Summarize the user's text in three bullet points." },
{ role: "user", content: req.body.text },
],
});
res.json({ summary: completion.choices[0].message.content });
});
app.post("/api/checkout", async (req, res) => {
const session = await stripe.checkout.sessions.create({
mode: "payment",
line_items: [{ price: req.body.priceId, quantity: 1 }],
success_url: "https://example.com/thanks",
});
res.json({ url: session.url });
});
app.listen(3000);
Run it in your AI client: ask "start lab lab-01-secrets", fix the code, then "check my lab". Progress saves to your account.
A user search endpoint builds its SQL with an f-string. Make the query safe without changing what it returns.
A support bot pastes the customer's message into its system prompt. Separate instructions from data so a message cannot rewrite the bot's rules.
An ops helper asks a model for a shell command and runs whatever comes back. Let the model choose, but never let it execute.
Generated login code compares plain-text passwords, issues tokens that never expire, and "checks" tokens with jwt.decode. Fix all three.
Invoice endpoints require login but load any invoice by ID. Make every lookup belong to the signed-in user.
Comments support markdown, so the assistant rendered them with dangerouslySetInnerHTML. Keep markdown, lose the script injection.
A link-preview endpoint fetches whatever URL it is given, including internal addresses. Restrict where the server is allowed to go.
An avatar upload saves any file, of any size, under the name the client chose, inside the static folder. Lock it down.
A project .mcp.json pulls unpinned packages, embeds an API key, gives a filesystem server your whole home folder, talks to a server over plain HTTP, and pipes a script from the internet into a shell. Make it safe to commit and safe to run.
Scenario: This .mcp.json is checked into a team repository so everyone's assistant gets the same tools. Every server listed runs with the permissions of whoever opens the project, and every tool description it returns goes straight into the model's context.
{
"mcpServers": {
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": {
"BRAVE_API_KEY": "BSAk3x9Qw7Lm2Pz8Rt5Vy1Nc4Hd6Jf0"
}
},
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/sam"]
},
"team-wiki": {
"url": "http://wiki-mcp.internal.example.com/mcp"
},
"db-helper": {
"command": "sh",
"args": ["-c", "curl -fsSL https://get.example.dev/db-mcp.sh | sh"]
}
}
}
Run it in your AI client: ask "start lab lab-10-mcp-install", fix the code, then "check my lab". Progress saves to your account.