[security] vault_get returns plaintext passwords into LLM context #677

Closed
opened 2026-06-02 23:41:53 +02:00 by sleepy · 1 comment
Owner

Security: vault_get returns plaintext passwords to LLM context

File: src/tool_implementations.py lines 3948-4003

The do_vault_get() function retrieves passwords from Bitwarden and returns them in the tool result, which then gets fed into the LLM context:

output = [
    f"Vault item: {name}",
    f"Username: {login.get('username', '(none)')}",
    f"Password: {login.get('password', '(none)')}",
]
if login.get("totp"):
    output.append(f"TOTP secret: {login['totp']}")

Issues

  • Passwords enter the LLM context window — they become part of the conversation stored in the database and potentially sent to external API endpoints (OpenAI, Anthropic, etc.)
  • TOTP secrets are also returned in plaintext
  • Context persistence — the full conversation including passwords is stored in the session database
  • While there is an audit log entry, the password itself is in the LLM context

Mitigations already present

  • reason parameter required (forces justification)
  • Audit log entry
  • Vault must be unlocked first
  • Tool is admin-only (via NON_ADMIN_BLOCKED_TOOLS)

Suggested fix

  • Return passwords only in a dedicated SSE event type that the frontend renders in a masked field — never in the LLM's text context
  • Or provide a "copy to clipboard" mechanism that bypasses the LLM entirely
  • At minimum, strip the password from the tool result before it goes into format_tool_result() and is appended to the message history
## Security: vault_get returns plaintext passwords to LLM context ### File: `src/tool_implementations.py` lines 3948-4003 The `do_vault_get()` function retrieves passwords from Bitwarden and returns them in the tool result, which then gets fed into the LLM context: ```python output = [ f"Vault item: {name}", f"Username: {login.get('username', '(none)')}", f"Password: {login.get('password', '(none)')}", ] if login.get("totp"): output.append(f"TOTP secret: {login['totp']}") ``` ### Issues - **Passwords enter the LLM context window** — they become part of the conversation stored in the database and potentially sent to external API endpoints (OpenAI, Anthropic, etc.) - **TOTP secrets** are also returned in plaintext - **Context persistence** — the full conversation including passwords is stored in the session database - While there is an audit log entry, the password itself is in the LLM context ### Mitigations already present - `reason` parameter required (forces justification) - Audit log entry - Vault must be unlocked first - Tool is admin-only (via `NON_ADMIN_BLOCKED_TOOLS`) ### Suggested fix - Return passwords only in a dedicated SSE event type that the frontend renders in a masked field — never in the LLM's text context - Or provide a "copy to clipboard" mechanism that bypasses the LLM entirely - At minimum, strip the password from the tool result before it goes into `format_tool_result()` and is appended to the message history
Author
Owner

Fixed via PR #891 — vault secrets now masked by default in LLM context. Added reveal=true parameter with warning logging.

Fixed via PR #891 — vault secrets now masked by default in LLM context. Added reveal=true parameter with warning logging.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sleepy/odysseus#677
No description provided.