In short

Train each role on the weaknesses it actually ships, with labs and fixes that have failing tests, not slides. Give everyone a short hands-on onboarding path, add role tracks for web and API, identity, platform, AI and cryptography work, and send engineers to the matching fix card when a finding with that CWE lands on them. Keep a dated record per person for PCI DSS 6.2.2 and SSDF PO.2.2, but judge the program by outcomes: fewer repeat findings of the trained CWE in each team, compared with that team's own history.

  • Do make every module hands-on: a lab or project whose tests fail until the learner fixes the code.
  • Do pick topics from your own findings by CWE and team, not from a generic top-10 list.
  • Do train just in time: link the fix card for a finding's CWE in the ticket and ask for its test on the fix.
  • Do keep per-person, dated training records with topics and evidence, because PCI DSS 6.2.2 requires yearly training for developers of bespoke and custom software.
  • Don't report completion rates, quiz scores or hours as success; they are inputs. Report repeat findings and time to fix for trained weaknesses.

Verify it

  1. Pick five developers at random and find, for each, a dated training record from the last 12 months with topics and evidence of a hands-on exercise.
  2. Check that each team's training topics match its own top CWEs from the last two quarters of findings.
  3. Run the repeat-findings comparison for every team trained more than six months ago and act on the teams that show no improvement.
  4. Open three recent security tickets and confirm each links the fix card or guide for its weakness.
  5. Confirm the program report leads with outcome measures and lists completion figures only as inputs.
Applies to
  • PCI DSS v4.0.1, Requirement 6.2.2
  • NIST SSDF 1.1, task PO.2.2
  • OWASP SAMM 2.2.0, Education and Guidance practice
  • Script Python 3.14 standard library (tested)

Engineering organizations of any size that need developers to write fewer vulnerabilities, and those that must show training evidence for PCI DSS, NIST SSDF or ISO/IEC 27001.

Part of
Workflow: Build an AppSec program
Learning goals and prerequisitesAbout 29 minutes: 9 to read and 20 for the exercise

What you will learn

  • Build role-based, hands-on curricula from paths, labs and fix cards.
  • Train just in time by linking fix guidance to findings.
  • Keep training records that satisfy PCI DSS 6.2.2 and SSDF PO.2.2.
  • Measure the effect with repeat findings per team and CWE instead of completion rates.

Before you start

AppSec leads, engineering managers and security champions who plan or run developer training

  • Have access to your findings by CWE and team for the last two quarters.
  • Know which obligations (PCI DSS, SSDF, ISO/IEC 27001) apply to your organization.
  • For the script: Python 3.11 or later.
Go to the guided practice

Why hands-on training instead of slides?

Developers change how they write code after they have broken and fixed the same mistake in code that looks like theirs. A lab with a failing test gives that experience in minutes; a slide deck about the OWASP Top 10 does not. OWASP SAMM makes the same distinction: its first Education and Guidance activity is awareness training for everyone, with an auditable sign-off, and its second is training customized to roles and technologies, including the security nuances of each language and platform.

This site is built for that second kind. The learning paths at /learn/ combine guides with labs that run in the browser and check the learner's fix against attack cases. The downloadable projects on /labs/ come with a starter that fails its tests and a reference fix that passes. The fix cards at /fix/ show a vulnerable, a fixed and a plausible but wrong fix for one weakness in Node.js, Python, Java and C#, each with a regression test.

What do PCI DSS 6.2.2, SSDF PO.2.2 and ISO 27001 A.6.3 require?

Three common obligations ask for training, with different scope. None of them asks for slides; all of them accept hands-on modules if the records show who did what, when, and on which topics.

What do PCI DSS 6.2.2, SSDF PO.2.2 and ISO 27001 A.6.3 require?
RequirementWhoWhat it asksEvidence that satisfies it
PCI DSS v4.0.1 6.2.2Software development personnel working on bespoke and custom softwareTraining at least once every 12 months on software security relevant to their job and languages, secure design and secure coding, and the security testing tools they useDated record per developer listing topics, languages and tools; see /frameworks/pci-dss-requirement-6/
NIST SSDF 1.1 PO.2.2Everyone whose role contributes to secure developmentRole-based training; periodic review of proficiency and of the training itselfCurriculum per role with desired outcomes; review notes; records
ISO/IEC 27001:2022 A.6.3All personnel and relevant interested partiesAwareness, education and training appropriate to rolesAwareness plus role training records within the ISMS
OWASP SAMM 2.2.0 Education and GuidanceEveryone in development, then rolesLevel 1: awareness for all with auditable sign-off. Level 2: role- and technology-specific trainingAssessment answers backed by the same records

What should each role learn?

Start every engineer with the same short, hands-on path, then add one role track. Keep each track to what that role ships. Choose the yearly refresh from the team's own top CWEs rather than repeating the onboarding path.

How do you keep the curriculum in one place?

Store the curriculum as data so the training record, onboarding checklists and reports all read the same source. The file below maps roles to paths, labs and fix cards on this site and states the just-in-time rule. Review it when your top CWEs change and when SSDF PO.2.2's "periodically review" falls due.

training/curriculum.yamlYAML
# Role-based curriculum built from softwaresecurity.com paths, labs and fix cards.
# Paths and labs are hands-on; "evidence" is what the training record stores.
roles:
  all-engineers:
    onboarding: [/learn/developer-foundations/]
    labs: [/labs/authorization/, /labs/webhooks/]
    yearly_refresh: one lab and one fix card chosen from the team's top CWEs
    evidence: lab verdict screenshots or project test runs, dated
  web-and-api:
    onboarding: [/learn/browser-api-defense/]
    labs: [/labs/csrf/, /labs/archive-paths/, /labs/checkout-race/]
    fix_cards: [/fix/xss/, /fix/sql-injection/, /fix/missing-authorization/, /fix/ssrf/, /fix/csrf/]
  identity-and-accounts:
    onboarding: [/learn/identity-lifecycle/]
    labs: [/labs/token-validation/, /labs/recovery/]
    fix_cards: [/fix/jwt-validation/, /fix/session-cookies/, /fix/password-hashing/]
  platform-and-build:
    onboarding: [/learn/supply-chain-assurance/, /learn/runtime-defense/]
    labs: [/labs/sbom-inventory/, /labs/artifact-policy/, /labs/kubernetes-policy/]
    fix_cards: [/fix/hardcoded-secrets/, /fix/tls-certificate-validation/]
  ai-features:
    onboarding: [/learn/ai-application-defense/]
    labs: [/labs/rag-isolation/, /labs/agent-tool-gateway/, /labs/output-rendering/]
  cryptography-owners:
    onboarding: [/learn/cryptography-foundations/]
    labs: [/labs/nonces/]
    fix_cards: [/fix/insecure-randomness/]
  tech-leads-and-champions:
    onboarding: [/learn/appsec-practitioner/]
    practice: [threat model one feature per quarter, review two security-relevant pull requests per sprint]
  security-leads:
    onboarding: [/learn/security-program-assurance/]
    labs: [/labs/release-evidence/]
just_in_time:
  trigger: a finding is assigned to an engineer
  action: link the fix card for the finding's CWE in the ticket and ask for its test to pass on the fix

How do you train at the moment of need?

The best time to learn about SQL injection is when a SQL injection finding is assigned to you. When a scanner, review or report produces a finding, put the matching fix card or guide in the ticket, and ask for the card's regression test, adapted to the code, in the fix. The engineer learns the pattern, the fix arrives with a test, and the record shows training tied to a real weakness.

Look up the card by CWE on the CWE pages at /cwe/ or the Fix a finding router at /workflows/fix-a-finding/. Add the link automatically where your tracker allows it; a ticket template with a "Fix guidance" field filled from the CWE is enough to start.

Which hands-on formats work?

Which hands-on formats work?
FormatGood forWhat makes it work
Browser labsOnboarding and refreshers, 20 to 45 minutes eachAttack cases decide pass or fail; learners see the exploit stop
Downloadable projectsDeeper practice and proof of skillLearners fix the starter until the tests pass; run the tests in CI on their branch for evidence
Fix cardsJust-in-time training in the learner's stackA vulnerable, a fixed and a wrong fix side by side, with the test that tells them apart
Fix-a-real-finding sessionsTeams with repeat findingsPair on a real (closed) finding from the team's code; write the regression test together
Code review practiceTech leads and championsReview seeded pull requests with /domains/appsec/code-review/security-code-review/ as the checklist
Threat modeling practiceDesigners of new featuresModel one upcoming feature using /domains/appsec/threat-modeling/threat-modeling-methods/ and keep the output

What evidence will an auditor ask for?

An assessor for PCI DSS 6.2.2 will ask which developers are in scope, when each was last trained, on which topics, and whether the topics match their job and languages. Keep one record per person per year with dates, topics, languages, tools and the evidence of each module. Prefer evidence an outsider can check: a lab result, a CI run of a project's tests, a merged fix with its regression test.

This site's progress export (the "Export progress" button on learning path pages) downloads a list of completed item IDs stored in the learner's browser. It has no name or dates and is self-reported, so use it as input to your own record, not as the record.

training-records/e-1042-2026.jsonJSON
{
  "person": "e-1042",
  "role": "web-and-api",
  "languages": ["TypeScript", "Python"],
  "period": {"start": "2026-01-01", "end": "2026-12-31"},
  "requirement": "PCI DSS v4.0.1 6.2.2; NIST SSDF 1.1 PO.2.2",
  "modules": [
    {
      "id": "learn/browser-api-defense",
      "completed": "2026-03-12",
      "topics": ["secure design", "secure coding", "security testing tools"],
      "evidence": "lab csrf passed 2026-03-10; project express-api reference tests passed in CI run 81423"
    },
    {
      "id": "fix/sql-injection/node-express",
      "completed": "2026-06-02",
      "trigger": "finding APPSEC-311 (CWE-89)",
      "evidence": "fix merged in PR 2210 with the card's regression test"
    }
  ],
  "tools_covered": ["Semgrep rules used in CI", "dependency scanner"],
  "recorded_by": "appsec-team",
  "recorded_on": "2026-06-03"
}

How do you know training worked?

Completion rate, quiz score, hours and satisfaction show that training happened, not that code changed. Report them as inputs, and judge the program by outcomes in each team's code, compared with that team's own history: teams that volunteer early are often already stronger, so comparing teams with each other misleads.

How do you know training worked?
MeasureTypeWhy
Findings of the trained CWE per team, before and afterOutcomeThe direct question: does the team still ship this weakness?
Time to remediate findings of trained CWEsOutcomeTrained engineers should fix faster; use the definitions in /frameworks/appsec-metrics-and-slas/
Escapes: trained CWEs found in production or by external reportersOutcomeShows whether prevention or only detection improved
Security comments in code review per sensitive pull requestLeading indicatorMore issues caught before merge, if the count of escapes falls too
Completion within 12 months of in-scope developersInput (compliance)Needed for PCI DSS 6.2.2, not a measure of effect
Quiz scores, hours, satisfactionInputUseful for course design only

How do you measure repeat findings before and after training?

The script compares, for each team and trained CWE, the findings opened in a window before the training date with the same window after it. In the sample, checkout's SQL injection findings fell from 3 to 1 in 180 days, while search still had 3 XSS findings after training and billing had 1 IDOR finding in each window. Search is the team to visit: the training did not change what it ships, so look at its templates and code review before scheduling more training.

Small counts are noisy. Use the comparison to decide where to look, not to grade people, and keep the same finding sources (scanner rules, review checklist) across both windows, or the numbers will move for reasons unrelated to training.

repeat_findings.pyPython
"""Compare findings of a trained CWE before and after each team's training.

Usage: python repeat_findings.py findings.csv training.csv [window_days]
Counts findings with the trained CWE in the window before and after the training date.
"""
import csv
import sys
from datetime import date, timedelta


def rows(path):
    with open(path, newline="", encoding="utf-8") as f:
        return list(csv.DictReader(f))


def compare(findings, training, window):
    for t in training:
        trained = date.fromisoformat(t["trained"])
        dates = [
            date.fromisoformat(f["opened"])
            for f in findings
            if f["team"] == t["team"] and f["cwe"] == t["cwe"]
        ]
        before = sum(trained - window <= d < trained for d in dates)
        after = sum(trained <= d < trained + window for d in dates)
        yield t["team"], t["cwe"], before, after


if __name__ == "__main__":
    window = timedelta(days=int(sys.argv[3]) if len(sys.argv) > 3 else 180)
    print(f"{'team':10} {'cwe':8} before after  ({window.days}-day windows)")
    for team, cwe, before, after in compare(rows(sys.argv[1]), rows(sys.argv[2]), window):
        flag = "  <- no improvement" if after >= before else ""
        print(f"{team:10} {cwe:8} {before:6} {after:5}{flag}")

How often, and how long?

  • Onboarding: the foundations path and one role track in the first weeks, about half a day of hands-on work in total.
  • Just in time: a fix card or guide with every security ticket, as the default.
  • Yearly: one refresher per person chosen from the team's top CWEs, which also satisfies the PCI DSS 12-month cycle when records are kept.
  • Quarterly: a review of each team's repeat findings and an update to the curriculum file.
  • Champions: a monthly session built from the organization's own findings, as in /frameworks/security-champions-program/.

Where do training programs go wrong?

  • Buying a video library and reporting completion as success.
  • Teaching the OWASP Top 10 in the abstract instead of the CWEs each team actually ships, in its languages.
  • Training once a year with nothing linking a later finding back to the lesson.
  • Ranking teams or people by training scores; it rewards gaming and hides the teams that need help.
  • Keeping records that cannot answer "who, when, what topics" for an in-scope developer.
  • Treating more training as the answer to every repeat finding when the cause is a missing library, framework default or review step.

Guided practice

Wren, a fictional payments company, has 60 developers. Its auditor asked for PCI DSS 6.2.2 evidence, and leadership wants to know whether last year's training paid off. Use the data to fix the program.

Supplied scenario material
Plain text
Current program (fictional):
- All developers watch a 2-hour OWASP Top 10 video each January; completion 97%; average quiz score 88%
- Records: an LMS export with name, video title, completion date
Teams and languages: checkout (Java), api (Node.js), mobile (Kotlin, Swift), data (Python)
Findings by CWE, last 12 months:
  checkout: CWE-89 x5, CWE-639 x2
  api: CWE-639 x6, CWE-918 x2
  mobile: CWE-312 x3
  data: CWE-502 x2, CWE-89 x1
Security tools in CI: Semgrep and a dependency scanner. The video does not mention either.
Tickets: none link fix guidance.
  1. 1. Check 6.2.2

    Does the current program meet PCI DSS 6.2.2?

    Expected result and reasoning

    Partly. It is yearly and recorded, but 6.2.2 asks for training relevant to job function and languages, secure design and coding, and the security testing tools used; the generic video covers none of the languages or the Semgrep and dependency-scanner tools. The records also lack topics.

  2. 2. Re-plan by role and CWE

    Choose a track and two modules for checkout and api.

    Expected result and reasoning

    Checkout (Java): /learn/browser-api-defense/ with /fix/sql-injection/java-spring/ and /fix/missing-authorization/java-spring/. API (Node.js): /labs/authorization/ and /fix/missing-authorization/node-express/, plus /fix/ssrf/node-express/ for CWE-918. Add a module on reading and triaging Semgrep results for both.

  3. 3. Add just-in-time links

    What changes in the ticket workflow?

    Expected result and reasoning

    Every security ticket gets the fix card for its CWE and stack, and the fix must include the card's regression test adapted to the code; this becomes a dated training record entry.

  4. 4. Replace the success metric

    Leadership cites 97% completion and an 88% quiz average. What do you report instead?

    Expected result and reasoning

    Those are inputs. Report, per team and trained CWE, findings in the 180 days before and after training (for example api CWE-639), time to remediate, and escapes. Keep completion in the compliance appendix.

  5. 5. Spot a non-training cause

    Mobile keeps getting CWE-312 (cleartext storage of sensitive information). Is more training the answer?

    Expected result and reasoning

    Maybe not. Check whether the apps lack a shared secure-storage wrapper; a library and a lint rule may prevent the class better than a course. Train on the wrapper once it exists.

Your deliverable: A one-page plan for Wren: tracks per team with links, the ticket rule, the record fields for 6.2.2, and the outcome metrics leadership will see next quarter.

Wren and its data are fictional. PCI DSS applies to entities that store, process or transmit cardholder data and their service providers; confirm scope with your assessor.

Save a draft on this device to resume later. Automatic saving begins after you choose Save. Drafts are never sent by this application; use synthetic data.

No draft saved on this device yet.

Sources & further reading

The standards, specifications and documentation behind the guidance above. Each is the evidence for a claim on this page; consult it for detail beyond the defaults and versions listed here.

  1. PCI SSC document library: PCI DSS v4.0.1. v4.0.1 (June 2024).
  2. NIST SP 800-218: SSDF 1.1 (PO.2.2 role-based training). Version 1.1 (February 2022).
  3. OWASP SAMM: Education and Guidance, stream A (Training and Awareness)
  4. OWASP SAMM: Education and Guidance practice
  5. BSIMM16 report: Training practice activities. BSIMM16 (January 2026).
  6. OWASP Security Champions Guide
  7. MITRE CWE: CWE-312 Cleartext Storage of Sensitive Information. CWE 4.20.

Reference information

Download this guide as Markdown