eWPT study materials
eWPT study resources

Public Invoice Bucket, Shared Cookie Domain, and a Verbal Green Light

eWPT · Put your knowledge to work in context.

All case studies

Public Invoice Bucket, Shared Cookie Domain, and a Verbal Green Light

You are the lead tester on a four-week engagement for an online retailer. The signed scope lists *.shop.example.com as in scope, explicitly excludes payments.example.com (run by a PCI-compliant payment processor) and every SaaS vendor, and permits production testing only between 22:00 and 04:00 UTC at no more than 5 requests per second. The client's security manager says verbally that "the admin panel is fine to hammer, we don't lock accounts." On night two you find that assets.shop.example.com is an S3 bucket with public ListBucket enabled; the first page lists 400 object keys including invoices/2024/INV-100341.pdf. You also notice that responses from www.shop.example.com set SESSION with Domain=.example.com, and that payments.example.com accepts the same cookie name. Your main contact is asleep and the testing window closes in 90 minutes.

1. What do you do about the publicly listable bucket and the invoice objects inside it, within this window?

Read the worked answer

Stop after the listing. The ListBucket response is already complete proof of the vulnerability; every additional object request increases the exposure of real customer data and creates copies of PII on your laptop, which almost certainly violates the data-handling clause of the engagement contract.

Minimal evidence to capture: the bucket name and region, the raw response for GET /?list-type=2&max-keys=1 showing KeyCount, the timestamp, and your source IP. For the example key, record only the prefix and a truncated identifier (invoices/2024/INV-10****) - the customer name and full invoice number are not needed to prove the finding.

Escalate now rather than at report time. A live PII exposure is an incident, not a deliverable: use the 24/7 number in the contract, state the bucket name and the one-line fix (enable S3 Block Public Access, remove the bucket policy), and explicitly say you have not downloaded any object. Do not test the fix yourself and do not keep enumerating pages of keys to size the exposure - "400+ objects on the first page" is enough. Log the stop condition and the notification in your engagement notes.

2. The `SESSION` cookie is set with `Domain=.example.com`. How far can you take this, given that `payments.example.com` is out of scope?

Read the worked answer

You may not send a single request to payments.example.com, and you may not attempt to set or overwrite a cookie for that host - that is active testing of an out-of-scope, third-party system. But the cookie attributes emitted by www.shop.example.com are in-scope behaviour, and that is where the finding lives.

The real issue is that a domain-wide cookie with no __Host- prefix can be set or shadowed by any sibling subdomain. Since *.shop.example.com is in scope, the risk becomes concrete only if an in-scope subdomain is XSS-able, serves user content, or is a subdomain-takeover candidate - then an attacker on that sibling can plant a SESSION value and fixate an admin's session. Test exactly that: look for a controllable response under an in-scope host, and if you find one, demonstrate cookie shadowing (duplicate SESSION values) against the in-scope app only. If no controllable subdomain exists, do not manufacture one; document it as a design weakness with the observed attributes and recommend the __Host- prefix plus a narrow Domain or host-only cookie.

3. The security manager verbally authorised hammering the admin login. Do you run a brute-force or lockout test tonight?

Read the worked answer

No. The written scope caps you at 5 requests per second and the verbal comment does not amend a signed document - an examiner, an auditor, or the client's own incident team will treat the written scope as authoritative if the login service degrades at 03:00.

You also do not need brute force to report the issue. Lockout testing at low volume is enough: send 10 sequential failed logins for a single seeded account within 60 seconds, then check for 429, a lockout message, or an unbounded 401 stream. Because 10 requests in a minute is far below 5 rps, this fits the window and produces the finding "no account lockout or rate limiting on /admin/login". The impact statement can note that the credential-stuffing feasibility follows from that observation; you are not required to prove it by running a wordlist.

If the client genuinely wants a lockout/rate-limit stress test, ask for a written scope amendment that names the endpoint, the rate, and the account set, and schedule it outside the shared login path. Record the request and the refusal in your notes either way.