You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Missing OAuth state validation allows login-CSRF via the gitify:// callback #3425
Affected versions: confirmed on commit 339aee39ed899f9993e08dd1bd48392494f8b889 (current default branch, main).
Summary
The OAuth App web-flow login never generates or validates an OAuth state parameter, so an authorization code arriving through the app's gitify://oauth custom protocol callback is accepted and exchanged for an access token regardless of where it came from, including a code an attacker obtained for their own GitHub account.
No state option is passed to getWebFlowAuthorizationUrl, and handleCallback never reads or compares a state value from the callback URL. The dependency @octokit/oauth-authorization-url happens to append its own Math.random()-derived state to the authorization URL as a fallback when none is supplied, but since Gitify never stores or checks that value, it has no security effect; it is functionally inert.
src/main/index.ts registers a gitify:// custom protocol handler:
src/main/lifecycle/startup.ts, handleProtocolURL, forwards any incoming URL starting with the protocol prefix to the renderer with no further validation:
exportfunctionhandleProtocolURL(mb: Menubar,url: string,protocol: string): void{if(url.startsWith(`${protocol}://`)){logInfo('main:handleUrl',`forwarding URL ${url} to renderer process`);sendRendererEvent(mb,EVENTS.AUTH_CALLBACK,url);}}
Custom protocol handlers are registered at the OS level and can be triggered from a webpage, an email client, or another local application, not only from Gitify's own OAuth popup.
Steps To Reproduce
(available upon request)
Impact
An attacker completes GitHub's OAuth authorize step for their own GitHub account using Gitify's public OAuth client ID, obtaining a valid authorization code. The attacker then gets that code delivered to a victim's running Gitify instance via a crafted gitify://oauth?code=<attacker's code>&type=oauth link. The victim's Gitify client accepts the code and exchanges it for an access token, silently authenticating the victim's client as the attacker's GitHub account instead of the victim's own, with no indication to the victim that the account identity has been swapped.
This is a login-CSRF / account-binding confusion bug, not theft of the victim's own credentials and not remote code execution. No secret belonging to the victim is exposed, but the victim's client ends up bound to and displaying data from an attacker-controlled account, which could support phishing or spoofed-notification scenarios, or mislead a victim into treating attacker-controlled content as their own.
A fix PR is attached: generates a per-attempt random state value, passes it through to the authorization URL, and requires the callback's state to match before treating a code as belonging to that login attempt.
Activity