Thinking Like an Attacker
A different way to look at your app
When you build an app, you think about what it should do. When an attacker looks at your app, they think about what it can be made to do.
Every field, every URL parameter, every header, every cookie, every file upload is a question the attacker asks: “What happens if I put something unexpected here?”
Your login form expects an email address. What happens if the attacker types ' OR 1=1 --? Your search bar expects a keyword. What happens if the attacker types <script>alert('hacked')</script>? Your file download expects a filename. What happens if the attacker types ../../../etc/passwd?
This course teaches you to ask these questions yourself, before an attacker does.
The trust boundary
Your app has a boundary between things you control and things you do not. Everything that crosses this boundary from the outside is untrusted input.
Untrusted input includes request bodies, URL parameters, HTTP headers (including cookies), file uploads, data from external APIs, and even data from your own database — because it may have been stored from untrusted input earlier.
That last one surprises people. If a user’s name is stored as <script>alert(1)</script> in your database, it was untrusted input when it went in, and it is still dangerous when it comes out. The database does not sanitize it for you.
Trusted input is limited to code you wrote, environment variables you set, and constants in your source code.
The trust boundary rule: never use untrusted input without validating, encoding, or escaping it first. The specific technique depends on where the input is going (SQL query, HTML template, shell command, file path), and this course covers each one.
How each lesson works
Every vulnerability lesson follows the same structure:
- The attack: We build a vulnerable version of a feature and demonstrate the exploit
- Why it works: We explain what makes the code vulnerable
- The fix: We write the defense, usually a small function
- Verification: We try the attack again and confirm it fails
You will attack your own code. This is the most effective way to understand vulnerabilities: if you can exploit it, you understand it.
What this course covers
Injection (Section 2): SQL injection, command injection, header injection. The attacker injects code into a system that interprets it. The fix: separate code from data.
Cross-site scripting (Section 3): Stored, reflected, and DOM-based XSS. The attacker injects JavaScript into your pages. The fix: encode output for its context, and use CSP as a safety net.
Broken access (Section 4): IDOR, open redirects, SSRF. The attacker accesses data or functionality they should not have. The fix: always verify authorization, validate redirect targets, restrict outbound requests.
File and data handling (Section 5): Path traversal, mass assignment, denial of service via input. The fix: validate paths, pick fields explicitly, limit input size.
A user's display name is stored in your database as '<script>alert(1)</script>'. When is this value considered untrusted input?