Feb 09, 2025·8 min read

Security training for engineers with real code examples

Security training for engineers works better with review comments, short incident stories, and drills that fit normal sprint work.

Security training for engineers with real code examples

Why engineers tune out slide decks

Most engineers do not hate security. They hate training that feels disconnected from the code they ship every week.

A generic slide deck usually opens with rules, acronyms, and scary stories from some other company. People sit through it, but they do not connect it to their own pull requests. If the lesson never shows up in their repo, it feels like somebody else's problem.

Long decks make that worse. After a few slides, the pattern is obvious: risk, warning, policy note, another warning. There is nothing to solve, nothing to review, and nothing to argue about. Attention drops because the format asks engineers to listen passively when they usually learn by testing ideas.

Real diffs stick for a simple reason. They have stakes.

A code review comment on an unsafe query, a hardcoded token, or a missing auth check stays in memory because it interrupted real work. The engineer can see what changed, why it mattered, and how the fix looked in context. That lasts longer than a paragraph in a policy document.

Teams also remember small incident details better than abstract advice. Someone pushed a debug endpoint. A secret leaked into logs. A retry loop hammered a third-party API after an auth failure. Those short, awkward stories stay with people because they sound familiar.

Security training works best when it sits close to review and release work. If it lives off to the side as a separate ritual, it feels like homework. Under pressure, teams skip homework and keep merging.

The sessions that hold attention usually use material engineers already care about: recent pull requests, review comments that changed a fix, incident snippets from real releases, and tests that should have caught the issue.

This also respects people's time. Instead of asking them to absorb a long deck and hope they apply it later, show one mistake, one consequence, and one better version. That is easier to remember on a busy Tuesday when somebody is about to approve a risky change.

What to teach with real code

Start with code the team already touched. Skip famous breach stories unless they match a mistake people make in pull requests every week. If reviewers keep finding missing auth checks, raw SQL strings, weak input validation, or secrets in logs, teach those first.

Use examples that fit on one screen. An engineer should be able to read the bad version, spot the risk, and understand the fix in about two minutes. If the snippet needs ten minutes of setup or too much app context, it is too big.

A side-by-side rewrite usually beats a long explanation because it shows the exact decision point. People remember the line they should stop writing.

// unsafe
const query = `SELECT * FROM users WHERE email = '${email}'`;
const user = await db.query(query);

// safer
const query = "SELECT * FROM users WHERE email = $1";
const user = await db.query(query, [email]);

That example teaches one rule: never build SQL with string interpolation. Keep the rule short enough that someone can use it in the next review without opening a handbook.

The same pattern works for access control, file uploads, deserialization, and logging. Pick a real issue, trim the code until only the risky part remains, then show the safer rewrite. Most teams learn faster from five tiny cases than from one giant case study.

A useful set might include an auth check a handler forgot, a log line that exposed a token, a file upload that trusted the filename, a query built from user input, and a dependency update that fixed a known bug.

End each example with a rule the team can apply right away. Keep it plain: "Check ownership before returning data." "Do not log secrets." "Allow only known file types." That is enough.

If you review engineering work across several products, this scales well. You do not need custom training material for every team. You need a small set of real mistakes, a safer rewrite, and a rule people can use before the meeting ends.

How to build a session from your own pull requests

Start with review comments from the last few weeks, not a policy document. Pick five to seven comments that led to an actual code change. If the thread ended in debate and nobody changed the code, skip it. People remember fixes they can see.

Remove names before you share anything. Strip out the author, reviewer, ticket number, and any product detail that turns the session into guess-who. The point is pattern recognition, not blame. If your team uses GitLab or a similar review tool, this cleanup usually takes less time than building new slides.

Group the examples by pattern, not by project. A session built around "missing auth check," "unsafe log output," or "input trusted too early" lands better than one split across Repo A, Repo B, and Repo C. Engineers start noticing the same mistake in different code, which is exactly what you want.

For each example, keep the package small: the original snippet, the review comment that changed the code, the revised snippet, and one line about what the reviewer noticed first.

That last line matters more than it looks. "User ID came from the request body" or "debug log printed the token" teaches people where to look under time pressure. It turns a review comment into a habit.

Order the examples from obvious to subtle. Put the easy win first so the room warms up fast. Save the trickier case for later, when people already trust the format. A good mix might include one bug that could expose data, one weak validation check, one risky permission shortcut, and one comment that caught a bad assumption before production.

Keep the code short enough to fit on one screen. If people need to scroll, they stop thinking about the mistake and start parsing the file. Trim helpers, mocks, and setup code unless the bug lives there.

This is why your own pull requests work so well. The examples already match your stack, your naming, and your bad habits. That makes the lesson stick the next time someone opens a review tab.

Run a 45-minute session

Most teams lose focus in the first five minutes. A good session feels closer to a code review than a lecture. Put one flawed snippet on screen and ask, "What bothers you first?" Do not explain it yet. Let people react, even if they miss part of the problem.

app.get("/user", async (req, res) => {
  const query = `SELECT * FROM users WHERE id = ${req.query.id}`;
  const rows = await db.query(query);
  res.json(rows);
});

Give them two minutes. Ask them to name the risk and say how they would fix it. Engineers usually wake up fast when they can inspect real code instead of listening to abstract rules.

Then spend about ten minutes on two review examples from recent work. Pick small pull requests, not horror stories. One example might show weak input validation. The other might show secrets in logs, a missing auth check, or unsafe file handling. Show the original code, the review comment, and the fixed version. If people can read each example in under a minute, the pace stays sharp.

Next, tell one short incident story. Keep it plain. Say what happened, what users saw, what the team missed, and where the miss began. A simple case works best, like a debug endpoint that stayed open longer than anyone expected. Then ask one direct question: "When could we have caught this?" That moves the room away from blame and toward pattern spotting.

A simple agenda is enough: five minutes for the bad snippet and first reactions, ten minutes for review example one, ten minutes for review example two, fifteen minutes for the incident story and discussion, and five minutes for a short drill plus one final rule.

End with a quick drill. Hand out a tiny diff with one obvious issue and one subtle one. Ask each person to write a one-sentence review comment. Short comments matter because real code reviews rarely need mini essays.

Close on one rule people can remember the next day. Keep it short enough to fit in a pull request template, such as "Trace user input to the sink before you approve." That single line will last longer than twenty slides.

Turn incidents into short teaching moments

Tighten Your Security Reviews
Ask Oleg to review the pull request patterns your team keeps missing.

Engineers remember a bad deploy faster than a polished policy slide. A short incident story works because it feels real and gives people something concrete to inspect: a choice, a missed check, and a fix.

Keep each story small. Strip it down to four parts: the trigger, the mistake, the impact, and the fix. If the story needs ten minutes of company history before anyone understands it, trim it harder.

Ordinary details make the lesson stick. A rushed Friday deploy. A reused token copied from a test script. A debug flag left on because the team wanted to "clean it up later." Those details sound familiar, which is why people pay attention.

Do not turn the story into a public trial. Remove names, teams, and any detail that points to one person. The useful question is not "who caused this?" It is "why did this choice feel reasonable at the time?" That shift keeps the room honest and makes people more willing to talk.

A good incident note can fit on half a page. For example: a late Friday hotfix went out, the service accepted an old internal token in production, one customer account was exposed to another tenant's data, and the team fixed it by rotating tokens, adding environment checks, and blocking shared test secrets.

Then ask one short follow-up: what small check would have caught this earlier? In many cases, the answer is boring in a good way. A pull request checklist. A test that rejects test tokens in production. A review comment on missing auth boundaries. Boring checks prevent expensive weekends.

This is where training gets better. Instead of teaching a rule in the abstract, you attach it to a moment people can picture. They can imagine the deploy, the pressure, the shortcut, and the cleanup.

End with one action the team will actually use next week. Add one review question, one lint rule, or one tiny drill to the next workshop. If the lesson changes a daily habit, it lasts.

A realistic example from bug to fix

Most security lessons land better when the bug looks ordinary. An engineer tries to trace a login problem, adds one debug line, and pushes a small pull request. The change looks harmless because it only touches logging.

// bad
logger.info("session check", {
  userId: user.id,
  sessionToken: req.cookies.session_token
})

// better
logger.info("session check", {
  userId: user.id,
  hasSession: Boolean(req.cookies.session_token)
})

That one line can create a real incident. The app sends logs to a shared system so support staff can help users faster. A support teammate opens a ticket, searches the log stream, and can now read a live session token. Nobody hacked anything. Nobody broke a rule on purpose. A normal troubleshooting habit created the risk.

That is why this example sticks. Most engineers have added extra logging when they felt pressure to fix a bug. They can see themselves making the same choice, which makes the lesson feel real instead of theatrical.

The fix starts with cleanup. The team removes the token from the code and deploys the patch. Then they rotate exposed secrets or invalidate active sessions that may have leaked through logs. After that, they check who could read the log entry and whether anyone copied it into a ticket, chat, or incident note.

The last step matters most for future pull requests. Add a review check that treats sensitive logging as a blocker. Reviewers should stop any change that prints tokens, cookies, authorization headers, passwords, or full API keys. A short checklist works well, and a simple pattern scan in CI helps catch the obvious cases before review even starts.

This kind of example works because it does not depend on a dramatic breach story. It shows a plain mistake, a clear fix, and one rule people can use the same day: if a value can unlock an account, do not print it.

Mistakes that make the lesson fade fast

Review Infra And Delivery
Review CI, logging, and deploy habits together so security lessons stick.

Most teams lose the room when they try to cram five security topics into one meeting. People walk out with a foggy memory of terms and no clear change to make in their next pull request. One session should fix one pattern, or two that naturally belong together.

A short session on unsafe input handling will teach more than a broad talk that jumps from secrets to auth to logging to access control. Engineers remember a small rule they can use today. They forget a packed tour of everything that can go wrong.

Fake code causes the same problem. If the sample looks like a toy app nobody on the team would ship, people treat it like schoolwork and move on. Use a real snippet from your own codebase, trim names if you need to, and keep the messy parts in place.

Familiar examples start real discussion. A rushed API handler, a Terraform change with wide permissions, or a helper that skips validation will get a stronger reaction than clean demo code.

The format matters too. If one person talks for forty minutes, everyone else checks messages and waits for the meeting to end. Give the group a few minutes to read the diff first. Then ask where they would comment, what they would block, and which test they would add.

People remember the debate they had with a teammate far longer than a rule on a slide.

Another common mistake is ending with nothing concrete. If the meeting stops at "any questions?", the lesson fades by the next sprint.

Close with one small action. Add a review rule to the pull request template. Run a five-minute drill on a similar snippet next week. Check the next ten pull requests for the same mistake. Name one person to report what changed.

Without a drill, a review rule, or a follow-up check, the session turns into trivia. Teams forget trivia fast.

Quick checks after every session

Support Your Small Team
Get senior CTO support without rushing to a full-time executive hire.

A session worked if people change one habit the same day. If everyone nods, says "good points," and goes back to the same review patterns, the lesson is gone by tomorrow.

Good training leaves a small trace in the team process right away. That trace might be a fixed bug, a new review note, a bot rule, or one sharp question people start asking in pull requests.

Before the meeting ends, ask each engineer to name one thing they will scan for in code review that week. Make the group fix one real example before they leave. Add the new check to the pull request template, review checklist, or bot rules. Then bring the same topic back next sprint.

That first check sounds simple, but it tells you whether the lesson was concrete enough. "Be more careful with auth" is too vague. "Look for user input reaching SQL without parameter binding" is clear. "Check whether file uploads trust the client MIME type" is clear too.

The repair matters even more. Teams remember what they fix with their own hands. If you spent thirty minutes on unsafe redirect logic, end by changing the real handler, adding the test, and merging the fix. One small repair beats ten polished slides.

Then lock the lesson into the workflow. If the issue was missing rate limits on a password reset route, add a line to your review template that asks whether the endpoint can be abused. If you use a review bot, teach it to flag the pattern. Memory fades fast. Process lasts longer.

A follow-up in the next sprint keeps the lesson alive. Bring back the same topic for five minutes and ask a blunt question: did anyone catch this issue in review after the session? If the answer is no, the training was too abstract or the check never made it into daily work.

One practical rule helps: end every session with a changed artifact. A merged fix, a new checklist item, a bot update, or a test case is enough. If nothing changed outside the meeting notes, the session probably felt useful and still did little.

Next steps for your team

Most teams try to cover too much at once. That turns a useful session into background noise by next week. Pick one issue your team misses often in review, then stay with it for a month.

Good topics are boring in a useful way: unsafe input handling, auth checks skipped in edge cases, secrets in test fixtures, or weak tenant isolation. Repetition works better than novelty. If engineers see the same pattern in code review, a short drill, and one real incident, they start catching it on their own.

A simple monthly rhythm is enough. In week one, show one real bug from a pull request and discuss the fix. In week two, run a ten-minute drill with a similar mistake in a new file. In week three, share a short incident snippet from your own system or a close internal example. In week four, review recent pull requests and count whether the mistake shows up less often.

Keep a small bank of material so you do not rebuild every session from scratch. Save review comments that taught something useful. Save trimmed incident notes with the cause, the bad assumption, and the fix. Over time, that becomes your own set of code review examples, and it will fit your stack far better than generic training.

If AI writes part of your code, update the review habit too. Reviewers should check the prompt when it affects security-sensitive logic, read generated tests with suspicion, and look closely at how the code handles secrets. AI often produces code that looks clean and still misses rate limits, permission checks, or safe defaults.

That part deserves more attention than many teams give it. AI-assisted development can speed up delivery, but it also changes where mistakes enter the codebase. A reviewer who only scans the final diff will miss too much.

If your team needs an outside pass, Oleg Sotnikov at oleg.is works as a Fractional CTO and startup advisor and helps teams tighten code review, infrastructure, and AI-assisted development practices. That can help when the same bug pattern keeps coming back or when the team is moving too fast to fix the process alone.

Done well, security training should leave behind a habit, not a slide deck.

Frequently Asked Questions

Why do engineers tune out security slide decks?

Because most slide decks feel far away from daily work. Engineers learn faster from diffs, review comments, and fixes they can use in the next pull request.

What works better than generic security slides?

Use small examples from your own codebase. Show the risky snippet, the review comment or incident detail, and the safer rewrite so people can see the choice in context.

How much code should I show in one training example?

Keep each example small enough to fit on one screen. If someone needs a long setup to understand the bug, trim it until the risky line and the fix are obvious.

Which security topics should we teach first?

Start with the mistakes your team keeps making in review. Missing auth checks, unsafe SQL, secrets in logs, weak input validation, and risky file handling usually give you quick wins.

How do I turn pull requests into training material?

Pull examples from recent review threads that ended with a real code change. Remove names and product details, group the snippets by pattern, and keep only the code and comment that taught the lesson.

What does a good 45-minute session look like?

Run it like a code review, not a lecture. Open with one flawed snippet, spend time on two recent review examples, tell one short incident story, and end with a tiny drill plus one rule people can use tomorrow.

How do I use incidents without turning the meeting into blame?

Strip the story down to the trigger, the mistake, the impact, and the fix. Remove names and ask why the choice felt reasonable at the time so the team talks about the pattern instead of the person.

How do I make the lesson stick after the session ends?

End with a changed artifact, not just notes. Add one review question, one test, one bot rule, or one merged fix so the lesson shows up in daily work right away.

How should we review AI-generated code during security training?

Treat AI output like junior code that looks polished. Reviewers should check prompts when they affect sensitive logic, read generated tests with doubt, and look hard at secrets, permissions, and safe defaults.

When should a team ask for outside security training help?

Bring in outside help when the same bug pattern keeps returning, reviews feel rushed, or the team needs a better process around code review, infrastructure, and AI-assisted development. A Fractional CTO such as Oleg Sotnikov can give the team a practical outside pass and help turn training into habits.