-
-
Notifications
You must be signed in to change notification settings - Fork 11.2k
🐛 Fixed query params being stripped on private site login #25596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
ref https://linear.app/ghost/issue/NY-693/ - updated middleware to pass through query/search params with path
WalkthroughThis change modifies the redirect URL handling in the private blogging middleware to properly preserve query strings during login redirects. The Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
ghost/core/core/frontend/apps/private-blogging/lib/middleware.js (1)
28-46: Redirect URL parsing and query preservation look solid; host check could be simplifiedThe updated
getRedirectUrlcorrectly:
- Decodes the
rparam safely under atry/catch.- Uses
URLto normalise the path.- Preserves the query string via
pathname + search.- Still prevents redirects off-instance by collapsing suspicious values (e.g. full URLs or
//host-style paths) back to/.As a small optional tidy-up, you could drop the extra
targetURL construction and useparsedUrldirectly for the host check, which keeps all logic in one place and avoids a second parse:function getRedirectUrl(query) { try { - const redirect = decodeURIComponent(query.r || '/'); - const parsedUrl = new URL(redirect, config.get('url')); - const pathname = parsedUrl.pathname; - const search = parsedUrl.search; - - const base = new URL(config.get('url')); - const target = new URL(pathname, config.get('url')); - // Make sure we don't redirect outside of the instance - if (target.host !== base.host) { - return '/'; - } - // Preserve query string (e.g., UTM parameters) - return pathname + search; + const redirect = decodeURIComponent(query.r || '/'); + const baseUrl = config.get('url'); + const base = new URL(baseUrl); + const parsedUrl = new URL(redirect, baseUrl); + + // Make sure we don't redirect outside of the instance + if (parsedUrl.host !== base.host) { + return '/'; + } + + // Preserve query string (e.g., UTM parameters) + return parsedUrl.pathname + parsedUrl.search; } catch (e) { return '/'; } }Behavior should remain the same (including the existing tests around full URLs and
http://britney.com//example.com), but the intent becomes a bit clearer.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
ghost/core/core/frontend/apps/private-blogging/lib/middleware.js(1 hunks)ghost/core/test/unit/frontend/apps/private-blogging/middleware.test.js(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24779
File: ghost/core/core/server/services/members/members-api/controllers/RouterController.js:34-51
Timestamp: 2025-09-03T12:28:11.174Z
Learning: The extractRefererOrRedirect function in Ghost's RouterController (ghost/core/core/server/services/members/members-api/controllers/RouterController.js) is working as intended according to maintainer kevinansfield. The current handling of autoRedirect, redirect parameter parsing, and referrer logic does not need the security-related changes suggested around autoRedirect coercion, relative URL handling, or same-origin checks.
📚 Learning: 2025-03-13T09:00:20.205Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/utils/pending-activity.ts:13-71
Timestamp: 2025-03-13T09:00:20.205Z
Learning: The pending activity utilities in the Ghost ActivityPub module are covered by tests in the file `apps/admin-x-activitypub/test/unit/utils/pending-activity.ts`.
Applied to files:
ghost/core/test/unit/frontend/apps/private-blogging/middleware.test.js
📚 Learning: 2025-09-03T12:28:11.174Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24779
File: ghost/core/core/server/services/members/members-api/controllers/RouterController.js:34-51
Timestamp: 2025-09-03T12:28:11.174Z
Learning: The extractRefererOrRedirect function in Ghost's RouterController (ghost/core/core/server/services/members/members-api/controllers/RouterController.js) is working as intended according to maintainer kevinansfield. The current handling of autoRedirect, redirect parameter parsing, and referrer logic does not need the security-related changes suggested around autoRedirect coercion, relative URL handling, or same-origin checks.
Applied to files:
ghost/core/core/frontend/apps/private-blogging/lib/middleware.js
📚 Learning: 2025-04-23T15:44:52.549Z
Learnt from: 9larsons
Repo: TryGhost/Ghost PR: 21866
File: ghost/core/core/server/web/admin/middleware/serve-auth-frame-file.js:10-19
Timestamp: 2025-04-23T15:44:52.549Z
Learning: The existing implementation in `ghost/core/core/server/web/admin/middleware/serve-auth-frame-file.js` using `path.parse(req.url).base` is secure against path traversal attacks as it properly extracts only the filename component without any directory parts.
Applied to files:
ghost/core/core/frontend/apps/private-blogging/lib/middleware.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Ghost-CLI tests
- GitHub Check: Acceptance tests (Node 22.18.0, sqlite3)
- GitHub Check: Acceptance tests (Node 22.18.0, mysql8)
- GitHub Check: Legacy tests (Node 22.18.0, sqlite3)
- GitHub Check: Legacy tests (Node 22.18.0, mysql8)
- GitHub Check: Unit tests (Node 22.18.0)
- GitHub Check: Lint
- GitHub Check: Cursor Bugbot
- GitHub Check: Build & Push
🔇 Additional comments (1)
ghost/core/test/unit/frontend/apps/private-blogging/middleware.test.js (1)
283-307: New tests accurately cover query-string preservation for private login redirectsBoth added specs set up
req.body,req.session, andreq.query.rconsistently with the existing suite and assert the exactres.redirecttarget, ensuring:
- Root-level URLs preserve UTM-style query params.
- Path URLs preserve their query strings as well.
This aligns with the new
getRedirectUrlbehavior and keeps the existing security-focused tests (full URLs / other domains) intact.
E2E Tests FailedTo view the Playwright test report locally, run: REPORT_DIR=$(mktemp -d) && gh run download 19897988807 -n playwright-report -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR" |
ref https://linear.app/ghost/issue/NY-693/
Note
Private login redirects now keep original query strings (e.g., UTM params) while still preventing cross-domain redirects.
core/frontend/apps/private-blogging/lib/middleware.js)getRedirectUrlto parse withURL, validate host, and returnpathname + searchto preserve query strings.test/unit/frontend/apps/private-blogging/middleware.test.js)/.Written by Cursor Bugbot for commit b510f4c. This will update automatically on new commits. Configure here.