A close friend suggested XenForo as a target and asked to stay out of the story. I already had reports open with Avast and Malwarebytes, both under coordinated disclosure. The antivirus vendors were taking their time. XenForo looked like a project I could finish while waiting for those inboxes to move.
That estimate was slightly optimistic.
I used Codex 5.6 throughout the review. By the end, I had fourteen CVEs and a clear record of where the agents spent their time. The dead-lead folder was larger.
A very basic first setup
I split the XenForo source into areas and opened several Codex sessions. One looked at OAuth, another at payments, another at ACP permissions, and so on. Each session had to return a candidate plus a request I could run against a local XenForo 2.3.12 installation.
The first real result came from the OAuth token endpoint. XenForo rejected an incorrect PKCE verifier, as expected. It accepted an empty verifier, skipped the comparison, and issued working access and refresh tokens. I checked the access token against /api/me before keeping the report.
CVE-2026-73309 was a small bug. An attacker needed a valid authorization code. The tokens worked. I kept going.
Codex finds plenty of bugs if you let it define “bug”
The raw output was mostly noise. One report traced back to a server-generated value. Another quietly assumed the attacker possessed a private secret. Several ended with 200 OK and no state change. A few sessions rediscovered the ancient technique of logging in as an administrator and doing administrator things.
So every lead had to answer four boring questions:
- Which exact build did I test?
- What account, permission, or configuration did the request need?
- Which request fields did the attacker control?
- What changed on the server afterward?
The last question killed a lot of findings. For OAuth, I used the token. For payments, I checked the upgrade expiry and transaction log. For the archive importer, I requested the file from the web root. For the BBCode parser, I watched the Apache workers and the Windows exit status.
The agents became more useful after I handed rejected reports back with a concrete reason. Each revision had to include a reachable route and a visible server-side result.
Then the results got stranger
The PayPal REST handler accepted an unknown algorithm name. Its verifier logged that cryptographic verification had been skipped, returned success, and processed a fabricated completion event. The recurring upgrade gained 30 days from that request (CVE-2026-73314).
The Windows style importer validated ../ and left backslash traversal untouched. I uploaded an archive as a delegated style administrator; a PHP marker escaped the extraction directory, landed in the public web root, and executed (CVE-2026-74239).
The guest BBCode-to-HTML route accepted 5,000 nested quote tags. On my Windows test host, PHP workers died with 0xC00000FD. Apache replaced each worker. Concurrent requests could empty the pool during that replacement cycle (CVE-2026-73321).
These tests also exposed the weakest part of my setup: I was asking agents to read too much code before making them run anything. By then a flimsy idea could collect pages of explanation and start looking respectable. Reproduction needed to happen earlier.
What survived testing
The final set covered OAuth, PayPal, ACP authorization, XSS, information disclosure, denial of service, and archive extraction:
- CVE-2026-73309: Empty OAuth2 credentials — record, PoC
- CVE-2026-73310: OAuth redirect URI binding — record, PoC
- CVE-2026-73311: Authorization code replay — record, PoC
- CVE-2026-73312: Refresh token replay — record, PoC
- CVE-2026-73313: Passkey TFA user mismatch — record, PoC
- CVE-2026-73314: PayPal signature check bypass — record, PoC
- CVE-2026-73315: PayPal certificate URL SSRF — record, PoC
- CVE-2026-73316: PayPal webhook replay — record, PoC
- CVE-2026-73317: ACP rebuild authorization — record, PoC
- CVE-2026-73318: Agreement reset permissions — record, PoC
- CVE-2026-73319: JavaScript URI redirect — record, PoC
- CVE-2026-73320: Unfurl result disclosure — record, PoC
- CVE-2026-73321: BBCode stack overflow — record, PoC
- CVE-2026-74239: Windows style archive traversal — record, PoC
Disclosure
VulnCheck was quick to review the reports and helpful throughout the handoff. XenForo fixed all fourteen issues in 2.3.13 and credited me, Marco Paciaroni, in its security announcement. The fixes shipped on September 7; the CVE records followed on September 8.
The public advisories and reproducible cases are linked from each write-up above. VulnCheck’s process is documented in its disclosure policy.
The Avast and Malwarebytes work is still under coordinated disclosure. I will write about those after the vendors finish moving at vendor speed.
Next
My first method was clumsy: source splits were too large, duplicate work was common, and I waited too long before reproducing candidates. Later runs use smaller assignments, earlier tests, and a second agent whose job is to kill the report before I spend time polishing it.
Part 2 will cover those changes and the other workflows I tried. Some improved the hit rate. Others produced immaculate fiction.
A close friend suggested XenForo as a target and asked to stay out of the story. I already had reports open with Avast and Malwarebytes, both under coordinated disclosure. The antivirus vendors were taking their time. XenForo looked like a project I could finish while waiting for those inboxes to move.
That estimate was slightly optimistic.
I used Codex 5.6 throughout the review. By the end, I had fourteen CVEs and a clear record of where the agents spent their time. The dead-lead folder was larger.
## A very basic first setup
I split the XenForo source into areas and opened several Codex sessions. One looked at OAuth, another at payments, another at ACP permissions, and so on. Each session had to return a candidate plus a request I could run against a local XenForo 2.3.12 installation.
The first real result came from the OAuth token endpoint. XenForo rejected an incorrect PKCE verifier, as expected. It accepted an empty verifier, skipped the comparison, and issued working access and refresh tokens. I checked the access token against `/api/me` before keeping the report.
[CVE-2026-73309](/posts/cve-2026-73309/) was a small bug. An attacker needed a valid authorization code. The tokens worked. I kept going.
## Codex finds plenty of bugs if you let it define “bug”
The raw output was mostly noise. One report traced back to a server-generated value. Another quietly assumed the attacker possessed a private secret. Several ended with `200 OK` and no state change. A few sessions rediscovered the ancient technique of logging in as an administrator and doing administrator things.
So every lead had to answer four boring questions:
- Which exact build did I test?
- What account, permission, or configuration did the request need?
- Which request fields did the attacker control?
- What changed on the server afterward?
The last question killed a lot of findings. For OAuth, I used the token. For payments, I checked the upgrade expiry and transaction log. For the archive importer, I requested the file from the web root. For the BBCode parser, I watched the Apache workers and the Windows exit status.
The agents became more useful after I handed rejected reports back with a concrete reason. Each revision had to include a reachable route and a visible server-side result.
## Then the results got stranger
The PayPal REST handler accepted an unknown algorithm name. Its verifier logged that cryptographic verification had been skipped, returned success, and processed a fabricated completion event. The recurring upgrade gained 30 days from that request ([CVE-2026-73314](/posts/cve-2026-73314/)).
The Windows style importer validated `../` and left backslash traversal untouched. I uploaded an archive as a delegated style administrator; a PHP marker escaped the extraction directory, landed in the public web root, and executed ([CVE-2026-74239](/posts/cve-2026-74239/)).
The guest BBCode-to-HTML route accepted 5,000 nested quote tags. On my Windows test host, PHP workers died with `0xC00000FD`. Apache replaced each worker. Concurrent requests could empty the pool during that replacement cycle ([CVE-2026-73321](/posts/cve-2026-73321/)).
These tests also exposed the weakest part of my setup: I was asking agents to read too much code before making them run anything. By then a flimsy idea could collect pages of explanation and start looking respectable. Reproduction needed to happen earlier.
## What survived testing
The final set covered OAuth, PayPal, ACP authorization, XSS, information disclosure, denial of service, and archive extraction:
- [CVE-2026-73309: Empty OAuth2 credentials](/posts/cve-2026-73309/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73309), [PoC](https://github.com/BomboBombone/CVE-2026-73309)
- [CVE-2026-73310: OAuth redirect URI binding](/posts/cve-2026-73310/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73310), [PoC](https://github.com/BomboBombone/CVE-2026-73310)
- [CVE-2026-73311: Authorization code replay](/posts/cve-2026-73311/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73311), [PoC](https://github.com/BomboBombone/CVE-2026-73311)
- [CVE-2026-73312: Refresh token replay](/posts/cve-2026-73312/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73312), [PoC](https://github.com/BomboBombone/CVE-2026-73312)
- [CVE-2026-73313: Passkey TFA user mismatch](/posts/cve-2026-73313/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73313), [PoC](https://github.com/BomboBombone/CVE-2026-73313)
- [CVE-2026-73314: PayPal signature check bypass](/posts/cve-2026-73314/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73314), [PoC](https://github.com/BomboBombone/CVE-2026-73314)
- [CVE-2026-73315: PayPal certificate URL SSRF](/posts/cve-2026-73315/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73315), [PoC](https://github.com/BomboBombone/CVE-2026-73315)
- [CVE-2026-73316: PayPal webhook replay](/posts/cve-2026-73316/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73316), [PoC](https://github.com/BomboBombone/CVE-2026-73316)
- [CVE-2026-73317: ACP rebuild authorization](/posts/cve-2026-73317/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73317), [PoC](https://github.com/BomboBombone/CVE-2026-73317)
- [CVE-2026-73318: Agreement reset permissions](/posts/cve-2026-73318/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73318), [PoC](https://github.com/BomboBombone/CVE-2026-73318)
- [CVE-2026-73319: JavaScript URI redirect](/posts/cve-2026-73319/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73319), [PoC](https://github.com/BomboBombone/CVE-2026-73319)
- [CVE-2026-73320: Unfurl result disclosure](/posts/cve-2026-73320/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73320), [PoC](https://github.com/BomboBombone/CVE-2026-73320)
- [CVE-2026-73321: BBCode stack overflow](/posts/cve-2026-73321/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-73321), [PoC](https://github.com/BomboBombone/CVE-2026-73321)
- [CVE-2026-74239: Windows style archive traversal](/posts/cve-2026-74239/) — [record](https://www.cve.org/CVERecord?id=CVE-2026-74239), [PoC](https://github.com/BomboBombone/CVE-2026-74239)
## Disclosure
VulnCheck was quick to review the reports and helpful throughout the handoff. XenForo fixed all fourteen issues in 2.3.13 and credited me, Marco Paciaroni, in its [security announcement](https://xenforo.com/community/threads/security-fixes-released-for-all-xenforo-and-media-gallery-versions-2-2-0-2-3-12.239856/). The fixes shipped on September 7; the CVE records followed on September 8.
The public advisories and reproducible cases are linked from each write-up above. VulnCheck's process is documented in its [disclosure policy](https://www.vulncheck.com/vulnerability-disclosure-policy).
The Avast and Malwarebytes work is still under coordinated disclosure. I will write about those after the vendors finish moving at vendor speed.
## Next
My first method was clumsy: source splits were too large, duplicate work was common, and I waited too long before reproducing candidates. Later runs use smaller assignments, earlier tests, and a second agent whose job is to kill the report before I spend time polishing it.
Part 2 will cover those changes and the other workflows I tried. Some improved the hit rate. Others produced immaculate fiction.