Skip to content

Fix volunteer PII leak on public event pages#879

Open
edwh wants to merge 3 commits into
developfrom
fix/volunteer-pii-isolated
Open

Fix volunteer PII leak on public event pages#879
edwh wants to merge 3 commits into
developfrom
fix/volunteer-pii-isolated

Conversation

@edwh

@edwh edwh commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Party::expandVolunteers() was serialising the full User Eloquent model into event page HTML, exposing api_token, calendar_hash, recovery, latitude, and longitude to anonymous visitors
  • Rewrote expandVolunteers() to emit a whitelist-only $safeUser array and call unsetRelation('volunteer') to prevent Eloquent's relationsToArray() clobbering it during json_encode
  • Extended User::\$hidden to cover all credential and PII fields
  • Fixed inverted \$showEmails in EventController::listVolunteers (was negated — showed emails to non-hosts)
  • Added latitude/longitude to makeHidden() belt-and-suspenders guards in ApiController and UserController (Zapier endpoint)
  • Added credential/PII fields to User::\$auditExclude so they are never written to the audit log

Test plan

  • VolunteerPiiTest — page HTML does not leak credentials, User::\$hidden covers all sensitive fields, expandVolunteers emits safe shape via json_encode
  • UserAuditExcludeTest — credential fields absent from audit old_values/new_values
  • All CircleCI PHP and Playwright suites pass

🤖 Generated with Claude Code

edwh and others added 3 commits June 19, 2026 08:20
Party::expandVolunteers() was serialising the full User Eloquent model
into the page HTML (via json_encode in the Blade template). Because
User::$hidden only contained password and remember_token, any visitor
could read api_token, calendar_hash, latitude, longitude, recovery, and
mediawiki tokens directly from the page source.

Fixes:
1. User::$hidden — add api_token, calendar_hash, recovery,
   recovery_expires, mediawiki, latitude, longitude (defence-in-depth;
   protects every serialisation point).
2. Party::expandVolunteers() — replace the full User model assignment
   with an explicit whitelist of only the fields the frontend needs
   (id, name, email when showEmails, user_skills shape). Never put an
   Eloquent model directly into page-embedded JSON.
3. ApiController::getUserInfo() — extend the belt-and-suspenders
   makeHidden() call to cover all credential fields, not just api_token.

Tests (VolunteerPiiTest.php):
- testEventPageDoesNotLeakVolunteerCredentials: loads the public event
  page HTML and asserts sentinel values are absent while volunteer name
  is still present.
- testUserModelHiddenFieldsExcludeCredentials: asserts every sensitive
  field is in $hidden via User::toArray().
- testExpandVolunteersEmitsSafeShape: asserts expandVolunteers() returns
  a plain array (not an Eloquent model) and contains no sensitive keys.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ints

- Call unsetRelation('volunteer') before assigning the safe array; without
  this, Eloquent's toArray() merges relationsToArray() last, silently
  overwriting the safe array with the full User model in JSON output
- Add null guard for orphaned skill FK rows (deleted skillName record)
- Fix inverted $showEmails in EventController::listVolunteers — was
  negated so non-hosts received emails and hosts did not
- Add latitude/longitude to makeHidden() in ApiController::getUserInfo()
  and UserController::mapUserAndAuditToUserChange() (Zapier endpoint)
- Update testExpandVolunteersEmitsSafeShape to assert via json_encode so
  the Eloquent relation-bypass is actually caught (PHP array-access was
  a false pass — it reads $attributes, not the serialised output)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add api_token, calendar_hash, recovery, recovery_expires, latitude,
longitude, and password to User::$auditExclude so they are never
written to the audits table on any model update.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant