Summary
During a recent engagement on a food industry B2B platform, I discovered a vulnerability chain that allowed me to dump the entire database of users registered for a corporate event. By chaining a sequential ID enumeration vulnerability with a secondary IDOR on the "Edit Profile" endpoint - and optimizing the attack by identifying a weakness in the ID generation logic - I was able to access the Personally Identifiable Information (PII) of all event attendees.
The Target
The target was a web application allowing store owners and food companies to register for an upcoming trade event. The registration form collected sensitive PII, including:
- Full Name
- Email Address
- Mobile Number
- Job Title
- Company/Store Name
- Postal Code & Address
The Vulnerability Chain
1. Reconnaissance & Entropy Analysis
After registering for the event, I received a confirmation email containing two links:
- Download Badge: A URL to download a PDF badge containing a QR code, Name, and Job Title.
- Edit Information: A URL to update registration details.
I analyzed the Badge URL structure: https://event.target.com/badge/download?id=XX110993
- Prefix: Two uppercase letters (e.g.,
TE,TG). - Sequence: A 6-digit sequential number.
Since I was the most recent registrant with ID 110993 (and IDs started at 110000), I knew there were exactly 993 registered users in the event. The sequential number was trivial to guess, leaving only the 2-letter prefix.
I assumed the 2-letter prefix was fully random ( 26 * 26 = 676 combinations).
2. The Hurdle: Cloudflare WAF & JS Obfuscation
I attempted to use a standard Python script to fuzz the optimized list. However, the application was protected by Cloudflare. Any request from a standard HTTP client returned a generic HTML page asking the client to "Enable JavaScript."
Because my script couldn't execute JS, it couldn't retrieve the actual page source to determine if a guessed Badge ID was valid (HTTP 200) or invalid (HTTP 404).
3. The Bypass: Selenium + CDP + Auto-Solving CAPTCHA
To bypass this, I utilized Selenium with webdriver_manager to spawn a real browser instance, which naturally executes JavaScript and satisfies Cloudflare's check.
However, a standard Selenium .page_source call still occasionally returned the "Enable JavaScript" loading state rather than the rendered content. To fix this, I utilized the Chrome DevTools Protocol (CDP). By commanding the browser to retrieve the DOM after execution, I could bypass the obfuscation and validate which IDs were real.
The CAPTCHA Bypass: During the fuzzing process, Cloudflare occasionally flagged the traffic and presented a CAPTCHA challenge. I modified the script to detect this page and simply sleep for 4 seconds.
Because I was using a full browser environment (Selenium) rather than a simple HTTP client, the Cloudflare challenge (likely a "Managed Challenge" or "Turnstile") was able to verify the browser environment during this 4-second pause. It automatically "solved" itself without human interaction, redirecting me back to the content, allowing the script to resume enumeration seamlessly.
The Optimization:
after manually checking about 50 enumerated badges, I noticed a flaw in the randomness. While the first letter was random (A-Z), the second letter only cycled through a specific pool of 8 repeating characters.
This observation allowed me to optimize my script, reducing the search space from 676 to just 208 requests per ID ( 26 * 8 ), significantly speeding up the enumeration process by 70%.
- Result: Using the optimized 208-request loop, I successfully enumerated the valid badge IDs for all users.
4. Escalation: From Medium to High Severity
While downloading badges (Badge QR Code + Name + Job Title) is a valid finding, it is often considered Medium severity. I wanted to demonstrate critical impact.
I returned to the "Edit Information" link found in the email. It used the same ID structure but required a 4-digit PIN for access:
https://event.target.com/user/edit?id=TE110993&pin=XXXX
Since I had already harvested the valid IDs (e.g., TE110993) from the first step, the only barrier left was the 4-digit PIN (10,000 combinations).
I updated my Selenium script to:
- Feed in the valid IDs found in Step 3.
- Brute-force the PIN (0000–9999) for each ID.
- Use the CDP method to bypass the Cloudflare/Captcha checks.
The Impact
The script successfully brute-forced the PINs. Upon a successful guess, the application loaded the "Edit Profile" page, exposing the Full User Database:
- Full Name, Email, Mobile Number
- Home/Business Address, Postal Code
- Company Details
This effectively bypassed the authentication mechanism, turning a simple ID enumeration into a mass PII data breach.

Lessons Learned
- Escalate via Chaining: Instead of reporting the initial low-hanging fruit (Badge download), I dug deeper for the PII endpoint (Edit Profile). This chained exploit turned a Medium severity bug into a High/Critical severity.
- Work Smarter, Not Harder: Manually analyzing the first 50 results revealed a pattern in the "random" IDs, reducing the brute-force search space by 70% (208 requests vs 676).
- Client-Side / Server-Side Security: Cloudflare's JS and CAPTCHA checks verify browsers, not authorization. By using Selenium and a simple sleep timer, the "security" validated my bot as a legitimate user.
- Predictability is Fatal: Hiding sequential IDs behind a weak 2-letter prefix is "security by obscurity." Once the prefix pattern was broken, the entire database was exposed.