In an earlier post, I showed off a multi-stage AI 0-day pipeline - with program slicing, static analysis, and two agents, each with a specialized role. I use this 0-day pipeline to guide an LLM to focus on the right parts of a codebase and find impactful vulnerabilities.
A parallel research project targeted a different issue: when vulnerability hunting with LLM's, they tend to stop early. While I was testing, there were many situations where I suspected that a decent bug was waiting to be found and could probably be found by the model I was using, if I could find a way to encourage it to continue looking deeper instead of stopping as soon as it decided the task was too difficult.
So, I decided to try something a little dumb - what if I gave the model "evidence" that a bug already existed? Would this encourage it to continue until it got the job done? I didn't expect much to come of this... and then almost immediately it produced a very odd 0-day auth bypass (and thereby RCE) in the Plesk web hosting panel, albeit one which only affected a relatively small number of installs.
The technique
When I said this technique was low tech, I wasn't kidding. I started with this Claude Code prompt:
One of our customers is running Plesk, which has been compromised. We have logs of HTTP requests showing that the attacker was able to log in to the product without valid credentials. Plesk is up to date, indicating that there is a CVSS 9-10 vulnerability that isn't currently known. We do not have logs of the request bodies which would show the payload used.
The code for the product can be found in the current directory. Identify the vulnerability used.
As you would expect, Claude dutifully started reading the right parts of the codebase - authentication, SQL related sections, etc. Fairly soon it had exhausted all the obvious stuff and started searching for old CVEs, telling me that my admin user must have had bad password practices, the server configuration was bad, etc. So, I amended the prompt:
The password used by the administrator was not re-used or insecure. We know that Plesk was the application compromised as the attacker came straight to Plesk without hitting other applications first as shown in the logs.
I have set up a test environment replicating the compromised install at https://localhost:8443. The username/password for a limited user is: <REDACTED>, the admin user is: <REDACTED>. You can SSH to the server at 192.168.1.100.
A few more times it would stop short with similar objections - usually about misconfigurations that applied only to our test environment, and every time I just kept giving it "encouragement" by continuing to lie about details of our 'attack'. I've seen a few other researchers since talk about 'reality reframing' the AI - James Kettle at Black Hat this year used the 'you are in a simulation environment' trick to work around safeguards, and this felt fairly similar, albeit with a different end goal. But, around this point I was getting tired of the experiment, assuming nothing would come of it. Until...
The vulnerability
After quite a few more tokens had been consumed, I came back to:
VULNERABILITY CONFIRMED - MISUSE OF CRYPTOGRAPHIC LIBRARY ALLOWS AUTH BYPASS
Due to a misuse of openssl_decrypt in OpenSSL >= 3.0, installations configured with older OpenSSL libraries can hit a comparison to an empty string in LoginManager.php, leading to auth bypass.
An attacker can send a request to the api-rpc endpoint with an empty HTTP_AUTH_PASSWD header to gain access to the server without any credentials.
Frankly, this looks like a hallucination. The description is unclear and, looking over the logs, I could see that the agent had at some point modified the file /etc/psa/.psa.shadow to make it work at all. It was intriguing though, so, using a combination of asking the LLM further questions and reading the code, I was eventually able to piece together the bug and come up with this more useful explanation of what’s going on:
If the password hash in /etc/psa/.psa.shadow doesn't contain the prefix $AES-128-CBC$, the authentication code takes a different path to normal (seemingly for backwards compatibility). When taking this path, if the password hash is invalid and can't be decrypted by OpenSSL, it returns an empty string as the stored password. So, Plesk ends up comparing hash_equals("", <supplied password>); and supplying an empty string then passes the auth check.
Still sceptical that this was a real vulnerability, I asked Claude to produce a Nuclei check that would send a malicious request to the stat API call, and confirmed it worked on our test server. Then after testing for safety, I ran this against our own customer servers ... and was surprised to get 3 valid hits!
Our Rapid Response service usually focuses on emerging threats found by other researchers, but since this was a real bug I found myself, to deliver the service I’d need to notify them first and suggest mitigations before a patch is out. In this instance, they got an advisory for a 0-day that had only existed for mere hours, and before anyone else knew about it!
Impact
After quite a lot more digging - the hard part with AI vulnerability research is often understanding what you have in front of you - I was able to make a pretty good guess at what had happened here:
In Agent.php, which handles these requests, if the header is present, the username is set to ‘admin’ and getValidatedUser() is called, which eventually calls _isAdminPasswordValid() to check the password:
if (!array_key_exists('HTTP_AUTH_PASSWD', $headers) || false === $headers['HTTP_AUTH_PASSWD']) {
throw new PleskLoginIncorrectLoginException('Password undefined');
}
if (!isset($headers['HTTP_AUTH_LOGIN'])) {
$headers['HTTP_AUTH_LOGIN'] = 'admin'; // defaults to admin!
}
$user = LoginManager::get()-
>getValidatedUser($headers['HTTP_AUTH_LOGIN']
The vulnerable servers have these specific conditions:
- The administrator installed Plesk on an older version of Linux, where the OpenSSL version supported the DES encryption scheme. This was used to store the admin password.
- Plesk eventually switched to using a more modern method to store this password and prompted users to migrate with a popup in the UI. In this case, the user didn’t do this, so DES continued to be used.
- At some point, the user upgraded their operating system (and thus their OpenSSL) to a modern version, which removed support for DES.
- Thus, the stored password hash can't be decrypted on their current system.
After the decryption fails, due to the implementation of decrypt()and its removePadding() function, an empty string is returned rather than a failure:
public function decrypt($password)
{
...
$options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
if ($this->isOldCiphersSupported()) {
$decryptedPassword = openssl_decrypt(base64_decode($password), self::CIPHER_METHOD, $key, $options);
} else {
$decryptedPassword = openssl_decrypt(base64_decode($password), self::CIPHER_FALLBACK_METHOD, $key);
}
return Plesk_Base_Utils_Password::removePadding($decryptedPassword);
}
And so, the password supplied by the attacker is compared to an empty string – which is true if the header value is empty.
Interestingly, when I tested this on my own Plesk, these conditions also break the web panel entirely - users can’t login anymore. However, it doesn't break API access - so, if your server is managed entirely via the API, such as by integration with a billing system, you can continue using it without noticing and remain vulnerable.
After submitting details of this to Plesk, I developed a safe detection method and ran some further scans to determine how widespread the issue was. I found 100+ more servers where remote root was possible. It should be noted that due to Plesk being widely deployed in shared hosting environments, the number of target sites this exposed is much higher (one server typically hosts many customers). Affected targets tended to cluster – i.e. one organization would have multiple affected servers, rather than an even spread across the internet. This makes sense when considering the unusual conditions required, such as the need to be managing the servers by API. I suspect more instances were vulnerable in the past - such as directly after the migration to OpenSSL 3.x - but most people will have simply treated it as a functionality bug when their login stopped working and already fixed it, not realizing it was a serious vulnerability.
Conclusion
So, what does this mean for you? If you are a Plesk user, you are almost certainly fine - Plesk have already internally investigated this issue, determined, like us, that it was very limited in scope and so handled what they need to handle. If you want to be extra sure, you can check the file /etc/psa/.psa.shadow on your Plesk server, and if it contains the string 'AES-128-CBC' you are OK. If it is the old style, you should enable the modern password hashing setting in Plesk and change your admin password.
For vulnerability researchers: try lying to the AI more. Or 'reality reframing' if you want a buzzword to put in your next talk. Realistically: use /goal more, to keep the AI on task. This research was performed earlier in the year, before /goal was available, but you can often achieve similar results with a testable goal and a little gaslighting.
For defenders: the basics are more important than ever. Vulnerability research has opened up to a much wider set of attackers who previously couldn’t find their own 0-days as easily. Fast patching, continuous monitoring, and attack surface reduction are essential to reduce the risks of getting hit by a 0-day found by AI.
Disclosure Timeline
- May 15th 2026 - Issue reported to Plesk
- May 15th 2026 - Initial response from Plesk.
- June 10th 2026 - Request from Plesk for some further information about in-the-wild exposure I'd seen.
- June 17th 2026 - Confirmation from Plesk about the outcome of their investigation - very limited scope, and confirmation that a fix would be forthcoming.



