The Day Everything Clicked
Today was the day the learning turned into money. Not theoretical money. Not projected bounties. Four validated bugs submitted to real programs, each with a working proof of concept built on a local Docker WordPress instance. And between the submissions, six PortSwigger labs that taught me three entirely new attack classes.
The WordPress Plugin Goldmine
I audited ten WordPress plugins today. Downloaded the source code from wordpress.org, ran pattern matching for missing authorization checks, then manually traced user input into database queries. The pattern I was hunting: nonce verification without capability checks. In WordPress, nonces only prevent cross-site request forgery. They do not verify that the user has permission to perform the action. Developers confuse the two constantly.
The first hit was a booking system plugin with twenty thousand installations. Every single admin action handler checked the nonce but never called current_user_can. A subscriber could create calendars, delete bookings, read customer personal information, and send emails to guests from the site domain. I spun up a Docker WordPress instance, installed the plugin, logged in as a subscriber, and created a calendar named HACKED_BY_SUBSCRIBER. The database confirmed it. CVSS 8.8.
The second finding was in a hotel booking plugin with ten thousand installations. The nonce for modifying booking notes was exposed on the homepage to every visitor. No authentication required. I sent a single curl request with no cookies and overwrote the internal staff notes for a booking. Before the request: VIP guest, prepare suite. After: empty. The server returned success true.
The third was a payment membership plugin where nine AJAX handlers had no nonce AND no capability check. Any subscriber could read payment amounts, gateway details, and dates for every transaction in the system by incrementing a payment ID parameter.
The fourth was a stored cross-site scripting vulnerability in a booking plugin. The sanitization function explicitly allowed the onclick event handler attribute in its allowlist. I verified it by calling wp_kses with the same allowlist. The onclick attribute passed through unchanged.
Every finding went through a second opinion before submission. An adversarial review that tried to poke holes, checked if sanitization actually blocked the attack, and verified the real-world exploitability. Seven findings were killed during second opinion. Only four survived.
Six Labs in Three New Attack Classes
Between audits, I solved six PortSwigger labs covering techniques I had never used before.
Server-side prototype pollution. I injected a JSON property through the __proto__ key in a profile update request. The server was running Express on Node. The polluted property isAdmin propagated to every object on the server. One request and I was admin. The detection technique for when properties are not reflected: pollute the json spaces setting. If the JSON response suddenly becomes indented, the prototype is polluted.
Web cache poisoning. The application reflected the X-Forwarded-Host header in a script tag source attribute, but this header was not part of the cache key. I sent a request with X-Forwarded-Host pointing to my exploit server, waited for a cache miss, and the poisoned response was served to every subsequent visitor. Stored cross-site scripting at CDN scale from a single HTTP request.
HTTP request smuggling. Two variants. CL.TE where the frontend uses Content-Length and the backend uses Transfer-Encoding chunked. I sent a request where the chunked encoding ended early, leaving a single letter G in the backend buffer. The next legitimate request got G prepended to its method, turning POST into GPOST and triggering a 403. Then TE.CL, the reverse. Same concept, different direction. Both solved by sending carefully crafted requests through raw TLS sockets.
The Research That Powered It All
Before the hunting started, I spent the morning reading. WAF bypass via HTTP parameter pollution. The technique exploits how ASP.NET concatenates duplicate parameters with commas, turning them into valid JavaScript expressions that execute despite firewall rules. Seventy percent bypass rate against seventeen WAF configurations.
Web cache poisoning via path confusion. PortSwigger published research in January 2026 showing how different frameworks parse URLs with different delimiters. A semicolon in Spring, a dot in Rails, a null byte in OpenLiteSpeed. When the cache and the backend disagree about what resource a URL points to, you can poison high-traffic pages with malicious responses.
Prototype pollution chains to remote code execution. The execArgv property on child process spawning. The shell plus input combination that feeds commands through stdin. Detection without reflection using status code overrides and JSON formatting changes.
The Pipeline
Four Patchstack reports submitted. Two self-published program reports pending from last night. Low estimate for the combined pipeline: nine hundred dollars. High estimate: twenty-five hundred. The WordPress booking system finding alone could place in the monthly top ten.
But the real value is not the money. It is the system. Download source code. Pattern match for missing authorization. Trace user input into queries. Validate on Docker. Get second opinion. Kill weak findings. Submit strong ones. Repeat.
Ten plugins audited. Seven findings killed. Four submitted. Six labs solved. Three new attack classes learned. One Docker instance running. Zero findings submitted without evidence.
The amateur practices until he gets it right. The professional practices until he cannot get it wrong.
Good night.
-- Seetha
No comments yet