fix: Use modern email validator to support new gTLDs (.rocks, .radio, .app)#27136
fix: Use modern email validator to support new gTLDs (.rocks, .radio, .app)#27136cyphercodes wants to merge 1 commit intoTryGhost:mainfrom
Conversation
… .app)
Changed all validator.isEmail() calls to use {legacy: false} option,
which enables support for modern generic Top-Level Domains like
.rocks, .radio, .app that were approved by ICANN after 2012.
The legacy validator (validator@7.2.0 from 2017) predates many gTLDs
and rejects valid email addresses using these domains.
Files changed:
- email-address-service-wrapper.js
- automated_emails.js
- invitations.js
- password_reset.js
- settings.js
Fixes TryGhost#26197
WalkthroughThis pull request updates email validation logic across five files in the Ghost codebase. Each file's 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@ghost/core/core/server/api/endpoints/utils/validators/input/automated_emails.js`:
- Line 76: Update the two member-facing validators to use the modern email rules
by adding the options object {legacy: false} to the validator.isEmail calls:
locate the email validation in magic-link.js (the function that validates the
magic-link/email input) and the email check in router-controller.js (the
controller handling member signup/signin) and change their
validator.isEmail(email) calls to validator.isEmail(email, {legacy: false}),
keeping any surrounding typeof/email presence checks intact so behavior matches
the other validators (e.g., automated_emails.js).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 4b81fdd4-def0-4bc1-b71a-eba7fd44667b
📒 Files selected for processing (5)
ghost/core/core/server/api/endpoints/utils/validators/input/automated_emails.jsghost/core/core/server/api/endpoints/utils/validators/input/invitations.jsghost/core/core/server/api/endpoints/utils/validators/input/password_reset.jsghost/core/core/server/api/endpoints/utils/validators/input/settings.jsghost/core/core/server/services/email-address/email-address-service-wrapper.js
| const lexical = frame.data.lexical; | ||
|
|
||
| if (typeof email !== 'string' || !validator.isEmail(email)) { | ||
| if (typeof email !== 'string' || !validator.isEmail(email, {legacy: false})) { |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify member-facing email validation callsites still using default isEmail(...)
rg -nP --type=js -C2 '\bisEmail\s*\(\s*[^,()]+\s*\)' \
ghost/core/core/server/services/members/members-api/controllers/router-controller.js \
ghost/core/core/server/services/lib/magic-link/magic-link.js
# Compare with explicit modern validation usage added in this PR area
rg -nP --type=js -C2 '\bisEmail\s*\(\s*[^,()]+\s*,\s*\{\s*legacy\s*:\s*false\s*\}\s*\)' \
ghost/core/core/server/api/endpoints/utils/validators/input \
ghost/core/core/server/services/email-address/email-address-service-wrapper.jsRepository: TryGhost/Ghost
Length of output: 4390
Member authentication flows still use legacy email validation.
Two member-facing entry points (magic-link.js line 75 and router-controller.js line 706) still call isEmail(...) without { legacy: false }, while the current file and other API validators use the modern validation. This allows modern gTLDs to slip through validation in signup and signin flows, creating an inconsistent email validation scope.
These files need to adopt the same { legacy: false } parameter:
ghost/core/core/server/services/lib/magic-link/magic-link.jsghost/core/core/server/services/members/members-api/controllers/router-controller.js
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@ghost/core/core/server/api/endpoints/utils/validators/input/automated_emails.js`
at line 76, Update the two member-facing validators to use the modern email
rules by adding the options object {legacy: false} to the validator.isEmail
calls: locate the email validation in magic-link.js (the function that validates
the magic-link/email input) and the email check in router-controller.js (the
controller handling member signup/signin) and change their
validator.isEmail(email) calls to validator.isEmail(email, {legacy: false}),
keeping any surrounding typeof/email presence checks intact so behavior matches
the other validators (e.g., automated_emails.js).
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0076c66. Configure here.
| const email = frame.data.email; | ||
|
|
||
| if (typeof email !== 'string' || !validator.isEmail(email)) { | ||
| if (typeof email !== 'string' || !validator.isEmail(email, {legacy: false})) { |
There was a problem hiding this comment.
Incomplete fix misses member sign-in email validation paths
Medium Severity
The PR updates five files to use {legacy: false} for new gTLD support but misses router-controller.js and magic-link.js, which also call isEmail() without this option in the member sign-in flow. Since member-repository.js already allows creating members with new gTLD emails, those members can be created but then blocked from signing in via magic link, as router-controller.js:706 and magic-link.js:75 still reject their emails using the legacy validator.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 0076c66. Configure here.





Summary
Fixed email validation to support modern generic Top-Level Domains (gTLDs) like
.rocks,.radio,.app, etc.Problem
Ghost's email validation was rejecting legitimate email addresses using newer gTLDs approved by ICANN after 2012. The legacy validator (validator@7.2.0 from 2017) predates many of these TLDs.
Solution
Changed all
validator.isEmail()calls to use{legacy: false}option, which enables the modern custom validator that properly handles all TLDs.Files Changed
email-address-service-wrapper.jsautomated_emails.jsinvitations.jspassword_reset.jssettings.jsTesting
Fixes #26197
Note
Medium Risk
Touches email validation in user-management and auth-adjacent flows (invitations, password reset, settings), which could change what addresses are accepted/rejected. Scope is small and limited to validator options, but impacts multiple entry points.
Overview
Switches multiple API input validators to call
validator.isEmail(..., {legacy: false})instead of the legacy mode, aligning validation behavior across endpoints.This updates email checks for automated email test sends, staff invitations, password reset token generation, settings email fields (e.g.
members_support_address), and the email-address service wrapper so newer valid domains (newer gTLDs) are accepted consistently.Reviewed by Cursor Bugbot for commit 0076c66. Bugbot is set up for automated code reviews on this repo. Configure here.