AUSTA | Adversarial Intelligence

Security Engineering

KV Leak Channels: What Your Agent State Store Reveals

Behind every LLM agent there is a KV layer holding session state, conversation IDs, partial outputs, and tool-call traces. It is plumbing the security review almost never asks about. Four leak channels worth pentesting.

By Austa · Published · ~6 min read

The state behind every agent

An LLM agent is not really stateless. The user sees a chat-shaped interface. Underneath, the runtime keeps a lot of moving pieces in a fast KV store:

Most teams use a generic KV store for this layer (Redis, DynamoDB, or a managed equivalent like basekv when they want simpler ops). The choice rarely matters for security. What matters is whether the layer is treated as an attack surface or as invisible plumbing.

The realistic threat model: the application enforces auth on every API endpoint. The KV driver does not enforce anything. An attacker who finds a single bug, a leaked debug endpoint, or a buggy admin route gets primitives like "check if key X exists" or "list keys starting with Y." Those primitives are enough to leak per-user state without ever reading any record's contents.

Leak channel #1: conversation-ID enumeration

If conversation IDs are predictable (sequential, timestamp-based, short random IDs with low entropy), an attacker who knows the format can enumerate which IDs exist. They do not need to read the content. The existence signal alone leaks:

What to test: capture a real conversation ID from your own session. Examine the format. Probe nearby IDs with a read request. Does the response distinguish "exists but forbidden" from "does not exist"? If yes, you have an existence oracle.

Mitigation that actually works

Use 128-bit random IDs that an attacker cannot guess. Return identical error codes for "missing" and "unauthorized." Apply the check inside the KV driver layer, not only at the HTTP layer where bug-prone middleware lives.

Leak channel #2: TTL inference

An agent action sets a KV entry when it begins and clears it when it finishes. The TTL is whatever the action expects to take. The existence-of-key check from channel #1 becomes a timing oracle.

An attacker who can poll for the existence of an action key learns:

What to test: trigger a known long-running action in one session. From another vantage point, probe for the corresponding key. Measure the time-to-disappearance. Repeat under varying inputs to see if the TTL window changes with input size (data-dependent timing).

Mitigation that actually works

Operations that should not be externally observable use a constant-time wrapper: the key lives for at least N seconds regardless of actual completion time, with the real result stored under a separate unguessable key.

Leak channel #3: error-message reflection

The KV driver returns errors. The application maps them to HTTP responses. Common mistakes:

What to test: fuzz the request shapes and capture every distinct error response. Cluster them. Any cluster that varies based on the existence or content of someone else's data is a leak.

Mitigation that actually works

A single error code and message for the entire "denied or missing" class. Detailed errors only in server logs that the user never sees.

Leak channel #4: prefix-scan side channels

Some KV implementations allow scans by key prefix. If the admin API exposes scan and a less-privileged role can reach it (intentionally or through bug), the attacker enumerates every key for a target tenant.

Even when scan is correctly gated, a clever attacker can sometimes get a prefix-scan-equivalent through:

What to test: map every endpoint that returns a key name, a count, or anything derivable from "this key exists." Confirm each enforces tenant isolation. Repeat with two test tenants to verify the boundary holds.

A test loop you can run today

  1. Inventory the KV access surface. Every endpoint, every backoffice tool, every debug route that reads or writes the KV.
  2. Capture key shapes. Look at a normal session and note every key the agent creates. Document the format.
  3. Probe with two accounts. Drive the same flows from account A and account B. Try to reach A's keys from B. Try to enumerate.
  4. Time the responses. Differentials of 5 ms or more between "exists" and "missing" are real channels.
  5. Cluster the errors. Group responses by error code, message, latency. Any cluster that depends on someone else's state is a finding.
  6. Triage by impact. Conversation-content disclosure is P0. Existence oracle without content is P1. Timing differential without an actionable inference is informational.

Final thought

KV stores feel safe because they are not databases. They are not running SQL. There is no parser to fuzz. That feeling is wrong. The leak channels are smaller per-channel, but the surface is wider because every agent runtime ships a custom KV access layer that nobody pentested.

If your agent has state, it has a KV layer. If it has a KV layer, it has these four channels. Test for them before someone else does.

Related