-
Notifications
You must be signed in to change notification settings - Fork 15
Description
Validation Result: Confirmed Bug
Verdict: VALID_BUG | Confidence: HIGH | Severity: HIGH
Summary
The GDPR consent banner reappears on every page load after Accept or Decline because the JavaScript-set consent cookie lacks the domain attribute, causing a mismatch with the server-side cookie that uses WordPress COOKIE_DOMAIN constant.
Root Cause
Fault Location: wp-slimstat.js:2146 + wp-slimstat.php:1193-1195
Mechanism: Cookie domain mismatch between client-side and server-side cookie configuration
Causal Chain:
- User clicks Accept/Decline - submitBannerDecision() fires
- JS sets cookie: slimstat_gdpr_consent=accepted; path=/; expires=...; SameSite=Lax - no domain
- Server AJAX handler sets cookie via setcookie() with domain => COOKIE_DOMAIN
- On next page load, PHP GDPRService::hasConsentDecision() checks dollar-sign COOKIE - cookie not found due to domain scope mismatch
- getBannerHtml() renders banner again
5 Whys:
- Banner reappears - hasConsentDecision() returns false
- hasConsentDecision() fails - cookie not in dollar-sign COOKIE
- Cookie not sent - domain scope mismatch between JS (host-only) and PHP (COOKIE_DOMAIN)
- Root cause: gdpr_cookie_domain is never passed in SlimStatParams - PHP passes gdpr_cookie_name and gdpr_cookie_path but omits the domain
Reproduction Steps
Preconditions: WordPress 5.6+ with wp-slimstat v5.4.4, GDPR mode on, Slimstat banner enabled, HTTPS
- Visit any frontend page as anonymous visitor
- GDPR banner #slimstat-gdpr-banner appears
- Click Accept (or Decline)
- Banner dismissed, AJAX request fires successfully (HTTP 200)
- Refresh the page
- Bug: Banner reappears despite prior consent decision
Expected: Banner should not reappear after user makes a consent choice
Actual: Banner reappears on every page load
Code References
| File | Lines | Description |
|---|---|---|
| wp-slimstat.js | 2142-2150 | JS cookie set WITHOUT domain attribute |
| src/Services/GDPRService.php | 104-111 | PHP cookie set WITH COOKIE_DOMAIN |
| wp-slimstat.php | 1193-1195 | SlimStatParams passes name+path but NOT domain |
| src/Services/GDPRService.php | 74-76 | hasConsentDecision() checks cookie |
| src/Services/GDPRService.php | 176-181 | getBannerHtml() renders if no consent decision |
Security Note
If implementing a fix based on this analysis:
- Verify the fix does not introduce new vulnerabilities
- Run security linting (SAST) on changed code
- Check for OWASP Top 10 in any new code paths
Validated via qa-issue-validate skill (jaan.to plugin)