SKILL.md
Core Concepts
HttpOnly vs Client-Side Storage
Cookies marked HttpOnly cannot be accessed or modified by client-side JavaScript (cookieStore or document.cookie). However, the browser automatically attaches active HttpOnly cookies to outgoing HTTP request headers (Cookie).
- To inspect current
HttpOnlyvalues: Look at theCookierequest header of any outgoing HTTP request viagetnetworkrequest. - To inspect how cookies were created or configured: Look at the
Set-Cookieresponse header of login/auth responses. - To inspect non-
HttpOnlycookies: Useevaluate_scriptwith the moderncookieStoreAPI (async () => await cookieStore.getAll()).
Session Strategy: Live Tab vs Isolated Context
Choose the right session environment to avoid state contamination (e.g., residual analytics or auth tokens):
| Strategy | When to Use | Setup / Teardown |
|---|---|---|
| Live Tab (Active Page) | Diagnosing an active user session, live 401/403 error, or current state. | Operates directly on the currently selected page. |
Clean-Slate (isolatedContext) |
Testing cookie consent banners, first-time visits, or zero-cookie guarantees. | Call newpage with a unique isolatedContext (e.g. "consent-audit-1"). When finished, call closepage. |
Client-Side Capabilities & Limitations
| Action | Client JavaScript (cookieStore / document.cookie) |
DevTools Network & Context Tools |
|---|---|---|
| Read Non-HttpOnly | ✅ async () => await cookieStore.getAll() |
✅ getnetworkrequest (Request Cookie) |
| Read HttpOnly | ❌ Blocked by browser security | ✅ getnetworkrequest (Request Cookie) |
Inspect Attributes (Domain, Path, SameSite, Expires) |
✅ async () => await cookieStore.getAll() |
✅ getnetworkrequest (Response Set-Cookie) |
| Modify / Delete Non-HttpOnly | ✅ async () => await cookieStore.set(...) |
N/A |
| Modify / Delete HttpOnly | ❌ Silent failure in JavaScript | ✅ Use new_page(isolatedContext: ...) for clean state |
[!WARNING]
Attempting to clear anHttpOnlycookie via JavaScript (cookieStore.deleteordocument.cookie = "...; max-age=0") will silently fail. To test in an unauthenticated or fresh state, always spawn a new isolated context usingnew_pagewithisolatedContext.
Workflow Patterns
1. Diagnosing Authentication Failures & Redirects (401 / 403)
When an authenticated page request fails, returns 401/403, or redirects to login:
- List Recent Requests: Call
listnetworkrequestswithincludePreservedRequests: true. - Find the Target Request: Locate the failing request (401/403) or redirect (302/307).
- Inspect Outgoing
CookieHeader: Callgetnetworkrequestwith thereqid.
- Verify if the Cookie header was attached and whether required tokens (e.g. SESSIONID, authtoken) were sent.
- Trigger Active Inspection (If no recent request exists):
- If the cookie was set in a previous session and no network call is listed, trigger a request: - Use navigatepage with reload: true, OR - Call evaluatescript with () => fetch(window.location.href) - Then call getnetworkrequest on the new request to inspect the active Cookie header.
- Trace the Setting Request: If the cookie is missing or rejected:
- Check earlier login/handshake responses for Set-Cookie directives: - Path mismatch: e.g., Path=/api when the request is to /. - Domain mismatch: e.g., Domain=api.example.com preventing cookies on sub.example.com. - Secure flag on HTTP: Secure cookies are never sent over unencrypted http://. - SameSite blocking: SameSite=Strict cookies are omitted on cross-site navigations. - Expiration: Check if Expires or Max-Age elapsed.
2. Cookie Banner & Consent Conformance Testing
To verify that no non-essential or tracking cookies are set before consent or when declining:
- Start Clean: Open a fresh isolated context with a dedicated name:
``json {"url": "<PAGE_URL>", "isolatedContext": "consent-test-1"} ``
- Record Baseline Cookies: Before interacting with the banner, run
evaluate_scriptwithasync () => await cookieStore.getAll(). - Inspect Premature Network Requests & Issues:
- Call listnetworkrequests to ensure no third-party tracking beacons fired before consent. - Call listconsolemessages with types: ["issue"] to check for tracking warnings.
- Interact with Consent Banner:
- Capture snapshot with take_snapshot to locate the "Decline" or "Reject All" button uid. - Click the button with click.
- Verify Cookie Difference:
- Run evaluate_script with async () => await cookieStore.getAll() after clicking to assert that only strictly necessary or consent-state cookies exist.
- Test Consent Revocation (Lifecycle Audit):
- When auditing consent withdrawal or preference changes: - Locate and click the "Cookie Settings", "Manage Preferences", or footer privacy trigger (takesnapshot $\rightarrow$ click). - Deselect non-essential categories or click "Revoke All" / "Save Preferences". - Re-query cookieStore.getAll() to verify previously accepted non-essential cookies were cleared or expired. - Call listnetwork_requests on subsequent actions to ensure tracking beacons are no longer fired.
- Teardown Context: Call
close_pagewhen the audit is complete to prevent leftover cookies from affecting subsequent tasks.
3. Auditing Cookie Security, SameSite & CHIPS (Partitioned Cookies)
- Fast-Track: Native DevTools Issues (Recommended):
- Call listconsolemessages with: ``json { "types": ["issue"], "includePreservedMessages": true } ` - Check for CookieIssue entries, such as: - SameSiteNoneInsecure: SameSite=None without Secure. - ThirdPartyCookiePhaseout: Third-party cookie blocked or restricted. - SchemefulSameSite: Cross-scheme cookie issues. - PartitionedCookies`: Invalid CHIPS partitioning attributes.
- Deep Audit: Lighthouse Third-Party Cookies:
- Run lighthouse_audit with mode: "navigation" and outputDirPath: "/tmp/lh-report". - Extract the specific cookie audit without loading the full report into context: ``bash node -e "const r=require('/tmp/lh-report/report.json'); const a=r.audits['third-party-cookies']; console.log(JSON.stringify({score: a?.score, displayValue: a?.displayValue, items: a?.details?.items}))" ``
4. Client-Side Cookie Inspection & Manipulation
For client-accessible, non-HttpOnly cookies (e.g., UI preferences, non-sensitive feature flags):
- Read Cookies & Attributes:
- Use the modern asynchronous Cookie Store API: ``js async () => await cookieStore.getAll(); ` - Fallback for insecure HTTP origins: () => document.cookie`.
- Set / Modify Cookie:
- Set client cookie via cookieStore: ``js async () => await cookieStore.set({ name: 'theme', value: 'dark', expires: Date.now() + 86400000, sameSite: 'lax', }); ``
- Delete Cookie:
- Clear client cookie: ``js async () => await cookieStore.delete('theme'); ``
Troubleshooting
cookieStoreis undefined:cookieStorerequires a Secure Context (https://,localhost, or127.0.0.1). On non-secure HTTP origins, use() => document.cookieor test over HTTPS.evaluate_scriptreturns empty / unresolved Promise:cookieStoremethods are asynchronous. Always wrap calls withasync () => await cookieStore.getAll().- Cookie not visible in JavaScript: The cookie is marked
HttpOnly. Trigger a network request and callgetnetworkrequestto view it in theCookierequest header. - JavaScript deletion did not remove cookie: The cookie is
HttpOnlyor requires matchingPathandDomainparameters. Use a freshisolatedContextwithnew_pagefor a clean slate. - Cookie set in response but not sent in requests:
- Verify if page is http:// while cookie specifies Secure. - Check if Domain restricts subdomains. - Check listconsolemessages(types: ["issue"]) for browser rejection reasons.
- Residual cookies contaminating audits: Always use
newpagewith a uniqueisolatedContextwhen running compliance tests, and callclosepagewhen done.