Skip to content

🛡️ Sentinel: [HIGH] Harden OAuth postMessage security#11

Open
AGI-Corporation wants to merge 4 commits intomainfrom
sentinel-secure-oauth-postmessage-11497284544736004468
Open

🛡️ Sentinel: [HIGH] Harden OAuth postMessage security#11
AGI-Corporation wants to merge 4 commits intomainfrom
sentinel-secure-oauth-postmessage-11497284544736004468

Conversation

@AGI-Corporation
Copy link
Copy Markdown
Owner

@AGI-Corporation AGI-Corporation commented Mar 7, 2026

🚨 Severity: HIGH
💡 Vulnerability: Insecure use of postMessage with wildcard origin ('*') and weak origin validation using startsWith.
🎯 Impact: Sensitive OAuth codes could be intercepted by malicious origins if they are able to open the redirect window or if the origin validation is bypassed.
🔧 Fix:

  • Restricted postMessage target origins to trusted frontend URLs using domainHelper.getPublicUrl on the server and window.location.origin on the client.
  • Hardened origin verification in the message listener by using strict equality of the derived origin instead of startsWith.
  • Added robust URL parsing and safety checks to prevent crashes.
    ✅ Verification: Targeted linting of modified files and manual code review. Logic ensures defense-in-depth for sensitive data transmission between windows.

PR created automatically by Jules for task 11497284544736004468 started by @AGI-Corporation

Summary by CodeRabbit

  • Bug Fixes

    • Hardened OAuth postMessage handling by restricting and strictly validating the target origin.
    • Improved popup cleanup and removal of event listeners after OAuth redirects complete.
    • Added safer handling for missing or invalid redirect URLs and related edge-case errors.
  • Documentation

    • Added a security note documenting the origin hardening guidance and mitigation steps.

- Restrict target origin for postMessage in OAuth redirect handlers on both server and client.
- Replace insecure `startsWith` origin validation with strict equality check of the derived origin.
- Add safety checks for URL parsing to prevent potential crashes.

Co-authored-by: AGI-Corporation <186229839+AGI-Corporation@users.noreply.github.com>
@google-labs-jules
Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 7, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6ba00d31-3fa2-437f-9022-49af004ffbbb

📥 Commits

Reviewing files that changed from the base of the PR and between 1333df9 and 8635de7.

📒 Files selected for processing (1)
  • .jules/sentinel.md

📝 Walkthrough

Walkthrough

Hardened OAuth postMessage handling: replaced wildcard targets with explicit origin values, tightened origin validation using parsed origins, added guards for undefined redirect URLs, and ensured popups are closed and listeners removed after successful code retrieval.

Changes

Cohort / File(s) Summary
OAuth2 Security Hardening
packages/react-ui/src/app/routes/redirect.tsx, packages/react-ui/src/lib/oauth2-utils.ts, packages/server/api/src/app/app.ts
Replaced '*' postMessage target with explicit origin (derived via new URL(...).origin); changed origin checks from startsWith to strict equality; added guard for optional redirectUrl; popup now closes and message listener is removed after code retrieval.
Documentation / Notes
.jules/sentinel.md
Added a security note documenting the OAuth postMessage origin hardening, describing the vulnerability with wildcard origins and advising strict origin equality and URL parsing checks.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Popup as OAuth Popup
    participant Server as Auth Server
    participant App as Parent App

    User->>Popup: initiate auth
    Popup->>Server: auth request / redirect
    Server-->>Popup: redirect with code to redirectUrl
    Popup->>App: window.opener.postMessage({code}, targetOrigin=<parsed origin>)
    App->>App: onmessage handler receives event
    App->>App: if event.origin === expectedOrigin (new URL(redirectUrl).origin)
    App-->>Popup: (optional) close popup
    App->>App: remove message listener
    App->>Server: exchange code for token
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hop between origins, tidy and neat,
No wildcards here—just checks complete.
I close the popup, tidy the way,
Listeners gone, tokens safe today.
A little hop for secure OAuth feet.

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description lacks required sections from the template: 'What does this PR do?' with clear feature explanation, 'How the Feature Works', and 'Relevant User Scenarios' are missing or incomplete. Add the missing template sections: provide a clear summary in 'What does this PR do?', explain how the hardened security works in 'Explain How the Feature Works', and list relevant user scenarios or affected use cases in 'Relevant User Scenarios'.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main security-focused change: hardening OAuth postMessage security by restricting origins and improving validation.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sentinel-secure-oauth-postmessage-11497284544736004468

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.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1333df9ffb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return reply.send('The code is missing in url')
}
else {
const origin = await domainHelper.getPublicUrl({})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve tenant-specific origin in OAuth redirect

Using domainHelper.getPublicUrl({}) here hard-codes the default frontend URL as the postMessage target, which breaks OAuth callbacks opened from tenant/custom domains. In Enterprise, THIRD_PARTY_AUTH_PROVIDER_REDIRECT_URL is generated per platformId (via getThirdPartyRedirectUrl(platformId)), so the popup can run on a custom domain while this script posts only to the global frontend origin; browsers drop that message and the login flow never resolves.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/react-ui/src/lib/oauth2-utils.ts (1)

74-95: ⚠️ Potential issue | 🟠 Major

Promise never resolves if redirectUrl is undefined or URL parsing fails.

If redirectUrl is undefined (lines 77-79) or URL parsing throws (lines 83-85), the handler returns early but the Promise created on line 75 never resolves or rejects. This leaves callers hanging indefinitely.

Looking at actual call sites (openWithLoginUrl and openOAuth2Popup), redirectUrl is always typed as a required string, so undefined should never occur in practice. However, the defensive guards should either:

  1. Reject the Promise to signal failure, or
  2. Keep the signature as string only and handle the try/catch by rejecting
🛠️ Proposed fix: Reject Promise on failure
-function getCode(redirectUrl: string | undefined): Promise<string> {
-  return new Promise<string>((resolve) => {
-    window.addEventListener('message', function handler(event) {
-      if (!redirectUrl) {
-        return;
-      }
-      let origin;
-      try {
-        origin = new URL(redirectUrl).origin;
-      } catch (e) {
-        return;
-      }
+function getCode(redirectUrl: string): Promise<string> {
+  return new Promise<string>((resolve, reject) => {
+    let origin: string;
+    try {
+      origin = new URL(redirectUrl).origin;
+    } catch (e) {
+      reject(new Error('Invalid redirect URL'));
+      return;
+    }
+    window.addEventListener('message', function handler(event) {
       if (
         origin === event.origin &&
         event.data['code']
       ) {
         resolve(decodeURIComponent(event.data.code));
         currentPopup?.close();
         window.removeEventListener('message', handler);
       }
     });
   });
 }

This also moves URL parsing outside the event handler since it only needs to be computed once.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-ui/src/lib/oauth2-utils.ts` around lines 74 - 95, The getCode
function currently can leave its Promise unresolved when redirectUrl is
undefined or URL parsing fails; update getCode to require a string redirectUrl
(or validate and immediately reject if undefined) and move new URL(redirectUrl)
parsing outside the message handler so parsing happens once; if parsing throws
or redirectUrl is falsy, immediately reject the Promise with a clear error and
ensure any created popup (currentPopup) is closed and the message handler
removed on both success and failure paths; reference getCode, currentPopup,
openWithLoginUrl and openOAuth2Popup to check callsites/types so the signature
and error handling remain consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/react-ui/src/lib/oauth2-utils.ts`:
- Around line 74-95: The getCode function currently can leave its Promise
unresolved when redirectUrl is undefined or URL parsing fails; update getCode to
require a string redirectUrl (or validate and immediately reject if undefined)
and move new URL(redirectUrl) parsing outside the message handler so parsing
happens once; if parsing throws or redirectUrl is falsy, immediately reject the
Promise with a clear error and ensure any created popup (currentPopup) is closed
and the message handler removed on both success and failure paths; reference
getCode, currentPopup, openWithLoginUrl and openOAuth2Popup to check
callsites/types so the signature and error handling remain consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 00df8a50-7491-44a0-9809-da7f785617ee

📥 Commits

Reviewing files that changed from the base of the PR and between f61e720 and 1333df9.

📒 Files selected for processing (3)
  • packages/react-ui/src/app/routes/redirect.tsx
  • packages/react-ui/src/lib/oauth2-utils.ts
  • packages/server/api/src/app/app.ts

google-labs-jules bot and others added 3 commits March 7, 2026 08:55
- Restrict target origin for postMessage in OAuth redirect handlers on both server and client.
- Replace insecure `startsWith` origin validation with strict equality check of the derived origin.
- Add safety checks for URL parsing to prevent potential crashes.

Co-authored-by: AGI-Corporation <186229839+AGI-Corporation@users.noreply.github.com>
…y journal

- Restrict target origin for postMessage in OAuth redirect handlers.
- Replace insecure `startsWith` origin validation with strict equality.
- Add safety checks for URL parsing.
- Add sentinel security journal entry.

Co-authored-by: AGI-Corporation <186229839+AGI-Corporation@users.noreply.github.com>
…y journal

- Restrict target origin for postMessage in OAuth redirect handlers.
- Replace insecure `startsWith` origin validation with strict equality.
- Add safety checks for URL parsing.
- Add sentinel security journal entry.

Co-authored-by: AGI-Corporation <186229839+AGI-Corporation@users.noreply.github.com>
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.

1 participant