Skip to content

Conversation

@subrata71
Copy link
Collaborator

@subrata71 subrata71 commented Nov 19, 2025

Key changes

  • Log mismatch if origin in request header doesn't match the derived host
  • Always set the base URL after deriving from request

Slack thread

Fixes #Issue Number
or
Fixes Issue URL

Warning

If no issue exists, please create an issue first, and check with the maintainers if the issue is valid.

Automation

/ok-to-test tags="@tag.All"

🔍 Cypress test results

Tip

🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
Workflow run: https://github.com/appsmithorg/appsmith/actions/runs/19491671380
Commit: ad9ae53
Cypress dashboard.
Tags: @tag.All
Spec:


Wed, 19 Nov 2025 07:15:50 UTC

Communication

Should the DevRel and Marketing teams inform users about this change?

  • Yes
  • No

Summary by CodeRabbit

  • Bug Fixes
    • Improved URL handling for password reset and email verification requests to ensure links work correctly across various server configurations and proxy setups.

@github-actions github-actions bot added the Bug Something isn't working label Nov 19, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 19, 2025

Walkthrough

This PR introduces host-based URL derivation infrastructure by adding a new HostUrlHelper utility and integrating it into UserController endpoints. The helper resolves client-facing base URLs from request context, replacing direct Origin header usage in password reset and email verification flows.

Changes

Cohort / File(s) Summary
UserController Dependency Injection
UserController.java
Added HostUrlHelper parameter to constructor and propagated via superclass call.
UserControllerCE Method Signatures
UserControllerCE.java
Updated forgotPasswordRequest and resendEmailVerification to accept ServerWebExchange parameter and delegate base URL derivation to hostUrlHelper.getClientFacingBaseUrl() instead of direct Origin header usage.
HostUrlHelper Utility
HostUrlHelper.java, HostUrlHelperCE.java
New Spring component and CE-specific utility class for host URL resolution. HostUrlHelperCE provides prioritized host extraction (OAuth2 query params → Forwarded header → X-Forwarded-\* headers → Host header) with scheme normalization and configured domain sanitization.

Sequence Diagram

sequenceDiagram
    participant Client
    participant UserControllerCE
    participant HostUrlHelper
    participant ServerRequest as Request Context

    Client->>UserControllerCE: POST forgotPasswordRequest
    UserControllerCE->>HostUrlHelper: getClientFacingBaseUrl(originHeader, exchange)
    
    HostUrlHelper->>ServerRequest: Check configured domain (appsmith.domain)
    alt Configured domain exists
        HostUrlHelper->>ServerRequest: sanitizeConfiguredDomain()
        HostUrlHelper-->>HostUrlHelper: Normalize & prefix scheme
    else No configured domain
        HostUrlHelper->>ServerRequest: getHostUrl(request)
        HostUrlHelper->>HostUrlHelper: Try OAuth2 query params
        HostUrlHelper->>HostUrlHelper: Try RFC 7239 Forwarded header
        HostUrlHelper->>HostUrlHelper: Try X-Forwarded-\\* headers
        HostUrlHelper->>HostUrlHelper: Fall back to Host header
    end
    
    HostUrlHelper-->>UserControllerCE: baseUrl (or empty string)
    UserControllerCE-->>Client: ResponseDTO
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • HostUrlHelperCE: Complex multi-path header parsing logic (OAuth2 query params, RFC 7239 Forwarded header, X-Forwarded-\* fallbacks, Host header) requires verification of precedence correctness and scheme normalization
  • Header parsing edge cases: Verify URL encoding/decoding, null-safety in chain of extraction methods, and mismatch logging behavior
  • Integration points: Confirm ServerWebExchange threading through controller methods doesn't introduce concurrency issues; validate that bean injection in UserController properly wires the new dependency

Poem

🔗 A helper springs forth, URLs refined,
Through headers and queries, the true host we find,
No more Origin guesses, just logic so bright,
Where forwarded requests meet crypto's good light! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning PR description lacks critical information: no issue link is provided (placeholder text remains), no motivation or context beyond a Slack link, and dependencies are not documented. Fill in the issue number or URL, add clear motivation/context for the account takeover fix, document any dependencies, and remove placeholder text.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: fixing an account takeover vulnerability by improving host URL validation and resolution.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/account-takeover-vulnerability

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 and usage tips.

@subrata71 subrata71 self-assigned this Nov 19, 2025
@subrata71 subrata71 added the ok-to-test Required label for CI label Nov 19, 2025
@subrata71 subrata71 requested a review from sharat87 November 19, 2025 06:11
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/HostUrlHelperCE.java (1)

82-94: Forwarded header parsing is fragile but safe.

The simple string split approach (line 87) for parsing the RFC 7239 Forwarded header may fail on edge cases or malformed headers. However, the try-catch wrapper ensures it fails safely and falls through to other header sources.

Consider using a more robust parsing approach or a library designed for RFC 7239 parsing if this becomes an issue in production.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3788dee and ad9ae53.

📒 Files selected for processing (4)
  • app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/UserController.java (3 hunks)
  • app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/UserControllerCE.java (4 hunks)
  • app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/HostUrlHelper.java (1 hunks)
  • app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/HostUrlHelperCE.java (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-10-04T05:51:15.138Z
Learnt from: abhvsn
Repo: appsmithorg/appsmith PR: 36596
File: app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/UserSignupCEImpl.java:475-475
Timestamp: 2024-10-04T05:51:15.138Z
Learning: In `app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/UserSignupCEImpl.java`, the variable `newsletterSignedUpUserEmail` is always expected to be non-null because the user's email is always present in the user object, so an additional null check is unnecessary.

Applied to files:

  • app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/UserController.java
  • app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/UserControllerCE.java
🧬 Code graph analysis (2)
app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/HostUrlHelper.java (1)
app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/HostUrlHelperCE.java (1)
  • Slf4j (14-187)
app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/HostUrlHelperCE.java (1)
app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/HostUrlHelper.java (1)
  • Slf4j (7-9)
⏰ 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). (5)
  • GitHub Check: perform-test / rts-build / build
  • GitHub Check: perform-test / server-build / server-unit-tests
  • GitHub Check: perform-test / client-build / client-build
  • GitHub Check: server-spotless / spotless-check
  • GitHub Check: server-unit-tests / server-unit-tests
🔇 Additional comments (9)
app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/HostUrlHelper.java (1)

1-9: LGTM!

Clean wrapper class following the CE/EE pattern. The @Component annotation enables Spring DI for the parent class's @Value fields.

app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/UserController.java (1)

21-38: LGTM!

Standard dependency injection pattern. The HostUrlHelper is properly wired through the constructor and forwarded to the parent class.

app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/UserControllerCE.java (3)

51-51: LGTM!

The HostUrlHelper is properly declared as a final field for constructor injection via Lombok's @RequiredArgsConstructor.


86-103: Excellent security improvement!

The method now derives the client-facing URL via HostUrlHelper instead of trusting the Origin header directly. This prevents account takeover attacks where an attacker could spoof the Origin header to redirect password reset emails to malicious domains.

The Origin header is now only used for logging discrepancies, which is the correct approach.


187-200: Excellent security improvement!

Consistent with the forgotPasswordRequest fix, this method now derives URLs via HostUrlHelper instead of directly using the Origin header. This prevents the same class of account takeover vulnerability in the email verification flow.

app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/HostUrlHelperCE.java (4)

26-65: Excellent security design!

This method implements the core vulnerability fix by deliberately ignoring the Origin header for URL derivation, using it only for logging discrepancies. The priority order (operator config → request metadata) ensures operators can enforce canonical URLs while still supporting dynamic environments.

The clear documentation and safe fallback (empty string) are well-designed.


96-106: LGTM!

Standard and secure handling of reverse proxy headers. X-Forwarded-* headers are operator-controlled (set by the proxy/load balancer), making them trustworthy sources for host derivation.


108-115: LGTM!

The fallback to the standard Host header is appropriate. In properly configured environments (especially behind proxies), this header reflects the actual host used to reach the server.


167-186: LGTM! Secure defaults.

The method properly sanitizes configured domains and defaults to https when the scheme cannot be determined (line 182), which is the secure choice.

@github-actions
Copy link

Failed server tests

  • com.appsmith.server.helpers.UserUtilsTest#makeInstanceAdministrator_WhenUserAlreadyAdmin_MaintainsPermissionsSuccessfully

@github-actions
Copy link

This PR has not seen activitiy for a while. It will be closed in 7 days unless further activity is detected.

@github-actions github-actions bot added the Stale label Nov 26, 2025
@subrata71
Copy link
Collaborator Author

Closing in favor of these
EE: https://github.com/appsmithorg/appsmith-ee/pull/8448
CE: #41426

@subrata71 subrata71 closed this Nov 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Something isn't working ok-to-test Required label for CI Stale

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant