Skip to content

Validated successUrl / cancelUrl / returnUrl origin in Stripe checkout#27845

Merged
mike182uk merged 1 commit into
mainfrom
BER-3647-validate-cancelurl-successurl-origin-in-stripe-checkout-creation
May 13, 2026
Merged

Validated successUrl / cancelUrl / returnUrl origin in Stripe checkout#27845
mike182uk merged 1 commit into
mainfrom
BER-3647-validate-cancelurl-successurl-origin-in-stripe-checkout-creation

Conversation

@mike182uk

Copy link
Copy Markdown
Member

ref https://linear.app/ghost/issue/BER-3647

  • the public create-stripe-checkout-session endpoint forwarded caller-supplied successUrl / cancelUrl verbatim to Stripe, which would redirect users to any external URL after checkout - turning the Ghost site into an open-redirect launch pad
  • the same applied to create-stripe-checkout-setup-session and create-stripe-billing-portal-session (both behind an identity token, but still worth tightening)
  • now reject any return URL whose origin or subpath doesn't match urlUtils.getSiteUrl(), letting the downstream stripe-api fall back to its existing same-origin defaults; the gift flow keeps its site-root cancelUrl fallback since Stripe gift checkout has no config-level default for cancel_url
  • subpath comparison normalizes both sides to trailing-slash form, so /blog and /blog/ are treated equivalently while /blogger is rejected

@coderabbitai

coderabbitai Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e14629d2-bd3f-4acc-a390-73746d93f630

📥 Commits

Reviewing files that changed from the base of the PR and between 4370fc1 and 043ca7d.

📒 Files selected for processing (2)
  • ghost/core/core/server/services/members/members-api/controllers/router-controller.js
  • ghost/core/test/unit/server/services/members/members-api/controllers/router-controller.test.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • ghost/core/test/unit/server/services/members/members-api/controllers/router-controller.test.js
  • ghost/core/core/server/services/members/members-api/controllers/router-controller.js

Walkthrough

This pull request adds URL sanitization to three Stripe checkout and billing endpoints to prevent open redirects. A new sanitizeReturnUrl helper validates that return URLs are well-formed, same-origin with the configured Ghost site URL, and located within the site's configured subpath. The helper is integrated into createCheckoutSetupSession, createBillingPortalSession, and createCheckoutSession for subscription, donation, and gift checkout flows. Invalid URLs return undefined, allowing Stripe to fall back to configured defaults. Comprehensive test coverage validates same-origin pass-through, cross-origin rejection, subpath enforcement, and gift-specific fallback behavior.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding validation for return URLs in Stripe checkout operations to prevent open redirects.
Description check ✅ Passed The description clearly explains the security issue being fixed, the scope of affected endpoints, and the validation logic implementation including subpath handling.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch BER-3647-validate-cancelurl-successurl-origin-in-stripe-checkout-creation

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.42.2)
ghost/core/test/unit/server/services/members/members-api/controllers/router-controller.test.js

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

@sagzy sagzy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice one, thorough and readable tests 👍

…heckout

ref https://linear.app/ghost/issue/BER-3647

- the public `create-stripe-checkout-session` endpoint forwarded
  caller-supplied `successUrl` / `cancelUrl` verbatim to Stripe, which would
  redirect users to any external URL after checkout - turning the Ghost
  site into an open-redirect launch pad
- the same applied to `create-stripe-checkout-setup-session` and
  `create-stripe-billing-portal-session` (both behind an identity token,
  but still worth tightening)
- now reject any return URL whose origin or subpath doesn't match
  `urlUtils.getSiteUrl()`, letting the downstream stripe-api fall back to
  its existing same-origin defaults; the gift flow keeps its site-root
  cancelUrl fallback since Stripe gift checkout has no config-level
  default for `cancel_url`
- subpath comparison normalizes both sides to trailing-slash form, so
  `/blog` and `/blog/` are treated equivalently while `/blogger` is rejected
@mike182uk mike182uk force-pushed the BER-3647-validate-cancelurl-successurl-origin-in-stripe-checkout-creation branch from 4370fc1 to 043ca7d Compare May 13, 2026 07:10
@mike182uk mike182uk merged commit 67a4b51 into main May 13, 2026
43 checks passed
@mike182uk mike182uk deleted the BER-3647-validate-cancelurl-successurl-origin-in-stripe-checkout-creation branch May 13, 2026 07:36
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