This entire curriculum has been built on dynamic, memory-managed languages — Python, JavaScript, TypeScript — where an entire historically enormous category of security vulnerability simply can't occur. Understanding why it can't, and what it actually looks like in a language where it can, matters the moment this curriculum's code reaches outside that world.
4 min read
Every language this curriculum has taught manages memory automatically — there's no way to write code in Python or JavaScript that directly reads or writes an arbitrary memory address, because the language simply doesn't expose that capability at all. Languages like C and C++ do: a program manipulates raw pointers and fixed-size buffers directly, and the language trusts the programmer to keep every access within bounds. Memory-safety bugs are exactly what happens when that trust is violated — and they've been, for decades, one of the single largest sources of serious, remotely-exploitable vulnerabilities in real software (operating system kernels, browsers, and widely-used C libraries, specifically because so much foundational infrastructure is written in C or C++ for performance reasons).
char buffer[8];
strcpy(buffer, user_input); // no bounds check — if user_input is longer than 8 bytes...A fixed-size buffer of 8 bytes given input longer than 8 bytes simply keeps writing past the buffer's actual boundary, overwriting whatever memory happens to sit immediately after it — other variables, or, in the most serious case, the stored return address that controls where the program jumps to next once the current function finishes. A carefully crafted overflow can overwrite that return address with an address of the attacker's own choosing, hijacking the program's control flow entirely — this is the classic mechanism behind a huge fraction of historical remote-code-execution vulnerabilities.
A fixed-size integer type has a maximum representable value; adding 1 to that maximum wraps around to the minimum (often a large negative number, or zero, depending on signedness) instead of raising an error. A size calculation that silently wraps from a huge value to a tiny or negative one can cause a subsequent buffer allocation to be far smaller than the code assumed — turning an arithmetic quirk into the setup for a buffer overflow one step later.
free(object);
object->do_something(); // using memory that's already been released back to the systemOnce memory is explicitly freed, the language makes no guarantee about what's there afterward — it might still hold the old data, or it might already have been reallocated for something completely different. Code that keeps using a pointer after freeing it (a genuinely easy mistake in a large codebase, where it's not always obvious whether some other code path already freed the same object) can read or write data belonging to an entirely unrelated, subsequently-allocated object — a bug class responsible for a large share of real, severe vulnerabilities in browsers specifically, which juggle enormous numbers of short-lived objects.
A garbage-collected language never lets a program free memory manually, and array/string operations are always bounds-checked — there is no strcpy-into-a-fixed-buffer equivalent, no manual free(), and therefore no use-after-free or buffer overflow of this specific kind possible at all. This is a genuine, structural safety property of the language itself, not a matter of writing more careful code — which is exactly why a systems language like Rust markets "memory safety without a garbage collector" as its core selling point: it gets Python/JavaScript's safety guarantee while keeping C/C++'s manual-memory performance profile, by having the compiler enforce the bounds-and-lifetime rules at compile time instead of relying on runtime garbage collection.
Every real application ultimately runs on top of memory-unsafe infrastructure somewhere — language runtimes (CPython and V8 are themselves written in C/C++), native extension modules, the operating system kernel. A vulnerability disclosed in any of those layers is a vulnerability the application inherits, the exact same supply-chain reasoning Web Security's dependency lesson already established, just one layer further down the stack than a package manager tracks.
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. Why can't a buffer overflow occur in ordinary Python or JavaScript code?
2. What is a use-after-free vulnerability?
3. What does Rust offer that distinguishes it from both C/C++ and garbage-collected languages?
Application Security & Secure Coding