Skip to main content
Glama
Agent Decoy Gateway

Agent Decoy Gateway

README.md
# Agent Decoy Gateway

An **experimental, bounded** reference decoy for authorized security labs. One
state machine is exposed as a loopback REST API and as an MCP stdio server. A
combined mode exposes REST and MCP Streamable HTTP from one process and lets a
client follow a REST handle through MCP (or the reverse). It
uses synthetic settlement references `A → B → A`, one-time signed handles, a
session cap, and a hard maximum number of follows. It never proxies to a real
service and contains no real customer data. The combined mode includes an
**in-memory synthetic transfer ledger**. Its trusted test driver can issue
one-time grants bound to the exact payee and amount; no REST route or MCP tool
issues grants. A decoy handle cannot authorize a transfer.

This repository is a runnable **mechanism prototype**, not evidence that the
decoy stops ARTEX, increases an adversary's real spending, or improves on
published deception defenses.

A [pre-specified local-model pilot](docs/PILOT_RESULTS_KO.md) has now run 24
synthetic trials against a real loopback REST server. The bounded decoy drew
valid reference follows in 10/12 decoy trials versus 0/12 direct-denial trials,
but **both conditions had zero unauthorized transfers**. This shows conditional
agent engagement, not a defense-rate advantage over denial.

## Why this exists

The useful research question is whether bounded deception reduces the
probability of a real harmful effect **within an attacker's fixed time and
inference budget**, while keeping defender cost and benign-user disruption
small. An attacker may run a local model, a cloud API, or no model at all.
Thus dollar charges to an unknown opponent are not a sound primary metric.

The project is also growing a **service-aware catalog** for existing REST and
MCP interfaces. `agent-decoy catalog` reads OpenAPI and saved MCP `tools/list`
files, reports action names and candidate relation keys, and leaves effects
and authorization boundaries unknown until evidence is supplied. It does not
enumerate every possible attack chain or make blocking decisions. See the
[product direction and VAmPI inventory](docs/SERVICE_AWARE_PROJECT_KO.md).

The simple cycle is a **published baseline**: Ayzenshteyn et al.,
[*Cloak, Honey, Trap*, USENIX Security 2025](https://www.usenix.org/system/files/usenixsecurity25-ayzenshteyn.pdf),
describe cyclic references. More recent comparison points include
[*AgentSnare*](https://arxiv.org/abs/2607.26998),
[*AgentTrap*](https://arxiv.org/abs/2610.02869), and
[*A Gingerbread House for LLM Agents*](https://arxiv.org/abs/2611.07611),
which evaluates an isolated shadow against ARTEX. Any future paper must compare
against these mechanisms and identify a narrower, independently demonstrated
contribution.

## Install and run

Requires Python 3.11+.

```bash
python3.12 -m venv .venv
.venv/bin/python -m pip install -e .
.venv/bin/agent-decoy api --port 8765
```

In another shell:

```bash
curl -s -X POST http://127.0.0.1:8765/v1/start -H 'Content-Type: application/json' -d '{}'
```

Pass the returned `handle` in `{"handle":"..."}` to `POST /v1/follow`.
`GET /health` reports whether the synthetic server is running. Only loopback
binding is accepted by the REST adapter.

For MCP, configure a host to launch `.venv/bin/agent-decoy mcp-stdio`. The
official Python MCP SDK exposes `lookup_settlement_reference` and
`follow_settlement_reference` as tools. The MCP adapter uses the same engine
as the REST adapter; each server process has its own in-memory sessions.

Run `.venv/bin/agent-decoy combined --port 8765` for REST routes on
`http://127.0.0.1:8765/v1/*` and the MCP Streamable HTTP endpoint at
`http://127.0.0.1:8765/mcp`. Both routes share one in-memory engine. The
combined server also exposes a **disposable** ledger via `GET /v1/ledger` and
`POST /v1/transfer`; its MCP counterparts are `read_synthetic_ledger` and
`transfer_synthetic_funds`. With no trusted grant, transfer requests are
denied. The public interfaces cannot mint a grant.

For an **opt-in lab comparison only**, run
`.venv/bin/agent-decoy combined --port 8765 --denial-policy decoy`.
An invalid-grant transfer then returns `verification_required` plus a bounded
reference instead of direct denial. It still commits no transfer; authorized
grants still work. The default remains `--denial-policy deny`. This mode is
for isolated synthetic experiments, not a production transaction response.

```bash
.venv/bin/python -m unittest discover -s tests -v
```

## Current limits

- The two-node cycle is intentionally easy to detect. The local pilot measures
  only conditional reference following by two small models after a failed
  transfer probe; it makes no ARTEX or attacker-population claim.
- The REST API has no authentication because it is restricted to loopback. Do
  not expose this prototype to a network or put it in front of a real bank.
- In-memory state disappears on restart. Per-process session limits do not
  impose a global limit across replicas.
- The defender cannot observe an external attacker's LLM bill. A future
  controlled experiment must instrument the attacking agent directly.
- The synthetic grant gate is only a test oracle; it is not a real bank's
  identity, consent, accounting, or transaction system. There is no
  benign-workflow classifier yet. These gaps must be closed before any
  defense-effect study.

## Planned evaluation gate

Use disposable, authorized REST and MCP applications with independent
server-side effect oracles. Freeze tasks, attack budgets, policies, and
thresholds before comparison. Run capable attack agents with both local and
cloud models where available. Compare direct denial/rate limiting, this
static cycle, published adaptive deception, and any new policy on the same
tasks. Report real harmful effects by budget, decoy tool calls/time/tokens,
defender CPU/model cost, benign completion and delay, and whether an
adaptive agent detects and abandons the decoy. A change to the cycle alone
is not a research contribution.

TDQS

B3.2/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have clearly distinct roles: one opens/creates a synthetic settlement-reference trail, while the other follows an existing reference handle. The descriptions make the sequence and action boundaries explicit, so an agent should not confuse them.

Naming Consistency5/5

Both names follow a consistent verb_noun pattern: lookup_settlement_reference and follow_settlement_reference. The shared object name reinforces the relationship without creating naming ambiguity.

Tool Count3/5

Two tools is thin for a gateway surface, even if the intended workflow is deliberately minimal. The set is not bloated, but it sits at the borderline where more lifecycle operations may be expected.

Completeness3/5

The basic open-and-follow workflow is covered, but there is no visible way to list trails, inspect status, close/reset a trail, or handle errors beyond the hard step limit. These are notable gaps for a stateful reference-trail domain, though agents may work around them.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues