Skip to content

Fix user IDOR, account takeover, and audit-log stored XSS#56

Merged
ardelato merged 3 commits into
hermesfrom
security/address-issues
Jun 23, 2026
Merged

Fix user IDOR, account takeover, and audit-log stored XSS#56
ardelato merged 3 commits into
hermesfrom
security/address-issues

Conversation

@ardelato

Copy link
Copy Markdown
Collaborator

Description

Closes six security findings in the user-account endpoints and the audit log, disclosed against this fork and already remediated upstream in TheRestartProject#881.

Changes

  • Authorization (UserPolicy): add update and delete abilities ("self or Administrator") as the single canonical ownership rule.
  • IDOR fixes (UserController): authorize soft-delete (F001), skills (F004), language (F006), and notification preferences (F007) through the policy, and migrate the existing edit-info/password/photo checks onto it.
  • Account takeover (F002): rewrite edit() to drop the Host bypass — only an administrator or the user themselves may edit. Group membership is synced only by an administrator for a non-administrator target, so a self-editing user can no longer rewrite their own group memberships (and an absent groups field no longer wipes existing ones).
  • Stored XSS (F005): render audited values through Blade {{ }} auto-escaping instead of a raw echo of json_encode.

Testing

  • PrivilegeEscalationTest: 24/24 passing — cross-user attempts return 403 for delete/edit/tags/language/preferences; a Host cannot edit or reset another user's password; self and admin still succeed; self-promotion to Host via a category-1 skill is preserved; plus regression tests asserting a non-admin cannot self-assign groups and that an edit() POST without a groups field preserves memberships.
  • GroupEditTest: new test asserts an injected <script> in an audited field renders HTML-escaped, not raw.
  • ProfileTest: updated so a Host now gets 403 and an admin reaches the password-mismatch path.
  • Note: a few pre-existing ProfileTest/GroupEditTest cases fail identically on the base branch due to local environment issues (logged-out auth expectation, geocoding) unrelated to this change; expected to pass in CI.

ardelato added 3 commits June 22, 2026 11:25
Authorise every user-mutation endpoint through UserPolicy via
Gate::authorize, fixing IDOR in soft-delete (F001), skills (F004),
language (F006) and notification preferences (F007), and migrating the
existing edit-info/password/photo checks onto the same policy.

Rewrite edit() to drop the Host bypass that allowed account takeover
(F002): only an administrator or the user themselves may edit, and group
membership is synced only by an administrator for a non-administrator
target, so a self-editing user can no longer rewrite their own groups.
Render audited values through Blade's {{ }} auto-escaping instead of a
raw PHP echo of json_encode, so a stored script payload in an audited
field no longer executes in an admin's browser (F005).
Add cross-user 403 and self/admin-success cases for soft-delete, edit,
skills, language and preferences, plus group-membership regression tests
and an audit-log XSS-escaping test. Drop the redundant RefreshDatabase
trait (it nests a second transaction inside TestCase's and breaks the
savepoint on legacy-table writes) and enable exception handling on the
403-asserting cases.

@mlahargou mlahargou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CR 📱 Checks out to me.

@ardelato

Copy link
Copy Markdown
Collaborator Author

QA 👍 confirmed the changes in the test cluster instance.

@ardelato ardelato merged commit 718b8b6 into hermes Jun 23, 2026
@ardelato ardelato deleted the security/address-issues branch June 23, 2026 00:43
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.

2 participants