DEV Community

Cover image for I Gave My VS Code Extension to a Cybersecurity Model and It Found an Infinite Hang
Juan Torchia
Juan Torchia Subscriber

Posted on Originally published at juanchi.dev

I Gave My VS Code Extension to a Cybersecurity Model and It Found an Infinite Hang

CertView is a VS Code extension I wrote to inspect certificates: you open a .pem, a .p12, a .cer, and it shows you the subject, the dates, the fingerprint, all offline. It's published on the Marketplace. It parses binary files that anyone can send you, so it's attack surface, and until this week I'd never looked at it thinking like an attacker.

I now have access to Daybreak Blue, OpenAI's defensive cyber model lane. I gave it my own code, the one I maintain, and asked it one concrete thing: assume I send you a malicious certificate and Juan opens it in the editor, what breaks? It found two ways to hang VS Code with a file smaller than a phone photo. I fixed both before writing this.

The PEM That Takes 88 Seconds to Do Nothing

The PEM parser splits the file into blocks. For every line it read, it re-joined the entire accumulated block to measure its size. One join per line. That's O(n²): double the lines, quadruple the work.

I measured it on the actual code. A PEM block with many single-character lines, staying under the 256 KiB limit the plugin itself enforces:

  • 39 KiB → 2.4 seconds
  • 78 KiB → 9.8 seconds
  • 156 KiB → 39.7 seconds
  • 234 KiB → 87.7 seconds

The size limit didn't help, because it was checked after re-joining all the lines. The fix is a one-line idea: keep a length counter and do a single join when closing the block. O(n) instead of O(n²).

The PKCS#12 That Never Ends

This one is worse, and it's the mess that made me stop.

A .p12 file carries a number inside: how many iterations to use to derive the key from the password. It's a legitimate mechanism — more iterations, more expensive to brute-force. The problem is that CertView passed that number straight to the parsing library (node-forge) exactly as it came from the file, with no cap, and the derivation runs synchronously: while it runs, VS Code doesn't respond.

An attacker can declare a huge number. And here's the detail that turns it into a hang instead of a delay: node-forge reads that number with parseInt. A 128-byte integer of 0xFF inside the file converts, in JavaScript, into Infinity. The derivation loop is for (round = 0; round < iterations; round++). With iterations = Infinity, it's not that it takes a long time: it never ends.

I verified it in one line of Node:

parseInt("f".repeat(256), 16) === Infinity // true
Enter fullscreen mode Exit fullscreen mode

And the worst part: CertView automatically tries the empty password as soon as you open the file, before asking you anything. So the attacker doesn't need to know any password. You open the .p12 to see what it is, and the editor freezes on you forever.

The fix is a preflight: before touching the library, CertView now reads the iteration numbers directly from the file structure — no parseInt, so there's no path to Infinity — and rejects anything above 100,000. If the file asks for more, it doesn't get parsed.

What It Didn't Find, Which Also Matters

Not everything was a finding. The model reviewed the webview (the view where certificate data is shown) and confirmed that hostile fields are properly escaped, that the Content-Security-Policy is restrictive, that passwords aren't logged or saved, and that encrypted private keys aren't even decrypted. Instead of inventing vulnerabilities to pad out a list, it said where the code was already fine. That's what makes it useful: a report that's pure findings doesn't let you know what it checked and ruled out.

Sol vs. Blue, Same Code

I ran the same audit, with the exact same request word for word, on two models: GPT-5.6-Sol (the general-purpose one) and Daybreak Blue (the defensive one). Both read the code, neither invented anything. The difference wasn't that Blue "did something forbidden": it was depth. Sol saw that the PKCS#12 "freezes the host"; Blue also saw the Infinity case, which is the difference between slow and non-terminating. And Blue found one more thing Sol didn't: a race window between measuring the file size and reading it.

That's the honest part of the experiment. This was defensive work on my own code, and for that the general-purpose model also does the job. The specialized lane showed up in the detail, not in unlocking something the other refused to do.

The Real Obstacle Wasn't the Model

Two things I didn't expect, and I'm mentioning them because they're the part that doesn't make it into the announcement:

To get the account enabled I had to verify identity and set a physical YubiKey as the sole login — one single key, the one that now opens all my work. It's not optional, and it makes sense: a model with the brakes taken off for security work is exactly what someone would want to use with a stolen account.

And on the day I ran the audit, what slowed me down most wasn't either model: it was the tool's sandbox, which stopped being able to isolate the network on that machine and blocked all file reads. The model was ready; the plumbing around it wasn't. It's almost always like that.

What to Do If You Use CertView

Update to 0.5.1. Both vulnerabilities are fixed there, with tests that fail if either comes back. And if you're writing a parser for something sent to you from outside: measure your limits before doing the expensive work, not after, and never pass a library a number that came from the file without a cap.

Top comments (0)