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
A previously merged security fix — moving the JWT session token out of localStorage into HttpOnly cookies (PR #235, closing High-severity issue #11) — was silently reverted by an unrelated merge-conflict "repair main" commit one day later. The raw JWT has been readable from localStorage on every commit since, and issue #11 still reads as closed/fixed.
Background
PR #235 (merged, closing issue #11 "[High] JWT stored in localStorage and leaked in OAuth redirect URL") replaced ApiService.setToken with a no-op and fully removed localStorage token handling. Commit ae2453d8 ("fix: repair main after bad merge (99e3e92) broke the Rust build and CI", PR #236) — while fixing an unrelated CI/build break the next day — clobbered api.ts back to its pre-#235 state, silently reintroducing full localStorage read/write of the raw JWT. No new issue was ever filed for the regression, and #11 remains closed as if the fix still stands.
Evidence
src/services/api.ts:511-518 — ApiService.token initializer reads directly from localStorage.getItem('txio_token').
src/services/api.ts:520-537 — setToken() writes/removes localStorage['txio_token'] on every call.
src/services/api.ts:688, :715 — both login() and register() (the primary email/password path, not just OAuth) call this.setToken(data.token).
src/features/SignInPage.tsx:62,74,128,130,144,146 — reads/writes localStorage for 'txio_token' directly, and the OAuth callback handling (SignInPage.tsx:19-77) feeds the fragment token straight into localStorage.
git blame -L 505,536 src/services/api.ts attributes all of it to commit ae2453d8; gh pr diff 235 confirms the pre-ae2453d8 state had setToken as a no-op with all localStorage calls removed.
git merge-base --is-ancestor ae2453d8 HEAD succeeds — this is on current main, not an abandoned branch.
Impact: every logged-in user's session token is readable by any script running in the page context — a future XSS, a malicious browser extension, or a compromised dependency in the large multi-chain wallet dependency tree. This is exactly the "High" severity scenario the project already scored and fixed once. Anyone auditing via GitHub issue state alone would conclude this is resolved, since #11's closing comment says "Fixed in commit(s) on branch test-191."
Proposed Solution
Re-apply the intent of PR #235: remove localStorage token storage entirely, restore ApiService.setToken to a no-op (or align with whatever the backend currently issues — confirm the backend still sets the HttpOnly cookie post-#236 revert, since the same "repair main" commit may have touched backend code too). Update SignInPage.tsx's OAuth/login/logout paths accordingly. Add a lightweight regression check — a grep-based CI lint or a unit test asserting ApiService never touches localStorage for the token key — so a future merge-conflict resolution can't silently reintroduce this again.
OAuth redirect flow specifically (the original vulnerability's exact vector — token appearing in a URL fragment)
Logout must clear the cookie server-side, not just stop reading a local value
Any other code path (besides api.ts/SignInPage.tsx) that might independently read txio_token from localStorage — worth a full-repo grep before closing
Risks
If the backend's HttpOnly cookie issuance was also affected by the same "repair main" commit, this fix needs to land alongside a backend verification/fix, not frontend-only
Regression risk is exactly what happened before (a future merge-conflict resolution reintroducing this) — the CI/test guard in the acceptance criteria exists specifically to prevent a third occurrence
Critical — a previously-fixed, maintainer-acknowledged High-severity session-theft vulnerability is currently live on main and invisible to anyone trusting GitHub issue state.
AI Rationale: A confirmed, git-blame-traced silent regression of a previously fixed High-severity vulnerability, currently live on main and masked by stale issue state. The fix is small and well-scoped — PR #235's diff is a direct reference for what "done" looks like — making this an unusually high-confidence, high-impact, low-difficulty finding.
Summary
A previously merged security fix — moving the JWT session token out of
localStorageinto HttpOnly cookies (PR #235, closing High-severity issue #11) — was silently reverted by an unrelated merge-conflict "repair main" commit one day later. The raw JWT has been readable fromlocalStorageon every commit since, and issue #11 still reads as closed/fixed.Background
PR #235 (merged, closing issue #11 "[High] JWT stored in localStorage and leaked in OAuth redirect URL") replaced
ApiService.setTokenwith a no-op and fully removedlocalStoragetoken handling. Commitae2453d8("fix: repair main after bad merge (99e3e92) broke the Rust build and CI", PR #236) — while fixing an unrelated CI/build break the next day — clobberedapi.tsback to its pre-#235 state, silently reintroducing fulllocalStorageread/write of the raw JWT. No new issue was ever filed for the regression, and #11 remains closed as if the fix still stands.Evidence
src/services/api.ts:511-518—ApiService.tokeninitializer reads directly fromlocalStorage.getItem('txio_token').src/services/api.ts:520-537—setToken()writes/removeslocalStorage['txio_token']on every call.src/services/api.ts:688,:715— bothlogin()andregister()(the primary email/password path, not just OAuth) callthis.setToken(data.token).src/features/SignInPage.tsx:62,74,128,130,144,146— reads/writeslocalStoragefor'txio_token'directly, and the OAuth callback handling (SignInPage.tsx:19-77) feeds the fragment token straight intolocalStorage.git blame -L 505,536 src/services/api.tsattributes all of it to commitae2453d8;gh pr diff 235confirms the pre-ae2453d8state hadsetTokenas a no-op with alllocalStoragecalls removed.git merge-base --is-ancestor ae2453d8 HEADsucceeds — this is on currentmain, not an abandoned branch.Impact: every logged-in user's session token is readable by any script running in the page context — a future XSS, a malicious browser extension, or a compromised dependency in the large multi-chain wallet dependency tree. This is exactly the "High" severity scenario the project already scored and fixed once. Anyone auditing via GitHub issue state alone would conclude this is resolved, since #11's closing comment says "Fixed in commit(s) on branch test-191."
Proposed Solution
Re-apply the intent of PR #235: remove
localStoragetoken storage entirely, restoreApiService.setTokento a no-op (or align with whatever the backend currently issues — confirm the backend still sets the HttpOnly cookie post-#236 revert, since the same "repair main" commit may have touched backend code too). UpdateSignInPage.tsx's OAuth/login/logout paths accordingly. Add a lightweight regression check — a grep-based CI lint or a unit test assertingApiServicenever toucheslocalStoragefor the token key — so a future merge-conflict resolution can't silently reintroduce this again.Technical Scope
src/services/api.ts—ApiService.token,setToken,login,registersrc/features/SignInPage.tsx— OAuth callback handling, login/logout pathsTxio-labs/txio-backendstill issues the HttpOnly cookie as PR Fix 13 unassigned issues: security, CI/CD, and UI improvements #235 expected)Acceptance Criteria
localStorageunder thetxio_tokenkeylocalStorage+ token-key usage is reintroduced inapi.tsorSignInPage.tsxEdge Cases
api.ts/SignInPage.tsx) that might independently readtxio_tokenfromlocalStorage— worth a full-repo grep before closingRisks
Deliverables
localStoragetoken handlingPriority
Critical — a previously-fixed, maintainer-acknowledged High-severity session-theft vulnerability is currently live on
mainand invisible to anyone trusting GitHub issue state.GrantFox Evaluation
Impact Score: 90/100
Difficulty Score: 25/100
Priority Score: 85.5
Confidence: 95%
Category: Security
Estimated Reward Tier: A
AI Rationale: A confirmed, git-blame-traced silent regression of a previously fixed High-severity vulnerability, currently live on
mainand masked by stale issue state. The fix is small and well-scoped — PR #235's diff is a direct reference for what "done" looks like — making this an unusually high-confidence, high-impact, low-difficulty finding.Estimated Completion: 96 hours
Telegram: https://t.me/txioCommunity