A WHMCS refugee, two AI assistants, 32 security findings, twelve matching code fixes, and a support ticket that has apparently taken a vow of silence.
I just wanted to leave WHMCS
Really. That was the whole plan.
After years of licensing gymnastics, price increases, and the general joy of running billing software whose business model appears to involve testing how much frustration can be invoiced monthly, I started looking at alternatives.
Blesta was on the list. It is extensible, much of its PHP source is readable, and it offers the sort of developer access that makes a migration tempting. I installed 6.0.3 on an isolated staging server to see whether it could eventually handle billing for my hosting business.
There is a minor catch with billing platforms: they are not just invoice generators. They hold customer details, payment integrations, and often credentials that can provision, modify, suspend, or terminate services on real servers. If something goes wrong, the consequences are considerably more interesting than a broken dashboard widget.
So I decided to audit it before trusting it. An unreasonable demand, apparently.
Two AIs walk into a codebase
I used Claude and Codex to help review Blesta 6.0.3. They searched source paths, followed data flows, questioned validation logic, and suggested things to check. I reviewed the results and reproduced four issues end-to-end on a throwaway staging installation with test data.
The report was intentionally explicit about its limits. Four findings were marked CONFIRMED-LIVE. The others were marked CODE: source-level findings needing the vendor’s review, especially where encoded core files prevented a complete trace. It contained 32 finding groups across severity categories, not 32 independently demonstrated exploits. Some were hardening observations. That distinction matters.
This was not “AI says scary thing, publish scary thing.” This was AI-assisted source review, human validation, and a private report with enough detail for the engineers responsible for the product to investigate.
On October 9, 2026, I sent the full report privately through Blesta’s own ticket system and by email. No forum thread. No Twitter victory lap. No exploit pastebin. No public proof-of-concept. The report expressly asked them to keep it confidential while fixes were prepared.
I thought that was how responsible disclosure was supposed to work.
A remarkably busy eleven days
Here is the timeline:
| Date | Event |
|---|---|
| October 9 | Private 6.0.3 report submitted, including four staging reproductions. |
| October 14 | Blesta publishes Not Everything Should Be Vibe Coded. |
| October 20 | Blesta releases 6.0.4 with eight entries labelled Undisclosed vulnerability and ten labelled Undisclosed security hardening. Its security advisory rates the release’s overall impact High. |
| October 27 | As I write this, I have received no human reply to my report through either channel. |
Eighteen security-labelled changes in one patch are certainly noticeable. But numbers alone prove nothing. Thirty-two items in a report and eighteen security entries in a changelog do not magically establish that one caused the other.
Fortunately, software comes with a more useful instrument than numerology: diff.
The ZIP files have opinions
I compared the official 6.0.3 source with the official cumulative 6.0.4 patch applied to a copy of that release. The archive hashes matched Blesta’s published SHA-256 values. This was a static code comparison, not an exploit test against production systems.
At least twelve distinct findings in my October 9 report have direct, specific corresponding changes in the October 20 code. Not merely changes in the same general area. Changes to the precise validation, ownership, escaping, or trust decision described in the report.
Among them:
| Area reported | What changed in 6.0.4 |
|---|---|
| Payment notification validation | A gateway no longer overrides a failed validation simply because the incoming status says the payment completed. |
| Applying payments to invoices | A new check verifies that an invoice belongs to the transaction’s client. |
| Third-party payment responses | Multiple integrations now verify signatures or retrieve authoritative payment details instead of trusting callback fields. |
| Affiliate withdrawals | Payout creation now forces a server-controlled pending status. |
| Avatar handling | Arbitrary paths are rejected and stored avatar paths are restricted. |
| Payment confirmation and admin views | Untrusted values are now escaped before rendering. |
| Registrar DNS views | Previously raw record fields are now escaped. |
Two examples are almost too neat. The report recommends verifying that each invoice belongs to the transaction’s client; the patch introduces a method called validateClientAmounts(). The report asks for output escaping on the payment confirmation view; the patch adds Html->safe() at that output.
Maybe the team had already found every one of these problems. Maybe other researchers reported overlapping issues. A source diff cannot identify who first noticed a bug or prove what prompted a developer to fix it. I am not claiming exclusive credit or access to their internal ticket history.
I am claiming something narrower, demonstrable, and rather awkward: an AI-assisted report submitted on October 9 described real code problems that were addressed in closely matching ways by October 20.
And not all concerns appear resolved. Some code relevant to other findings remains unchanged in 6.0.4. I am deliberately withholding the details of potentially outstanding issues, including the reproduction steps. This article is about the disclosure process, not a free weekend project for attackers.
About that vibe-coding essay
Five days after my report, Blesta published Not Everything Should Be Vibe Coded.
Let me be fair: I have no evidence that the article was aimed at me. It also makes a distinction I strongly agree with. Blindly accepting AI-generated code without understanding it is dangerous. Using AI in a disciplined process with review and tests is something else.
Excellent. That is precisely why I did not deploy the billing platform first and discover its security properties later. I reviewed the source, checked assumptions on my own staging system, labelled what was actually reproduced, and sent the evidence to the people who could fix it.
The essay even suggests evaluating a billing vendor by its security-response process: what happens when vulnerabilities are reported, and whether the vendor communicates about them.
That is a particularly good question.
The same company published a security patch eleven days after my report. Its release announcement graciously thanks people who helped through the forums and Discord. My report went through private channels, as security reports generally should. The patch shipped. The private ticket remained unanswered.
Perhaps the ticket is still waiting for human verification. The AI certainly had to pass it.
Known already? Fine. Acknowledge it anyway.
I have seen the suggestion in community discussion that vendors receive plenty of AI-generated vulnerability reports and already know about many reported issues. I can believe it. AI can produce noisy reports. Static analysis can be wrong. Even a correct finding can duplicate work already in progress.
That is why I separated confirmed reproductions from code-level suspicions. It is also why I sent the report privately rather than converting uncertainty into a headline.
If every issue was already known, a perfectly good reply would have been: Received, thank you. Some findings overlap with work in progress; we’ll review the rest.
If half were wrong, tell me which half. If the confirmed cases were already fixed internally, wonderful. If there was an existing embargo, I would have respected it. That is what the confidentiality note was for.
I was not asking for a bounty, a medal, or a marketing department to put my name in lights. A two-line acknowledgement would have been enough.
Blesta’s own Responsible Disclosure policy asks researchers to report vulnerabilities discreetly and says the company will work with them toward a resolution. I did the discreet part. The work with part has been a little difficult to observe from my side of the ticket.
Responsible disclosure is a two-party protocol. The researcher reports responsibly. The vendor responds responsibly. If one side sends and the other side stays silent, that is less a protocol than /dev/null with a ticket number.
Credit where it is due. Literally.
The speed of the 6.0.4 security release deserves credit. Shipping multiple fixes in eleven days is good engineering responsiveness. Customers should upgrade. I would much rather see a security patch than a beautifully worded apology with no patch behind it.
But shipping fixes and communicating with a reporter are not mutually exclusive features. You can do both. You can even do them in the same sprint.
AI did not replace security engineering in this story. It helped a prospective customer inspect software he was considering trusting with his business. Human review and staging tests made the report useful. Developers then shipped changes that closely match many of those findings. That is, arguably, a rather good example of humans and AI working together.
So yes: not everything should be vibe coded.
And apparently, not everything that arrives in a security ticket should be vibe ignored, either.
I started October looking for a replacement for WHMCS. I ended up testing both a billing platform and its responsible-disclosure process.
One of them received a patch in eleven days.
The other is still waiting for a reply.
Back to the logs. At least they answer when something happens.