🚀 Submit a Challenge — SecDim AppSec Village CTF at DEF CON 34 and Win a ROG Xbox Ally

Secure Design

7hBeginnerFeaturedRubyJavaC#JavaScriptPythonGoTypeScript

Most security vulnerabilities follow predictable structural patterns: programs that use raw input directly, data models that allow values that make no real-world sense, safety checks that disappear during refactoring, and race conditions caused by mutable shared state. This course teaches four defensive design principles -- Parse Untrusted Data, Make Unsafe State Unrepresentable, Make Unsafe Behaviour Impossible, and Immutable Branching -- that address these patterns at the design level. Each principle gives you a concrete technique for structuring code so that whole classes of vulnerability become impossible to express, not just unlikely to occur. No prior security background is required; every concept is taught through code examples in Java, Python, and TypeScript.

Topics

  1. Introduction

    Lesson5m

    An orientation to the four principles covered in this course and how they layer together as a defence. Learn what each principle addresses, how they connect, and what you will be able to do by the end.

  2. Why Input Validation Fails

    Lesson15m

    Generic advice like "validate all inputs" leaves too many questions unanswered. This module examines three anti-patterns -- complex input languages, regex-based validation, and unsafe escaping -- and explains why none of them reliably prevent security vulnerabilities.

  3. Parse Untrusted Data

    Lesson20m

    Parsing is a well-studied discipline with clear rules; validation is not. Learn how parsing differs from validation, why input language complexity is a security concern, and the three steps for building a parser that the rest of the application can trust.

  4. PUD: Void Safety

    Lesson15m

    The first check every parser must implement. Learn why unhandled null and undefined values cause information disclosure and memory vulnerabilities, and how void safety forms the baseline that all subsequent checks depend on.

  5. PUD: Range Safety

    Lesson15m

    Negative quantities, oversized payloads, and numeric overflow are all range problems. Learn how to implement range and length checks correctly, why regex is the wrong tool for this job, and how type coercion in weakly-typed languages can silently break a check that looks correct.

  6. PUD: Character Set Safety

    Lesson20m

    An adversary does not need a forbidden character to bypass a character-level check -- a different encoding is enough. Learn the four ordered steps of character set safety: encoding enforcement, normalisation, case folding, and allowed character verification, and what happens when any one step is skipped.

  7. PUD: Format Safety

    Lesson15m

    A dotless IP address bypasses a string check that correctly rejects `127.0.0.1`. Learn when to use a standard library, when a checksum or control digit is sufficient, and when a bounded regex is appropriate, with a reference table for validating URLs, email addresses, IP addresses, and hostnames.

  8. Parse Untrusted Data Lab

    Lab30m

    Complete this hands-on lab to put your learnings into practice

  9. Make Unsafe State Unrepresentable

    Lesson15m

    Using an integer to represent an age silently introduces thousands of meaningless values into your program. This module explains how loosely defined data models create vulnerability surface and introduces the Shotgun Parser anti-pattern -- scattered validation logic that can never be fully audited.

  10. MUSU: Principle

    Lesson15m

    Placing validity rules at the outer layers of an application does not guarantee they are applied consistently. Learn the principle's definition, why the data model's constructor is the right place for validity rules, and the four steps for turning a generic type into a type that cannot hold an invalid value.

  11. MUSU: Value Object

    Lesson15m

    Value Objects from Domain Driven Design model concepts by their value rather than by identity, enforce validity at construction, and are immutable. Learn the three defining properties of a Value Object and how they directly support the goal of eliminating invalid states from the program.

  12. MUSU: Domain Primitive

    Lesson15m

    A Domain Primitive extends the Value Object with an explicit security focus: fail-fast validation, immutability, and a single authoritative location for all checks on a concept. Learn how to implement one and why any code that receives a Domain Primitive can trust it without re-validating.

  13. MUSU: Union Type

    Lesson15m

    Some domain concepts can be in one of several distinct states, each with a different set of valid attributes. Learn how discriminated union types make invalid state combinations structurally impossible, and how exhaustive pattern matching ensures the compiler verifies that every state is handled.

  14. Make Unsafe State Unrepresentable Lab

    Lab30m

    Complete this hands-on lab to put your learning into practice

  15. Make Unsafe Behaviour Impossible

    Lesson15m

    Security checks enforced by naming conventions and coding style are bypassed as code evolves. This module walks through a codebase that grows over a decade, showing exactly how convention-based checks get skipped when new features are added without any developer intending to introduce a vulnerability.

  16. MUBI: Principle

    Lesson15m

    A safety violation that causes a compile error is caught immediately by the developer. A safety violation that causes a runtime error is caught in production -- or not at all. Learn why shifting detection from runtime to compile time fundamentally changes the security guarantee.

  17. MUBI: Design by Contract

    Lesson15m

    Design by Contract separates preconditions and postconditions from business logic, making a method's requirements explicit and auditable at a glance. Learn how to implement contracts in practice, why they must be active in production builds to provide a security guarantee, and which languages and libraries support this.

  18. MUBI: Phantom Type

    Lesson15m

    A Phantom Type uses a generic type parameter to encode safety state in the type signature itself. Calling a sensitive method with unsafe data becomes a compile error -- the program cannot build. Learn how to implement this technique and why it is the strongest form of the principle.

  19. Make Unsafe Behaviour Impossible Lab

    Lab30m

    Complete this hands-on lab to put your learning into practice

  20. Immutable Branching

    Lesson15m

    A payment check that passes at one moment offers no guarantee a moment later if the checked value can change. This module dissects three ways that mutable state defeats a security check -- field mutation, argument mutation, and race conditions -- and shows that all three stem from the same root cause.

  21. IB: Principle

    Lesson15m

    An immutable object's state cannot change after construction, so the value you check in a branch is always the value you use. Learn what it takes to make a class truly immutable, the critical distinction between an immutable field and an immutable reference, and why immutable objects require no locking to share safely across threads.

  22. IB: Defensive Copying

    Lesson15m

    When you receive a mutable object you cannot control, take ownership of it immediately by copying it before any check or use. Learn how to implement a deep copy correctly in Java, why shallow copies are insufficient, and why the copy alone is not enough -- the check and the action must also be atomic.

  23. IB: EAFP

    Lesson15m

    EAFP eliminates the check-then-use window by attempting the action directly and handling failure as an exception. Learn when EAFP is safe (when the callee checks and acts atomically), when it is not (when those two steps are separate), and how it works alongside Defensive Copying as a complementary technique.

  24. Immutable Branching Lab

    Lab30m

    Complete this hands-on lab to put your learning in practice