Skip to content

Security: Chat History and responseId Stored Unencrypted in localStorage #1071

@BenjaminMichaelis

Description

@BenjaminMichaelis

Summary

The chat widget stores the full conversation history (up to 100 messages) and the last OpenAI responseId in localStorage as plaintext JSON. This persists sensitive AI conversation data accessible to any JavaScript on the same origin — including third-party scripts, browser extensions, and XSS payloads.

Affected Code

EssentialCSharp.Web/wwwroot/js/chat-module.js:

const data = {
    messages: messagesToSave,           // up to 100 messages, full content
    lastResponseId: lastResponseId.value,  // OpenAI response ID (enables conversation replay)
    timestamp: Date.now()
};
localStorage.setItem('aiChatHistory', JSON.stringify(data));

Risk

OWASP AI Agent Security - §8 Data Protection & Privacy

  1. The lastResponseId in localStorage is security-sensitive — as noted in issue Security: Client-Supplied previousResponseId Not Bound to Authenticated User — Cross-User Conversation Access #1070, this ID can be used by any authenticated user to continue another user's conversation. Storing it in localStorage exposes it to XSS and browser extension theft.
  2. Conversation history may contain sensitive content that sits unencrypted on disk indefinitely.
  3. No expiry enforcement — the timestamp field is stored but never used to expire old data.
  4. On shared machines, any user of the browser can read prior conversations.

Recommended Mitigations

  1. Do not store lastResponseId in localStorage — store it server-side in the user's session (see Security: Client-Supplied previousResponseId Not Bound to Authenticated User — Cross-User Conversation Access #1070). Remove it from the persisted payload entirely.
  2. Use sessionStorage instead of localStorage — clears on tab close, reducing persistent exposure.
  3. Enforce the stored timestamp as a TTL:
    const MAX_HISTORY_AGE_MS = 24 * 60 * 60 * 1000;
    if (Date.now() - data.timestamp > MAX_HISTORY_AGE_MS) {
        localStorage.removeItem('aiChatHistory');
        return;
    }
  4. Add a "Clear chat history" button in the UI so users can explicitly remove stored data.

References

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions