Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/services/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type Required<T, K extends keyof T> = T & {
export interface AppUser extends User {
handle?: string
}
let userHandle: string | undefined = undefined
let userHandle: string | undefined

Comment on lines +21 to 22
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Global userHandle cache risks cross-user data leakage

The removal of the redundant = undefined assignment is fine, but the underlying design—keeping mutable auth-specific state in a module-level variable that survives across requests—remains risky. In SSR or edge-runtime scenarios a stale userHandle could bleed between different users served by the same process/thread.

Consider:

  • Storing the handle in React/Remix context or per-request state rather than a file-scope variable.
  • At minimum, keying the cache by auth.currentUser.uid (Map) instead of a single shared string.

🏁 Script executed:

#!/bin/bash
set -e

# Locate the module‐scope declaration in auth.ts
rg -n "let userHandle" app/services/auth.ts

# List all references to userHandle across the codebase
rg -n "userHandle" .

Length of output: 418


Avoid module‐level userHandle cache to prevent cross‐request data leakage

Keeping a mutable userHandle in the module scope means that once one user’s handle is populated, subsequent requests—especially under SSR or edge runtimes—may see or overwrite that value, risking cross‐user data bleed.

Locations to address in app/services/auth.ts:
• Line 21:

let userHandle: string | undefined

• Line 41 (reset) and Lines 67–72 (read/set)

Recommended fixes:

  • Move per‐user state into request‐scoped context (e.g. React/Remix loader context).
  • If you must cache at the module level, switch to a Map<string, string> keyed by a unique ID (e.g. auth.currentUser.uid) so entries can’t collide.
🤖 Prompt for AI Agents
In app/services/auth.ts around lines 21 to 22, avoid using a module-level
mutable variable userHandle to prevent cross-request data leakage. Instead,
refactor the code to store userHandle in a request-scoped context such as React
or Remix loader context. If caching at the module level is necessary, replace
the single userHandle variable with a Map keyed by a unique user identifier
(e.g., auth.currentUser.uid) to isolate user data and prevent collisions. Also
update related code at lines 41 and 67-72 to use this new approach.

export const AuthContext = createContext<AppUser | null>(null)
AuthContext.displayName = 'AuthContext'
Expand Down
39 changes: 23 additions & 16 deletions biome.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"organizeImports": {
"enabled": true
},
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
},
"ignore": ["build"]
}
"$schema": "https://biomejs.dev/schemas/2.1.3/schema.json",
"assist": { "actions": { "source": { "organizeImports": "on" } } },
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
"noUnusedVariables": {
"level": "warn",
"options": {
"ignoreRestSiblings": true
}
}
}
},
"includes": ["**", "!**/build"]

}
}
50 changes: 25 additions & 25 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,52 +15,52 @@
"start": "npx sirv-cli build/client/ --single"
},
"dependencies": {
"@conform-to/react": "^1.7.0",
"@conform-to/zod": "^1.7.0",
"@react-router/node": "7.6.2",
"@tailwindcss/vite": "^4.1.10",
"@conform-to/react": "^1.8.2",
"@conform-to/zod": "^1.8.2",
"@react-router/node": "7.7.1",
"@tailwindcss/vite": "^4.1.11",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"dayjs": "^1.11.13",
"firebase": "^11.9.1",
"isbot": "^5.1.28",
"lucide-react": "^0.515.0",
"marked": "^15.0.12",
"firebase": "^12.0.0",
"isbot": "^5.1.29",
"lucide-react": "^0.534.0",
"marked": "^16.1.1",
"next-themes": "^0.4.6",
"pure-uuid": "^1.8.1",
"radix-ui": "latest",
"react": "19.1.0",
"react-dom": "19.1.0",
"react": "19.1.1",
"react-dom": "19.1.1",
"react-markdown": "^10.1.0",
"react-router": "7.6.2",
"react-router-dom": "7.6.2",
"react-twc": "^1.4.2",
"react-router": "7.7.1",
"react-router-dom": "7.7.1",
"react-twc": "^1.5.1",
"remix-flat-routes": "^0.8.5",
"sonner": "^2.0.5",
"sonner": "^2.0.6",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.25.64",
"zodix": "^0.4.4"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@biomejs/biome": "^2.1.3",
"@mdx-js/rollup": "^3.1.0",
"@react-router/dev": "7.6.2",
"@react-router/remix-routes-option-adapter": "^7.6.2",
"@react-router/dev": "7.7.1",
"@react-router/remix-routes-option-adapter": "^7.7.1",
"@tailwindcss/typography": "^0.5.16",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"firebase-tools": "^14.7.0",
"@types/react": "^19.1.9",
"@types/react-dom": "^19.1.7",
"firebase-tools": "^14.11.1",
"npm-run-all": "^4.1.5",
"prettier": "^3.5.3",
"prettier-plugin-organize-imports": "^4.1.0",
"prettier-plugin-tailwindcss": "^0.6.12",
"prettier": "^3.6.2",
"prettier-plugin-organize-imports": "^4.2.0",
"prettier-plugin-tailwindcss": "^0.6.14",
"remark-frontmatter": "^5.0.0",
"remark-mdx-frontmatter": "^5.2.0",
"rollup-plugin-visualizer": "^6.0.3",
"tailwindcss": "^4.1.10",
"tailwindcss": "^4.1.11",
"typescript": "^5.8.3",
"vite": "^6.3.5",
"vite": "^7.0.6",
"vite-tsconfig-paths": "^5.1.4"
},
"engines": {
Expand Down
Loading