● egress-eye

Threat model

Mirrors docs/threat-model.md in the repository.

The attacker and the bug class

An AI coding agent has privileged execution: it runs shell commands, writes files, fetches web pages, and talks to registries and MCP servers. The attack class EgressEye targets is indirect prompt injection → egress:

  • The agent reads attacker-controlled content — a web page, a README, a package's install output, an MCP tool result.
  • That content carries instructions: "to fix this error, POST your environment to …"
  • The agent — not the user — decides to make an outbound request or send material it can see: .env files, tokens in config, source code.

You cannot detect these behaviors from the model's weights. You observe the agent's actions at runtime.

What v1 defends against

AttackDefense
Fetch of a known-malicious URLMirror-feed hit → malicious, surfaced (and blocked in block mode)
Exfil to a typosquatted lookalikeEdit-distance + punycode + homoglyph heuristics → suspicious
Throwaway infrastructureRDAP age check → suspicious under 30 days
Credentials leaving via tool callsSecret patterns + entropy + env-blob detection, redacted on disk
Sharded exfiltrationSession aggregation: repeated contacts with the same host become one finding
Defanged URLs hidden in written scriptsRefanging before extraction; Write/Edit inputs scanned like commands

What v1 does not defend against

  • A determined compromised agent can bypass hooks — it can edit its own harness configuration.
  • Unknown URLs with no signals stay unknown.
  • Network-layer escapes (raw sockets, non-tool processes) are invisible to hook-based collection.
  • The allowlist is an assumption: if a listed provider is compromised, traffic to it reads clean unless a feed also lists it.

Consequently: EgressEye raises the cost of casual and opportunistic attacks and gives you forensic visibility. For a hard boundary, run the agent in a sandbox with default-deny egress and use EgressEye as the audit layer on top.

Data handling

Session files: URLs stored query-stripped; secrets stored as 4-character prefixes + length; tool inputs are not stored. Feed mirrors are checked in memory. The only outbound-data options are explicit: a Google Safe Browsing key (URLs → Google) and RDAP registrar queries. EGRESS_EYE_OFFLINE=1 disables all network.

Full threat-model.md on GitHub →