-
Notifications
You must be signed in to change notification settings - Fork 0
π‘οΈ Sentinel: Fix insecure postMessage target origins in OAuth2 flow #12
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| ## 2025-05-15 - [Secure postMessage origins in OAuth2 flow] | ||
| **Vulnerability:** Use of `*` wildcard as target origin in `window.postMessage` during OAuth2 redirection, which could leak authorization codes to malicious windows. | ||
| **Learning:** The codebase has multiple places (frontend and backend) where `postMessage` is used to communicate the OAuth code back to the opener. | ||
| **Prevention:** Use `window.location.origin` on the client and `domainHelper.getPublicUrl` on the server to resolve the trusted frontend origin. Always extract only the origin (scheme + host + port) using `new URL(url).origin` to ensure strict matching by the browser. | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -250,12 +250,14 @@ export const setupApp = async (app: FastifyInstance): Promise<FastifyInstance> = | |||||||||
| return reply.send('The code is missing in url') | ||||||||||
| } | ||||||||||
| else { | ||||||||||
| const frontendUrl = await domainHelper.getPublicUrl({ platformId: null }) | ||||||||||
| const frontendOrigin = new URL(frontendUrl).origin | ||||||||||
|
Comment on lines
+253
to
+254
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Using Useful? React with πΒ / π. |
||||||||||
| return reply | ||||||||||
| .type('text/html') | ||||||||||
| .send( | ||||||||||
| `<script>if(window.opener){window.opener.postMessage({ 'code': '${encodeURIComponent( | ||||||||||
| params.code, | ||||||||||
| )}' },'*')}</script> <html>Redirect succuesfully, this window should close now</html>`, | ||||||||||
| )}' }, '${frontendOrigin}')}</script> <html>Redirect succuesfully, this window should close now</html>`, | ||||||||||
|
Comment on lines
+253
to
+260
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π§© Analysis chainπ Script executed: #!/bin/bash
# Description: Check how domainHelper.getPublicUrl handles platformId and multi-tenant scenarios
# Find the implementation of getPublicUrl
ast-grep --pattern 'getPublicUrl($$$) {
$$$
}'
# Check how other redirect endpoints handle platformId
rg -n "getPublicUrl|getInternalUrl" --type ts -C 3 | head -80
# See if there are any existing multi-platform redirect handling patterns
rg -n "platformId.*redirect|redirect.*platformId" --type ts -C 2Repository: AGI-Corporation/Route.X Length of output: 8543 π Script executed: # Get the full context of the endpoint where platformId: null is used
sed -n '240,270p' packages/server/api/src/app/app.ts
# Search for the endpoint definition and see if there's any state parameter handling
rg -n "platformId.*null|params\.code|oauth.*redirect" packages/server/api/src/app/app.ts -B 5 -A 2Repository: AGI-Corporation/Route.X Length of output: 2018 π Script executed: # Check if OAuth implementations use state parameter to track platform context
rg -n "state.*platform|platform.*state|oauth.*state" packages/server/api/src/app/ee/authentication --type ts -i | head -40
# Search for OAuth redirect implementations and see if any track platform
rg -n "getThirdPartyRedirectUrl|oauthRedirectUrl|redirect_uri" packages/server/api/src/app/ee/authentication --type ts -C 3 | head -100
# Check if there's any platform tracking mechanism in OAuth flows
rg -n "window.opener.postMessage|state.*=|platformId" packages/server/api/src/app --type ts -B 2 -A 2Repository: AGI-Corporation/Route.X Length of output: 50380 π Script executed: # Search for how OAuth flows pass context through the OAuth flow
rg -n "state|oauth.*code|code.*oauth" packages/server/api/src/app/ee/authentication --type ts -C 2 | grep -E "(state|oauth)" | head -50
# Check the frontend to see how it handles the postMessage
fd "redirect" packages/server -t ts | head -5
# Search for comments or patterns around platformId: null
rg -n "platformId.*null" packages/server/api/src/app/app.ts -B 5 -A 5
# Check if there's a state parameter or similar mechanism in OAuth flow
rg -n "searchParams|query|state" packages/server/api/src/app/ee/authentication/federated-authn --type ts | head -30Repository: AGI-Corporation/Route.X Length of output: 1927 π Script executed: # Check Google OAuth implementation for state parameter
sed -n '1,100p' packages/server/api/src/app/ee/authentication/federated-authn/google-authn-provider.ts
# Check if state is used anywhere in federated auth
rg -n "state" packages/server/api/src/app/ee/authentication/federated-authn/ --type ts -C 2
# Look at the entire app.ts redirect endpoint context
sed -n '240,270p' packages/server/api/src/app/app.tsRepository: AGI-Corporation/Route.X Length of output: 4295 π Script executed: # Get the full implementation of getThirdPartyRedirectUrl
sed -n '50,60p' packages/server/api/src/app/ee/authentication/federated-authn/federated-authn-service.ts
# Check if there are other redirect endpoints that handle platformId
rg -n "app.get.*redirect|app.post.*redirect" packages/server/api/src/app -C 2 | head -50Repository: AGI-Corporation/Route.X Length of output: 296 π Script executed: # Check if there's a way to extract platformId from request hostname
rg -n "request.hostname|request.host|req.headers.host" packages/server/api/src/app -C 2 | head -40
# Check if customDomainService can lookup platformId by hostname
sed -n '1,50p' packages/server/api/src/app/ee/custom-domains/custom-domain.service.tsRepository: AGI-Corporation/Route.X Length of output: 2286 Extract platformId from request hostname instead of hardcoding null. The endpoint receives the OAuth redirect at a platform-specific URL (built by Use Minor: Fix typo "succuesfully" β "successfully". π€ Prompt for AI Agents |
||||||||||
| ) | ||||||||||
|
Comment on lines
+260
to
261
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo: "succuesfully" β "successfully". Minor typo in the HTML response message. π Proposed fix )}' }, '${frontendOrigin}')}</script> <html>Redirect succuesfully, this window should close now</html>`,
+ )}' }, '${frontendOrigin}')}</script> <html>Redirect successfully, this window should close now</html>`,π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||||||
| } | ||||||||||
| }, | ||||||||||
|
|
||||||||||
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.
Date inconsistency in the documentation header.
The date "2025-05-15" appears to predate the PR creation timestamp (2026-03-08). This could cause confusion when reviewing the security timeline. Consider using the actual date when the vulnerability was fixed or documented.
π€ Prompt for AI Agents