03 Jun 2026 · 8 min read

A big part of what I do for PentesterLab is reading CVEs. I spend a lot of time going through them: it's how I find interesting content, spot trends, and decide what to build next. The best ones end up as hacking labs or code review labs.

Every so often, something else happens. I'm reading the patch that's supposed to fix a vulnerability, and I find a way around it. The fix doesn't actually fix the issue.

When that happens, I report the bypass before I publish anything. The reason is simple: I don't want learners studying a broken patch and walking away thinking that's how you're supposed to fix the problem. A vulnerable patch dressed up as a solution is worse than no example at all.

It's thankless work, to be honest. Very little recognition: rarely a thank-you, a note, or a CVE of your own. But these are some of the best learning opportunities I come across. Watching how people fail while they're actively trying to fix something is fascinating. It tells you exactly where the hard parts are and what's difficult to get right.

The issues I keep running into (for the last 12 months) cluster around two classics: SSRF fixes and directory traversal. People get these wrong again and again, which also makes them, right now, some of the most rewarding things a code reviewer or web hacker can look for.

Directory traversal

For directory traversal, the most common mistake is fixing the traversal but not the path manipulation. People block ../ and call it done, forgetting that you don't always need to traverse anywhere to reach data you shouldn't.

Say I'm logged in as admin123 and I can legitimately access /var/files/admin123/. If the check is a naive prefix match, I might also reach /var/files/admin/, because /var/files/admin123/ starts with /var/files/admin. No ../ required. The path was never manipulated in the way the filter expected; it just matched.

This is also why APIs like Go's new os.Root matter so much for the future of secure applications. Instead of asking developers to reason about every string trick, they constrain operations to a directory at the OS level.

Why SSRF keeps coming back

For SSRF, the recurring mistakes are more specific. The big one is redirects: people forget to stop the HTTP client from following them, or they validate the first URL but never apply the same filtering to the redirect target. A request to an allowed host comes back with a 302 pointing at http://169.254.169.254/, and the client follows it straight to the internal service.

The other classic is DNS rebinding. The hostname resolves to a public IP when you validate it, and to a private IP a moment later when the request is actually made. Both are rarely reported as the next step after a bypass, and both are hard to fix.

What makes SSRF special is that it's the one major class where frameworks still don't hand you a safe default. SQL injection, XSS, CSRF, password storage, crypto: developers increasingly get secure defaults for all of them. For SSRF they're mostly on their own, and every mitigation they add (denylists, allowlists, redirect checks) tends to fix one case while opening another. That's why so many SSRF CVEs aren't carelessness. They're reasonable-looking protections that fail on a single edge case.

A fix worth stealing

Sometimes I don't find a bypass. I find a fix I'd never have thought of, and that's valuable in its own way. It changes how I think about the whole class of problem.

A good recent example is CVE-2026-25738 in Indico. The fix monkey-patches socket.getaddrinfo() to add a per-request DNS cache stored in Flask's g object, so the hostname resolves to the same address during validation and during the actual request. That closes the DNS rebinding window directly. I'd never seen SSRF prevented this way, and I probably wouldn't have come up with it myself. I'm not in love with the complexity of the code, but the idea is gold.

When a bad report makes a bad fix

You can also see, very clearly, how a low-quality report shapes a bad fix.

Take CVE-2025-12203 in Vvveb. It was reported as a null byte injection: the researcher found that /.%00./.%00./.%00./ slipped past the directory filter. But that framing was wrong. The real issue was non-recursive filtering, and the null byte was only one of many characters that exposed it. Because the report focused on the null byte, the developer blocked the null byte. The original payload stopped working; the actual vulnerability did not. A precise description of the root cause would have produced a real fix. The narrow report produced a narrow patch.

CVEs are a gold mine

As I wrote in my book, CVEs are the most underutilised gold mine you'll find. New variants of old vulnerabilities, novel ways to fix them, bypasses, trends across an entire ecosystem: it's all in there, mostly ignored.

Sometimes the most interesting CVE is the one hiding inside someone else's CVE.

Want to build these skills hands-on?

PentesterLab has 700+ real-world labs on web hacking, code review, and vulnerability analysis. Start with a free account.

Photo of Louis Nyffenegger
Louis Nyffenegger
Founder and CEO @PentesterLab