Skip to content

[Bug] GDPR banner reappears after Accept/Decline — consent cookie missing domain attribute #241

@parhumm

Description

@parhumm

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:

  1. User clicks Accept/Decline - submitBannerDecision() fires
  2. JS sets cookie: slimstat_gdpr_consent=accepted; path=/; expires=...; SameSite=Lax - no domain
  3. Server AJAX handler sets cookie via setcookie() with domain => COOKIE_DOMAIN
  4. On next page load, PHP GDPRService::hasConsentDecision() checks dollar-sign COOKIE - cookie not found due to domain scope mismatch
  5. getBannerHtml() renders banner again

5 Whys:

  1. Banner reappears - hasConsentDecision() returns false
  2. hasConsentDecision() fails - cookie not in dollar-sign COOKIE
  3. Cookie not sent - domain scope mismatch between JS (host-only) and PHP (COOKIE_DOMAIN)
  4. 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

  1. Visit any frontend page as anonymous visitor
  2. GDPR banner #slimstat-gdpr-banner appears
  3. Click Accept (or Decline)
  4. Banner dismissed, AJAX request fires successfully (HTTP 200)
  5. Refresh the page
  6. 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions