Skip to content

fix(proxy): remove deterministic session ID to prevent collision across conversations#793

Merged
ding113 merged 1 commit intodevfrom
fix/deterministic-session-id-collision
Feb 15, 2026
Merged

fix(proxy): remove deterministic session ID to prevent collision across conversations#793
ding113 merged 1 commit intodevfrom
fix/deterministic-session-id-collision

Conversation

@ding113
Copy link
Owner

@ding113 ding113 commented Feb 15, 2026

Problem

generateDeterministicSessionId() hashes (User-Agent, IP, API Key prefix) with no time dimension, producing identical session IDs for the same user across separate conversations hours apart.

Impact

  • Usage logs merge unrelated conversations into one session
  • Dashboard session duration spans hours (actually multiple short chats)
  • ZSET tracking entries get "revived", inflating active session counts
  • Concurrent session limits bypassed (same ID = same session)

Root Cause

session-guard.ts falls back to generateDeterministicSessionId() when extractClientSessionId() returns null. Since the hash inputs are static per-user, the same ID is generated every time.

Fix

Remove generateDeterministicSessionId() entirely. The existing fallback in getOrCreateSessionId() already handles clientSessionId = null correctly:

  1. Content hash (first 3 messages SHA-256) - provides session continuity for multi-turn conversations
  2. Random generateSessionId() - ensures unique IDs for new conversations

Changes

  • session-guard.ts: Remove || session.generateDeterministicSessionId() fallback
  • session.ts: Delete generateDeterministicSessionId() method + unused crypto import
  • Tests: Remove related test block and mock

Greptile Summary

This PR removes the deterministic session ID generation mechanism that was causing session ID collisions across unrelated conversations. The generateDeterministicSessionId() method hashed static per-user attributes (User-Agent, IP, API Key prefix) without any time dimension, producing identical session IDs for the same user across separate conversations.

Key changes:

  • Removed fallback to generateDeterministicSessionId() in session-guard.ts:88-92
  • Deleted the 38-line generateDeterministicSessionId() method from session.ts:352-384
  • Removed unused crypto import from session.ts:1
  • Cleaned up related test code in both test files

Impact: The existing fallback logic in SessionManager.getOrCreateSessionId() already handles null client session IDs correctly by using content hash (for multi-turn conversations) or random session ID generation (for new conversations). This fix resolves issues with usage log merging, inflated session durations, ZSET entry revival, and concurrent session limit bypasses.

Confidence Score: 5/5

  • This PR is safe to merge with no risks
  • The change correctly removes a problematic deterministic session ID generation mechanism. The existing fallback logic in SessionManager.getOrCreateSessionId() already handles null client session IDs through content hash or random ID generation. All code paths are properly handled, tests are cleaned up, and the fix directly addresses the reported collision issues.
  • No files require special attention

Important Files Changed

Filename Overview
src/app/v1/_lib/proxy/session-guard.ts Removed fallback to generateDeterministicSessionId(), now passes null directly to getOrCreateSessionId()
src/app/v1/_lib/proxy/session.ts Deleted generateDeterministicSessionId() method and unused crypto import
tests/unit/proxy/metadata-injection.test.ts Removed test block for deleted generateDeterministicSessionId() method
tests/unit/proxy/session-guard-warmup-intercept.test.ts Removed mock implementation of deleted generateDeterministicSessionId() from test fixtures

Flowchart

flowchart TD
    Start[Request arrives at ProxySessionGuard] --> Extract[Extract client session ID<br/>from metadata/headers]
    Extract --> HasClient{Client session ID<br/>exists?}
    
    HasClient -->|Yes| UseClient[Use client-provided<br/>session ID]
    HasClient -->|No| ContentHash[Calculate content hash<br/>from first 3 messages]
    
    ContentHash --> HashExists{Hash calculated<br/>successfully?}
    HashExists -->|Yes| LookupHash[Lookup existing session<br/>in Redis by hash]
    HashExists -->|No| GenNew1[Generate new random<br/>session ID]
    
    LookupHash --> Found{Session found<br/>in Redis?}
    Found -->|Yes| Reuse[Reuse existing<br/>session ID]
    Found -->|No| GenNew2[Generate new random<br/>session ID]
    
    UseClient --> End[Session ID assigned]
    Reuse --> End
    GenNew1 --> End
    GenNew2 --> End
    
    style Start fill:#e1f5ff
    style End fill:#d4edda
    style Extract fill:#fff3cd
    style ContentHash fill:#fff3cd
    style GenNew1 fill:#f8d7da
    style GenNew2 fill:#f8d7da
Loading

Last reviewed commit: 94a409b

…ss conversations

generateDeterministicSessionId() hashes (UA, IP, API key prefix) with no time
dimension, producing identical session IDs for the same user hours apart. This
merges unrelated conversations into one session, polluting usage logs, session
tracking, and concurrent session limits.

The existing fallback in getOrCreateSessionId() (content hash -> random ID)
already provides correct session continuity without collision risk.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @ding113, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical issue where deterministic session IDs were causing collisions and data inaccuracies across user conversations. By completely removing the generateDeterministicSessionId() method and its fallback usage, the system now correctly assigns unique session identifiers, preventing usage logs from merging unrelated conversations and ensuring accurate session tracking. The change simplifies the session management logic by relying on existing, more appropriate methods for generating session IDs.

Highlights

  • Problematic Deterministic Session ID Removal: The generateDeterministicSessionId() method, which created session IDs based on static user attributes (User-Agent, IP, API Key prefix) without a time dimension, has been entirely removed. This method caused identical session IDs for the same user across different conversations, leading to significant data integrity issues.
  • Impact Mitigation: The previous deterministic session ID generation led to merged usage logs, inflated session durations, incorrect active session counts, and bypassed concurrent session limits. Removing it resolves these issues by ensuring unique session identification.
  • Reliance on Existing Session ID Generation: The system now exclusively relies on the existing robust fallback mechanisms for session ID generation: content hashing (for multi-turn conversations) and random ID generation (for new conversations), which correctly handle cases where a client session ID is not provided.
  • Code Cleanup: Associated code, including the crypto import in session.ts and all related test blocks and mocks for generateDeterministicSessionId, has been removed, streamlining the codebase.
Changelog
  • src/app/v1/_lib/proxy/session-guard.ts
    • Removed the fallback to session.generateDeterministicSessionId() when extracting the client session ID.
  • src/app/v1/_lib/proxy/session.ts
    • Deleted the generateDeterministicSessionId() method.
    • Removed the unused crypto import.
  • tests/unit/proxy/metadata-injection.test.ts
    • Removed the test suite for ProxySession.generateDeterministicSessionId.
  • tests/unit/proxy/session-guard-warmup-intercept.test.ts
    • Removed the mock implementation of generateDeterministicSessionId() from the createMockSession utility.
Activity
  • No human activity (comments, reviews) has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Feb 15, 2026

📝 Walkthrough

演练

此拉取请求移除了确定性会话 ID 生成逻辑。该更改删除了 generateDeterministicSessionId 方法及其实现,调整会话守卫以允许未定义的客户端会话 ID 传播,并更新相关测试。

更改

队列 / 文件 摘要
核心实现
src/app/v1/_lib/proxy/session-guard.ts, src/app/v1/_lib/proxy/session.ts
移除确定性会话 ID 生成逻辑。删除 generateDeterministicSessionId 方法、node:crypto 导入和相关哈希逻辑。调整会话守卫移除客户端会话 ID 未定义时的后备生成逻辑。
测试更新
tests/unit/proxy/metadata-injection.test.ts, tests/unit/proxy/session-guard-warmup-intercept.test.ts
删除 generateDeterministicSessionId 相关测试套件和模拟对象中的方法声明。

估计代码审查工作量

🎯 2 (简单) | ⏱️ ~10 分钟

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 标题清晰准确地总结了主要变更:删除确定性会话ID生成以防止跨对话碰撞,与代码改动完全相关。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into dev
Description check ✅ Passed Pull request description clearly explains the problem (deterministic session ID collisions), root cause, impact, and solution with specific code changes.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/deterministic-session-id-collision

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.

@github-actions github-actions bot added the size/S Small PR (< 200 lines) label Feb 15, 2026
@github-actions
Copy link
Contributor

🧪 测试结果

测试类型 状态
代码质量
单元测试
集成测试
API 测试

总体结果: ✅ 所有测试通过

@github-actions github-actions bot added bug Something isn't working area:session labels Feb 15, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request successfully addresses the session collision issue by removing the generateDeterministicSessionId method and its usage as a fallback in ProxySessionGuard. While this resolves the original problem by relying on the message content hash or random ID generation via SessionManager.getOrCreateSessionId for unique session identifiers, the new implementation introduces a critical security vulnerability. It relies on a flawed fallback mechanism and unvalidated client-provided session IDs, which could lead to session hijacking and cross-user session collisions. Specifically, the content-based hash fallback is global and does not account for the authenticated user or API key, and user-provided session IDs are trusted without verification. To mitigate these risks, session identifiers should be namespaced with the API key ID.

@ding113 ding113 merged commit f6a0b47 into dev Feb 15, 2026
17 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in Claude Code Hub Roadmap Feb 15, 2026
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Code Review Summary

No significant issues identified in this PR.

PR Size: S

  • Lines changed: 62
  • Files changed: 4

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean
  • Error handling - Clean
  • Type safety - Clean
  • Documentation accuracy - Clean
  • Test coverage - Adequate
  • Code clarity - Good

Automated review by Codex AI

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Submitted PR review for #793 and applied label size/S.

Code Review Summary

No significant issues identified in this PR.

PR Size: S

  • Lines changed: 62
  • Files changed: 4

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean
  • Error handling - Clean
  • Type safety - Clean
  • Documentation accuracy - Clean
  • Test coverage - Adequate
  • Code clarity - Good

Automated review by Codex AI

@github-actions github-actions bot mentioned this pull request Feb 15, 2026
ding113 added a commit that referenced this pull request Feb 15, 2026
* fix(proxy): extract model from Gemini Vertex AI publishers path for correct billing

When Gemini requests use the Vertex AI URL format
/v1/publishers/google/models/{model}:generateContent, the system
failed to extract the model name, falling back to a hardcoded
"gemini-2.5-flash" default and causing incorrect billing.

Add publishers path regex to extractModelFromPath() and
detectFormatByEndpoint() to handle this URL pattern.

* fix(proxy): correct Host header to match actual request target in standard path

buildHeaders() derives Host from provider.url, but the actual fetch target
(proxyUrl) may use a different host when activeEndpoint.baseUrl differs or
MCP passthrough overrides the base URL. This causes undici TLS certificate
validation failures. After proxyUrl is computed, re-derive Host from it.

* perf(logs): hide stats summary panel when no filters are active

Skip rendering UsageLogsStatsPanel and its aggregation query when all
filter conditions are empty, preventing full-table scans that cause
CPU overload.

* fix(proxy): remove deterministic session ID to prevent collision across conversations (#793)

generateDeterministicSessionId() hashes (UA, IP, API key prefix) with no time
dimension, producing identical session IDs for the same user hours apart. This
merges unrelated conversations into one session, polluting usage logs, session
tracking, and concurrent session limits.

The existing fallback in getOrCreateSessionId() (content hash -> random ID)
already provides correct session continuity without collision risk.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* perf(logs): hide stats panel in virtualized view when no filters active

Apply the same hasStatsFilters guard from the old view to the
virtualized logs view, preventing an unconditional full-table
aggregation query on page load. Also remove the unused legacy
usage-logs-view.tsx which is no longer imported anywhere.

* fix(my-usage): UX improvements for quota and statistics cards (#794)

* style(my-usage): use Badge for provider group values

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(my-usage): use currency symbol instead of code in quota cards

Replace manual `${currency} ${num.toFixed(2)}` formatting with
`formatCurrency()` so quota values display "$3.50" instead of "USD 3.50",
consistent with all other currency displays in the app.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style(my-usage): replace unlimited text with infinity icon in quota cards

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(my-usage): paginate model breakdown in statistics summary card

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(my-usage): suppress biome exhaustive-deps for intentional stats reset

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(my-usage): address PR #794 review comments

- Fix abbreviateModel/abbreviateClient crash on empty split parts
- Fix pagination reset on auto-refresh by using dateRange deps
- Restore noData fallback in model breakdown columns
- Add i18n for pagination controls with aria-labels (5 langs)
- Fix quota label overflow for long translations (w-8 -> w-auto)
- Rename Infinity -> InfinityIcon to avoid shadowing global
- Remove redundant span wrappers in TooltipTrigger asChild

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: John Doe <johndoe@example.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: miraserver <20286838+miraserver@users.noreply.github.com>
Co-authored-by: John Doe <johndoe@example.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:session bug Something isn't working size/S Small PR (< 200 lines)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant