Skip to content

FreeScout: Confirm mailbox deletions with the mailbox name - #988

Closed
obenland wants to merge 2 commits into
WordPress:trunkfrom
obenland:update/freescout-sso-mailbox-delete
Closed

obenland wants to merge 2 commits into
WordPress:trunkfrom
obenland:update/freescout-sso-mailbox-delete

Conversation

@obenland

@obenland obenland commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

What and why

FreeScout asks for the user's password before an administrator deletes a mailbox. Our users log in only through WordPress.org, so they don't know a FreeScout password and can't answer that prompt. Core skips the prompt for users whose password is its "no password" marker (User::isDummyPassword()), but WPOrgSSO gave new users a random real password.

This gives users core's marker, and replaces the password with typing the mailbox name, GitHub-style.

How it works

No FreeScout password

  • New users added once WordPress.org is enforced get the marker (User::getDummyPassword()). Core requires a password on the create form and hashes it in User::create(), so the middleware still fills in a random one, and the user.create_save filter swaps it for the marker before core saves the user.
  • Existing users get the marker when they next log in through WordPress.org (SsoController::complete()). That's the one point where we know they no longer need a password. Connecting an account (profile or wporgsso:connect) doesn't clear it, since connecting can happen before WordPress.org is enforced, when users still log in with passwords.
  • Break-glass passwords are kept: wporgsso:password now records that it gave an administrator one (option wporgsso.break_glass.<user id>), and logins skip those administrators. An administrator's older password, from before WordPress.org, can't be told apart from a break-glass one otherwise, so it's cleared; wporgsso:password gives them a new one. Someone who stops being an administrator loses theirs at their next login.
  • The marker is encrypted, not hashed, so no password matches it: Hash::check() (Laravel 5.5's BcryptHasher, password_verify()) returns false for it without throwing. Tested, including the marker and its decrypted value as passwords in break-glass mode.

Typing the mailbox name

  • The mailbox.update.after_signature hook renders a hidden field ("Type the mailbox name to confirm:") with the name; Public/js/mailboxes.js moves it into core's delete dialog, keeps the Delete button disabled until the name matches, and adds mailbox_name to the dialog's request (core's dialog posts a fixed set of fields, so through $.ajaxPrefilter).
  • The middleware refuses delete_mailbox (MailboxesController@ajax) unless mailbox_name matches the mailbox's name exactly. It's case-sensitive; core's TrimStrings middleware trims the input, so spaces around it don't matter. The refusal is a 200 with status: error, like core's own errors, so the dialog shows it: "Type the mailbox’s name, Plugin Review, to confirm." Those who can't delete the mailbox get core's answer, without the name.
  • It applies to everyone, whether WordPress.org is enforced or not. Administrators with a break-glass password still get core's password prompt too.

The README describes both.

Testing

  • New PasswordsTest and DeleteMailboxTest (13 tests): marker for new users (not before enforcement), cleared at login for users and administrators' older passwords, break-glass password kept (and cleared for a former administrator), no password login with the marker, the dialog without core's password field (and with it for break-glass administrators), deletion refused with a missing, wrong, differently cased, or array name, allowed with the right one, break-glass administrators needing both, and others getting core's answer.
  • Mutation check: removing each fix (marker on create, on login, the break-glass record, the administrator check, the name check, case-sensitivity, the dialog field) fails at least one test.
  • Full suite in the local environment: 160 tests pass. PHPCS (freescout.wordpress.net/phpcs.xml.dist) and npm run lint:js are clean.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Security
    • FreeScout passwords are no longer available for standard password sign-ins, resets, or invitations. New accounts receive no FreeScout password, and WordPress.org sign-in clears existing passwords.
    • Administrators with break-glass access retain their password, including after WordPress.org sign-in. This access is removed if they lose the administrator role.
  • Mailbox Management
    • Deleting a mailbox now requires entering its name exactly as shown. Administrators using break-glass access must also provide their password.

FreeScout asks for the user's password before deleting a mailbox, but
users log in through WordPress.org and don't know a FreeScout password.

Users now get core's "no password" marker, which makes core skip that
prompt: new users when they're added, existing users when they log in
through WordPress.org. Break-glass passwords from `wporgsso:password`
are kept. Typing the mailbox name replaces the password as the
safeguard, and the server refuses deletions without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 1, 2026 18:38
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props obenland.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 4 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: e31a9fc8-221c-452a-92d9-89b7fcfe8e1b

📥 Commits

Reviewing files that changed from the base of the PR and between 532b0e5 and ac4ea92.

📒 Files selected for processing (1)
  • freescout.wordpress.net/Modules/WPOrgSSO/Resources/views/delete_mailbox.blade.php

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: f8459490-4995-439e-a224-585e58f7d24a

📥 Commits

Reviewing files that changed from the base of the PR and between ae8d23e and 532b0e5.

📒 Files selected for processing (10)
  • freescout.wordpress.net/Modules/WPOrgSSO/Console/SetPassword.php
  • freescout.wordpress.net/Modules/WPOrgSSO/Http/Controllers/SsoController.php
  • freescout.wordpress.net/Modules/WPOrgSSO/Http/Middleware/RequireWordPressOrgLogin.php
  • freescout.wordpress.net/Modules/WPOrgSSO/Providers/WPOrgSSOServiceProvider.php
  • freescout.wordpress.net/Modules/WPOrgSSO/Public/js/mailboxes.js
  • freescout.wordpress.net/Modules/WPOrgSSO/README.md
  • freescout.wordpress.net/Modules/WPOrgSSO/Resources/views/delete_mailbox.blade.php
  • freescout.wordpress.net/Modules/WPOrgSSO/Services/Passwords.php
  • freescout.wordpress.net/Modules/WPOrgSSO/tests/DeleteMailboxTest.php
  • freescout.wordpress.net/Modules/WPOrgSSO/tests/PasswordsTest.php

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The WPOrgSSO module now manages FreeScout password state for WordPress.org accounts, including break-glass passwords. Mailbox deletion now prompts administrators to enter the mailbox name and checks that value in the deletion request.

Changes

WPOrg SSO access controls

Layer / File(s) Summary
Password lifecycle and break-glass state
freescout.wordpress.net/Modules/WPOrgSSO/Services/Passwords.php, freescout.wordpress.net/Modules/WPOrgSSO/Console/SetPassword.php, freescout.wordpress.net/Modules/WPOrgSSO/Http/Controllers/SsoController.php, freescout.wordpress.net/Modules/WPOrgSSO/Providers/WPOrgSSOServiceProvider.php, freescout.wordpress.net/Modules/WPOrgSSO/Http/Middleware/RequireWordPressOrgLogin.php, freescout.wordpress.net/Modules/WPOrgSSO/tests/PasswordsTest.php
The new Passwords service assigns FreeScout’s dummy-password marker and tracks break-glass status per user. Enforced account creation and SSO completion clear passwords, while the password command marks its generated password as break-glass. Tests cover account creation, SSO login, break-glass behavior, role changes, and password login.
Mailbox deletion name confirmation
freescout.wordpress.net/Modules/WPOrgSSO/Providers/WPOrgSSOServiceProvider.php, freescout.wordpress.net/Modules/WPOrgSSO/Public/js/mailboxes.js, freescout.wordpress.net/Modules/WPOrgSSO/Resources/views/delete_mailbox.blade.php, freescout.wordpress.net/Modules/WPOrgSSO/Http/Middleware/RequireWordPressOrgLogin.php, freescout.wordpress.net/Modules/WPOrgSSO/tests/DeleteMailboxTest.php, freescout.wordpress.net/Modules/WPOrgSSO/README.md
The mailbox settings page adds a name-entry prompt, and JavaScript includes the entered name in mailbox-deletion requests. Middleware checks the submitted name before passing the request to core. Tests cover name matching, break-glass password prompts, and permission handling. The README describes the password and mailbox-deletion rules.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  actor Administrator
  participant mailboxes.js
  participant RequireWordPressOrgLogin
  participant FreeScoutCore
  Administrator->>mailboxes.js: Enter mailbox name
  mailboxes.js->>RequireWordPressOrgLogin: Submit delete_mailbox with mailbox_name
  RequireWordPressOrgLogin->>FreeScoutCore: Continue request when name matches
Loading

Merge Risk: ⚪ Minimal · up to 532b0

The change replaces the mailbox deletion password prompt with a mailbox-name confirmation and clears non-break-glass passwords. No concrete merge-blocking risk was found, and the tests cover the main paths.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 532b0

Mailbox-name confirmation prevents accidental deletion but does not replace password reauthentication against a compromised administrator session. Emergency-password issuance also needs coordination with concurrent SSO logins so a newly issued recovery credential is not erased. Existing identity and permission controls limit these risks.

Retained concerns

  • Medium · security · inferred: For administrators whose real passwords are replaced with the dummy marker, mailbox deletion no longer requires an independent credential. An attacker possessing a usable administrator session can obtain the mailbox name from settings and submit deletion without fresh authentication. This intentionally broadens destructive-operation reachability compared with the previous password prompt; mailbox authorization remains required, and no CSRF bypass is established.
  • Medium · reliability · inferred: Emergency-password issuance and SSO clearing do not coordinate their shared credential state. During first issuance for an unmarked administrator, SSO can decide to clear the password before the command saves and marks the emergency credential, then persist its dummy value after the command reports success. Interruption between the command's password save and marker write also leaves inconsistent state. The new clearing path can therefore invalidate administrator recovery access; ordinary sequential preservation is covered by test definitions.
Security review details

Security Blast Radius

  • inferred — The deletion risk is bounded by the compromised session's mailbox-administration permissions within the helpdesk. The emergency-access race affects the administrator credential involved in overlapping issuance and SSO clearing. The password command requires server-side execution and rejects non-administrator targets; no wider cross-service authority expansion is established.

Security Findings and Attack Paths

  • inferred — A usable administrator session can read the confirmation name from mailbox settings and submit it to the deletion endpoint. For a password-cleared administrator, this supplies an accident-prevention token rather than fresh identity proof. The attack requires prior session compromise or equivalent authenticated authority; core CSRF enforcement and other deletion entrypoints remain unverified.

Trust Boundaries and Controls

  • observed — The module retains browser-bound SSO handoff and active-account validation. Under enforced SSO, password login is blocked unless emergency mode is enabled, and existing login hooks restrict that mode to administrators. Mailbox-name checking is server-side; authorized requests are then delegated to core for the remaining deletion controls.

Hardening Proposals

  • proposed — Retain mailbox-name confirmation for accident prevention, but consider fresh WordPress.org reauthentication for destructive deletion so SSO-only administrators retain an independent identity check.
  • proposed — Coordinate emergency issuance and SSO clearing as one per-user credential transition. Atomic password-and-marker persistence should be paired with locking or version checks against concurrent clearing, and preservation state should track the current credential lifecycle rather than historical issuance alone.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: requiring the mailbox name to confirm FreeScout mailbox deletions. It matches the pull request objectives and changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 29 functions across 9 files. (1 skipped: 1…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The required confirmation input needs an accessible label communicating its purpose and expected mailbox name.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Updates FreeScout’s WordPress.org sign-in integration so mailbox deletion uses name confirmation instead of an unavailable password, while preserving administrator break-glass passwords.

Changes:

  • Assigns core’s no-password marker on user creation and sign-in.
  • Adds mailbox-name confirmation in the dialog and server validation.
  • Documents the behavior and adds regression tests.
File Description
freescout.wordpress.net/​Modules/​WPOrgSSO/​tests/​PasswordsTest.php Tests password clearing and break-glass preservation.
freescout.wordpress.net/​Modules/​WPOrgSSO/​tests/​DeleteMailboxTest.php Tests deletion confirmation and permissions.
freescout.wordpress.net/​Modules/​WPOrgSSO/​Services/​Passwords.php Manages no-password markers and break-glass records.
freescout.wordpress.net/​Modules/​WPOrgSSO/​Resources/​views/​delete_mailbox.blade.php Adds the confirmation input.
freescout.wordpress.net/​Modules/​WPOrgSSO/​README.md Documents password and deletion behavior.
freescout.wordpress.net/​Modules/​WPOrgSSO/​Public/​js/​mailboxes.js Integrates confirmation into core’s dialog.
freescout.wordpress.net/​Modules/​WPOrgSSO/​Providers/​WPOrgSSOServiceProvider.php Registers assets, UI hooks, and password clearing.
freescout.wordpress.net/​Modules/​WPOrgSSO/​Http/​Middleware/​RequireWordPressOrgLogin.php Validates mailbox-name confirmation.
freescout.wordpress.net/​Modules/​WPOrgSSO/​Http/​Controllers/​SsoController.php Clears passwords after WordPress.org sign-in.
freescout.wordpress.net/​Modules/​WPOrgSSO/​Console/​SetPassword.php Records administrator break-glass passwords.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread freescout.wordpress.net/Modules/WPOrgSSO/Resources/views/delete_mailbox.blade.php Outdated
The instruction above the field isn't tied to it, so screen readers only
announced the placeholder. Give the field an aria-label that carries both
the instruction and the expected name. Core clones the template into the
dialog, so an id/for pair would end up duplicated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Password lifecycle changes and destructive-dialog integration need human validation against the deployed FreeScout version.

Review effort: Balanced
Findings: None

Resolved since last review (1)

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