The weekly web security email for developers.
One vulnerability. One code example. One practical fix. Under five minutes.
Can another website click your buttons?
An invisible iframe can turn a user's click into a real action.
Content-Security-Policy: frame-ancestors 'none';
Would this malicious URL pass your allow-list?
A string prefix can hide an attacker-controlled hostname.
value.startsWith('https://safe-app.com')
See what arrives in your inbox
One useful idea. 💡
Under five minutes.
Every email is a short Knowledge Pill — one practical lesson you can read in under five minutes and use right away.
Security Email #1 · Clickjacking
Bartosz from Dev Academy
Can another website click your buttons?
Hi developer,
Imagine a user visits an attacker-controlled page while signed in to your application. The attacker places your app inside a transparent iframe over a harmless-looking button.
If the framed page has an authenticated session, the browser delivers the user's click to the real button inside your app.
<iframe src="https://your-app.com/account"
class="invisible-overlay"></iframe>
- The user sees the attacker's interface, not the framed page.
- The click can trigger a real state-changing action in your app.
- Authentication alone does not prove that the user intended the action.
Return a Content Security Policy header with frame-ancestors. Use 'none' when your application should never be embedded.
Content-Security-Policy: frame-ancestors 'none';
The browser now refuses to render your application inside an attacker-controlled frame, preventing the clickjacking setup.
Stay curious, Bartosz
Security Email #2 · URL allow-list
Bartosz from Dev Academy
Would this malicious URL pass your allow-list?
Hi developer,
Imagine an agent opens a pull request containing this URL allow-list. The intention is to accept URLs from safe-app.com and reject everything else.
An attacker can put the trusted text at the beginning of a hostname they control, and this validator will accept it.
value.startsWith('https://safe-app.com')
- https://safe-app.com.evil.com passes the string check.
- String methods do not understand URL or hostname boundaries.
Let the URL parser identify the scheme, hostname, and port, then compare the complete origin your application trusts.
const origin = new URL(value).origin;
const trusted = origin === 'https://safe-app.com';
AI can generate a validator that looks reasonable. Your review still has to verify whether it enforces the real security boundary.
See you next Tuesday, Bartosz
Want the next security email in your inbox?
Why this matters now
Code gets produced faster. Judgment doesn't.
AI can generate features and security fixes. You still need to recognize broken trust boundaries, missing authorization, unsafe input handling, exposed secrets, and fixes that protect the wrong thing.
Dev Academy trains the security judgment behind the code — one focused email at a time.
Dev Academy by Bartosz Pietrucha
Practical teaching for people who ship real software.
Building production software since 2013. Teaching developers since 2017.
I created Dev Academy to make difficult engineering decisions clear, practical, and useful at work. Every email starts with a situation a developer can recognize and ends with something concrete to apply.
Your first security email arrives immediately
One practical security lesson every week.
One vulnerability. One code example. One practical fix. Free for JavaScript and TypeScript developers.