Secure coding in C++: common mistakes
You learn, from the defender’s side, how lifetime, type and bounds mistakes in C++ become vulnerabilities and prevent them with guidelines, hardening and fuzzing.
Level 401 · 19 lessons · 15 practice labs
Lessons
Memory and lifetime mistakes
- operator[] versus at(): bounds checking
- Dangling references: string_view, lambdas and return values
- The security impact of iterator invalidation
- Use after move
- Smart pointer pitfalls: cycles and get()
- Short task: find lifetime bugs in a code review
Type and logic mistakes
- Narrowing conversions and integer overflow
- Unsafe casts: reinterpret_cast and C-style casts
- Exception safety guarantees
- Legacy C APIs: memcpy, sprintf and char arrays
- Parsing untrusted input: from_chars and limits
- Keeping secrets in memory and wiping them
- Short task: review a class that reads network data
Prevention
- The C++ Core Guidelines and GSL
- Hardened standard library modes and compiler flags
- Fuzzing a C++ class with libFuzzer
- Security-focused static analysis
- Short task: fuzz, fix and add a regression test
Capstone
- Capstone: a secure code review and fix of a C++ service
Practice labs
- Closing unchecked index access: Make menu code that uses operator[] with a user-supplied index bounds-checked and return a clear error for an invalid index.
- Fixing a view into a temporary string: Fix a header function that returns a string_view into a temporary std::string and sometimes shows garbage by removing the lifetime bug, passing the ASan test.
- Finding five lifetime bugs in a code review: Find the dangling reference, invalidated iterator, use-after-move and get()-pointer bugs in a small session manager, repair them and add a test for each.
- Catching a narrowing conversion: Add a range check to a header writer that silently truncates a size_t length into a 16-bit field and return an error for large input.
- Preventing overflow when sizing an image buffer: Check for overflow in an image loader that allocates a buffer from width times height and pass the UBSan and large-dimension tests.
- Rewriting a parser with unsafe casts: Rewrite a parser that turns network bytes into a struct with reinterpret_cast, free of alignment and byte-order problems, using memcpy and explicit field reads.
- Converting sprintf use to safe formatting: Replace a log function that writes into a fixed char array with sprintf by std::string and std::format.
- Parsing an untrusted number with from_chars: Parse port and size values read with atoi using from_chars and reject trailing characters, overflow and out-of-range values with distinct errors.
- Reviewing a class that reads network data: Find every bounds and state bug in a message reader that trusts the length field and calls memcpy, replace it with a span-based reader and pass the malformed-message tests.
- Wiping a password buffer after use: Write a guard class that zeroes the buffer holding a password at scope end in a way the compiler cannot optimise away.
- Giving an update the strong exception guarantee: Fix a record update left inconsistent by a mid-way exception with copy-and-swap and show state is unchanged in the fault-injection test.
- Clearing smart pointer pitfalls: Fix subscription code that builds two shared_ptr from one raw pointer, stores a get() result and leaks through a cycle so ASan and the leak check come out clean.
- Building with hardening flags: Add the hardened standard library mode and protection flags to the build script and show the out-of-bounds test now terminates in a controlled way.
- Tightening interfaces with GSL types: Redefine functions taking a pointer and length pair with span and not_null and show the static analysis findings are closed.
- Fuzzing and repairing a URL parser: Write a libFuzzer harness for your own URL parser class, repair the crashes found and add the crashing inputs as regression tests.
About this course
You learn, from the defender’s side, how lifetime, type and bounds mistakes in C++ become vulnerabilities and prevent them with guidelines, hardening and fuzzing.
What you will learn
- Memory and lifetime mistakes
- Type and logic mistakes
- Prevention
- Capstone
Prerequisites
You should have practised the topics of the same path up to level 301.
Lab environment
Lessons run in your own Kali Linux terminal that opens in the browser. Nothing to install; the lab starts clean in every lesson.
Frequently asked questions
- Is this course right for my level?
- The course is at level 401; it assumes you know the topics of the lower-level courses.
- Is there anything to install?
- No. Every lesson runs in your own lab environment that opens in the browser.
- How do lessons work?
- Each lesson has 8 to 10 steps and a short quiz. Early steps show the command to type, later steps give less help; if two attempts fail, the solution opens.
- Can I try it for free?
- Yes. The first three lessons of every course are free.