A good secure coding lab has five parts: one bug class, a working exploit, a small codebase to fix, a test that fails before the fix and passes after, and a short explanation of why the fix works. Keep it to 30 minutes of work and one idea.
The five-part template
1. A single bug class. If a lab has an injection flaw, an access flaw and a logging flaw, people chase whichever is easiest and miss the lesson. One lab, one idea.
2. A reachable exploit. Give a starting point, such as "the search box," and a goal, such as "read another user's order." Attendees should be able to reach success without special tooling.
3. Editable code. Provide a small service, perhaps 100 to 300 lines, that the learner can change and rerun. Remove everything unrelated to the bug.
4. A test that proves the fix. Ship a failing test that encodes the exploit. When the test passes, the learner knows the fix works. Passing tests also give instant feedback without a facilitator.
5. A short explanation. A paragraph after the lab: what was wrong, the principle, and what to look for in real code.
Writing good hints
Use three levels. Level one nudges ("Look at how the query is built"). Level two points to the file and function. Level three shows the vulnerable line. Reveal them one at a time and let learners ask.
Common mistakes
- Too much scaffolding. If setup takes 20 minutes, the lab is already over.
- Unrealistic code. A bug that no real developer would write teaches nothing. Base flaws on patterns from real reviews.
- Fixes that only work in the lab. If the solution is "add one filter for this exact payload," the lesson is wrong. Aim for fixes that remove the whole class, such as parameterized queries or deny-by-default checks.
- No time check. Try the lab on a colleague with a stopwatch, then add 50 percent for real attendees.
Reviewing a lab
Have a second engineer attempt the exercise cold. Note where they hesitate, and fix those places. Check also that the exploit works only against the lab and cannot reach real services, and that nothing in the repository contains real credentials.
Keep a lab library
Store labs in a repository with a README per lab: goal, estimated time, prerequisites, hints and solution. Version them so that a lab can be updated when the framework changes. Labs rot quickly when dependencies move.
Related reading: how to run a lab on parameterized queries.
Quick check
How long should one lab take?
About 30 minutes for most participants, including reading, exploiting and fixing. Longer labs belong in a CTF or a multi-session course.
Should the solution be published with the lab?
Keep it in the repository but out of the learner's path until the session ends, so people can review it afterwards.
Last reviewed: 19 October 2026.