Skip to content

Comments

feat(codex): implement session isolation for concurrent Codex requests (#430)#434

Merged
ding113 merged 2 commits intodevfrom
fix/issue-430-codex-session
Dec 24, 2025
Merged

feat(codex): implement session isolation for concurrent Codex requests (#430)#434
ding113 merged 2 commits intodevfrom
fix/issue-430-codex-session

Conversation

@ding113
Copy link
Owner

@ding113 ding113 commented Dec 24, 2025

Summary

  • Implement session isolation for concurrent Codex CLI requests from the same user
  • Extract session_id from request headers/body with priority-based extraction
  • Add security hardening with length and character validation

Changes

File Change
src/app/v1/_lib/codex/session-extractor.ts New: Session ID extraction with priority chain
src/app/v1/_lib/codex/__tests__/session-extractor.test.ts New: 11 unit tests
src/lib/session-manager.ts Modified: Extended extractClientSessionId() signature
src/app/v1/_lib/proxy/session-guard.ts Modified: Pass headers/userAgent to extraction
src/app/v1/_lib/converters/codex-to-claude/request.ts Modified: Preserve original session_id

Session ID Extraction Priority

  1. headers["session_id"]
  2. headers["x-session-id"]
  3. body.metadata.session_id
  4. body.previous_response_id (with codex_prev_ prefix)

Security Hardening

  • Min length: 21 characters
  • Max length: 256 characters
  • Character whitelist: /^[\w\-.:]+$/

Test plan

  • Typecheck passes
  • Lint passes
  • 11 unit tests pass (extraction, priority, edge cases, security)
  • Backward compatible: Claude/OpenAI format requests unaffected

Closes #430

Generated with Claude Code

#430)

Enable distinct session tracking for multiple concurrent Codex CLI sessions
from the same user by extracting session_id from request headers/body.

Changes:
- Add session-extractor.ts with priority-based session ID extraction
- Extend SessionManager.extractClientSessionId() to accept headers/userAgent
- Pass headers/userAgent from ProxySessionGuard to session extraction
- Preserve original session_id in Codex-to-Claude request transformation

Security hardening:
- Session ID length validation (21-256 chars)
- Character whitelist validation (alphanumeric, dash, dot, colon)

Backward compatible: Claude/OpenAI format requests unaffected.

Closes #430

Generated with [Claude Code](https://claude.ai/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.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 significantly enhances the handling of Codex CLI requests by introducing robust session isolation. It achieves this through a new, dedicated session ID extraction utility that prioritizes various request fields and enforces strict security validations on the extracted IDs. This ensures that each concurrent request from a Codex client is correctly associated with its unique session, improving the reliability and security of the service.

Highlights

  • Codex Session Isolation: Implemented a new mechanism to isolate sessions for concurrent Codex CLI requests from the same user.
  • Priority-Based Session ID Extraction: Introduced a new utility to extract 'session_id' from request headers ('session_id', 'x-session-id') and body ('metadata.session_id', 'previous_response_id') with a defined priority order.
  • Session ID Security Hardening: Added validation for extracted session IDs, including minimum/maximum length (21-256 characters) and a character whitelist ('/^[\w-.:]+$/').
  • Integration with Session Management: Updated the 'SessionManager' to utilize the new Codex session extraction logic, passing request headers and user agent for more accurate session identification.
  • Preservation of Original Session ID: Modified the Codex-to-Claude request converter to ensure the original 'session_id' from the request metadata is used when generating the 'user_id'.
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.

@github-actions
Copy link
Contributor

🧪 测试结果

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

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

@github-actions github-actions bot added the size/M Medium PR (< 500 lines) label Dec 24, 2025
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 introduces session isolation for concurrent Codex CLI requests by implementing a robust session ID extraction mechanism. The changes are well-structured, with new logic for session extraction, comprehensive unit tests, and appropriate security hardening. The integration into the existing session management flow is clean. I have one suggestion to improve consistency in session ID validation.

Comment on lines 120 to 123
const sessionIdRaw = originalMetadata?.session_id;
if (typeof sessionIdRaw === "string" && sessionIdRaw.trim()) {
return `codex_session_${sessionIdRaw.trim()}`;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For consistency and security, the session_id from metadata should be validated using the same logic as in session-extractor.ts. The current implementation only checks if it's a non-empty string, but misses the length and character validation performed by normalizeCodexSessionId.

I suggest reusing normalizeCodexSessionId here. This will require exporting it from src/app/v1/_lib/codex/session-extractor.ts.

Example of how to use it:

import { normalizeCodexSessionId } from "@/app/v1/_lib/codex/session-extractor";
// ... in generateUserID:
const sessionId = normalizeCodexSessionId(originalMetadata?.session_id);
if (sessionId) {
  return `codex_session_${sessionId}`;
}
Suggested change
const sessionIdRaw = originalMetadata?.session_id;
if (typeof sessionIdRaw === "string" && sessionIdRaw.trim()) {
return `codex_session_${sessionIdRaw.trim()}`;
}
const sessionId = normalizeCodexSessionId(originalMetadata?.session_id);
if (sessionId) {
return `codex_session_${sessionId}`;
}

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

This PR implements session isolation for concurrent Codex CLI requests by extracting stable session IDs from headers and request body. The implementation is clean, well-tested, and follows security best practices with input validation. No significant issues were identified.

PR Size: M

  • Lines changed: 273 (268 additions, 5 deletions)
  • Files changed: 5

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 0 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 0 0
Simplification 0 0 0 0

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean (proper input validation with length/character restrictions)
  • Error handling - Clean (graceful fallbacks when session extraction fails)
  • Type safety - Clean (proper null checks and type guards)
  • Documentation accuracy - Clean (JSDoc comments accurately describe behavior)
  • Test coverage - Adequate (11 unit tests covering extraction priority, security validation, edge cases)
  • Code clarity - Good (clear function names and structure)

Notes

Positive aspects observed (not reported as issues per instructions):

  • Security hardening with min/max length (21-256 chars) and character whitelist prevents Redis key bloat attacks
  • Priority-based extraction chain is well-documented and logical
  • Tests cover all extraction sources and validation edge cases
  • Backward compatible with existing Claude/OpenAI format requests

Automated review by Claude 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.

Code Review Summary

This PR implements session isolation for concurrent Codex CLI requests by extracting stable session IDs from headers and request body. The implementation is clean, well-tested, and follows security best practices with input validation. No significant issues were identified.

PR Size: M

  • Lines changed: 273 (268 additions, 5 deletions)
  • Files changed: 5

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 0 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 0 0
Simplification 0 0 0 0

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean (proper input validation with length/character restrictions)
  • Error handling - Clean (graceful fallbacks when session extraction fails)
  • Type safety - Clean (proper null checks and type guards)
  • Documentation accuracy - Clean (JSDoc comments accurately describe behavior)
  • Test coverage - Adequate (11 unit tests covering extraction priority, security validation, edge cases)
  • Code clarity - Good (clear function names and structure)

Automated review by Claude AI

userAgent?: string | null
): string | null {
// Codex 请求:优先尝试从 headers/body 提取稳定的 session_id
if (headers && Array.isArray(requestMessage.input)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Critical [SECURITY-VULNERABILITY] Codex session_id validation can be bypassed via fallback

Why this is a problem: At src/lib/session-manager.ts:92, extractCodexSessionId(...) rejects too-short/too-long/invalid-character IDs, but this block falls through when result.sessionId is null and the function can later return metadata.user_id/metadata.session_id without those validations. A crafted metadata.session_id (e.g. extremely long or containing disallowed characters) would then be used as a Redis key component via getOrCreateSessionId(...), defeating the security hardening intent.

Suggested fix:

// Codex/Responses API request: only accept validated session IDs.
// If extraction fails, return null so SessionGuard falls back to deterministic session IDs.
if (headers && Array.isArray(requestMessage.input)) {
  const result = extractCodexSessionId(headers, requestMessage, userAgent ?? null);
  if (result.sessionId) {
    logger.trace("SessionManager: Extracted session from Codex request", {
      sessionId: result.sessionId,
      source: result.source,
      isCodexClient: result.isCodexClient,
    });
    return result.sessionId;
  }

  return null;
}

const prevResponseId = normalizeCodexSessionId(requestBody.previous_response_id);
if (prevResponseId) {
return {
sessionId: `codex_prev_${prevResponseId}`,
Copy link
Contributor

Choose a reason for hiding this comment

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

Medium [LOGIC-BUG] codex_prev_ prefix can violate CODEX_SESSION_ID_MAX_LENGTH

Why this is a problem: normalizeCodexSessionId(...) enforces CODEX_SESSION_ID_MAX_LENGTH = 256 (src/app/v1/_lib/codex/session-extractor.ts:18) on previous_response_id, but sessionId: codex_prev_${prevResponseId}`` (src/app/v1/_lib/codex/session-extractor.ts:102) can be up to 267 chars. This undermines the stated “Prevent Redis key bloat from malicious input” constraint.

Suggested fix:

const PREV_PREFIX = "codex_prev_";

const prevResponseId = normalizeCodexSessionId(requestBody.previous_response_id);
if (prevResponseId) {
  const sessionId = `${PREV_PREFIX}${prevResponseId}`;
  if (sessionId.length <= CODEX_SESSION_ID_MAX_LENGTH) {
    return {
      sessionId,
      source: "body_previous_response_id",
      isCodexClient: officialClient,
    };
  }
}

Suggested test:

test("rejects previous_response_id that would exceed 256 after prefix", () => {
  const prev = "a".repeat(256);
  const result = extractCodexSessionId(new Headers(), { previous_response_id: prev }, null);
  expect(result.sessionId).toBe(null);
});

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

This PR introduces Codex session ID extraction and wires it into session allocation. The main risk remaining is that invalid/overlong session IDs can still become clientSessionId via fallback paths and derived IDs can exceed the stated 256 char ceiling, which can bloat Redis keys and defeat the intended hardening.

PR Size: M

  • Lines changed: 273
  • Files changed: 5

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 1 0
Security 1 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 0 0
Simplification 0 0 0 0

Critical Issues (Must Fix)

  • src/lib/session-manager.ts:92 — Codex session_id validation can be bypassed via metadata fallback (Confidence: 95)

High Priority Issues (Should Fix)

  • src/app/v1/_lib/codex/session-extractor.ts:102codex_prev_ prefix can exceed CODEX_SESSION_ID_MAX_LENGTH (Confidence: 85)

Review Coverage

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

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.

  • PR #434: applied label size/M (273 lines changed, 5 files).
  • Posted inline review comments on:
    • src/lib/session-manager.ts:92Critical [SECURITY-VULNERABILITY] Codex session_id validation bypass via fallback
    • src/app/v1/_lib/codex/session-extractor.ts:102Medium [LOGIC-BUG] codex_prev_ prefix can exceed CODEX_SESSION_ID_MAX_LENGTH
  • Submitted the required ## Code Review Summary review comment to PR #434.

- Export normalizeCodexSessionId for unified validation
- Add prefix length check to prevent sessionId > 256 chars
- Block Codex request fallback to unvalidated metadata
- Add boundary value tests (21 and 256 chars)

Fixes:
- Critical: session_id validation bypass via metadata fallback
- Medium: codex_prev_ prefix could exceed 256 char limit
- Medium: generateUserID lacked unified validation

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ding113 ding113 merged commit 7fa5c7e into dev Dec 24, 2025
7 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in Claude Code Hub Roadmap Dec 24, 2025
@github-actions
Copy link
Contributor

🧪 测试结果

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

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

@ding113 ding113 deleted the fix/issue-430-codex-session branch December 30, 2025 17:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core area:session enhancement New feature or request size/M Medium PR (< 500 lines)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant