Skip to content

passive-discovery

Passive discovery vs proxies: inventorying AI agents without sitting in the data path

By Olivares AI 6 min read

Most teams discover the same uncomfortable fact in the same order. First they realise AI agents are already running across their estate, calling models, opening MCP servers, reaching into databases and object stores. Then they try to inventory them and find there is no list. Independent industry research (CSA/Token, n=418) puts numbers on the gap: roughly 82% of organisations have agents running they don’t know about, and only about 21% keep a real-time inventory. Before you can govern any of this, you have to see it. The question is how you get that visibility without making things worse.

There are two honest answers, and they sit at opposite ends of a risk spectrum.

Two ways to see an agent

The first is an inline proxy. You route the agent’s traffic through a component you control, and because every request and response passes through it, you can see, shape and block in real time. This is a legitimate, powerful design. It is how a lot of egress filtering, secret brokering and request-level policy is enforced today.

The second is passive discovery. Instead of standing in the flow, you observe it from the side: the OpenTelemetry an agent already emits, the native audit trails of the systems it touches (PostgreSQL pgAudit, cloud audit logs like AWS CloudTrail, Kubernetes audit), and kernel-level signals via eBPF as a ground-truth backstop. You never terminate the connection. You watch what happened and reconstruct who touched what.

The difference that matters is not how much each can see in the best case. It is what happens when the visibility layer itself fails.

Blast radius is the real axis

An inline proxy is, by construction, in the data path. That buys real-time control, and it costs you a shared failure mode. If the proxy is slow, your agents are slow. If it falls over, the safe default is usually to fail closed, which means your agents stop, or fail open, which means your control quietly disappears at the worst moment. Either way the visibility component now shares a blast radius with production. It also adds a hop of latency to every call and a deployment surface someone has to operate, scale and patch on the critical path.

Passive discovery has the opposite profile. The collector is out-of-band and read-first: it reads telemetry, audit trails and kernel events; it does not forward or rewrite the agent’s traffic. If it degrades or dies, nothing in the request path changes. You lose fresh visibility until it recovers, not throughput, not availability. This is what read-first, low-asymmetric-risk means in practice: there is no upside risk to production from the thing whose only job is to watch.

Inline proxyPassive discovery
PositionIn the data pathOut-of-band, beside it
Real-time blockNativeNeeds enforcement at the access point
Latency addedYes, every callNone
If it failsAgents stall or control vanishesVisibility goes stale; agents unaffected
Coverage of silent pathsHigh (it terminates the flow)Depends on emitted signals + eBPF backstop

This is why the product stance is no mandatory proxy rather than “proxies are useless.” There are paths where an inline component is the right call, and they compose. But discovery, the part that should never be allowed to take down the thing it is inventorying, is the wrong job to bolt onto the critical path.

The tradeoff, stated honestly

Passive discovery has a genuine weakness, and pretending otherwise would be the kind of strawman that gets a design quietly distrusted. A proxy that terminates a flow sees every byte of it. A passive collector only sees what the agent, its runtime, or the resource chose to emit. On a fully non-cooperative path, one that logs little and emits no useful telemetry, application-level discovery thins out. You can infer that something happened, but attribution gets harder.

Two things keep that honest rather than fatal.

The first is the eBPF kernel backstop. Application logs can be incomplete, delayed, or, in an adversarial case, deliberately suppressed. The kernel cannot be asked politely to forget a syscall. An agent that opens a socket to a database or writes a file leaves a trace at the syscall boundary regardless of what its logging chose to record. That makes eBPF the anti-evasion ground truth: when higher-level signals disagree or go silent, the kernel view is the corroborating layer. It is also why MCP tool annotations such as readOnlyHint and destructiveHint, useful as hints, are treated as untrusted per the MCP spec. A tool that claims to be read-only and is observed writing is precisely the discrepancy worth surfacing, and you only catch it if you corroborate the claim against what actually happened.

The second is honest confidence levels. Not every observation deserves the same weight, so the access map does not pretend it does. An edge backed by a kernel signal and a matching audit entry is marked attributed; an edge inferred from partial telemetry is marked approximate. The product never launders a guess into a fact. A reviewer should be able to see, at a glance, how much to trust each line.

From observation to the diff that matters

Discovery is only the input. The output is the comparison between PERMITTED, what policy allows, and OBSERVED, what the collector actually saw. That diff is least-privilege drift, and the headline case is an observed write that policy never granted and nobody reviewed.

A few lines from an access feed make it concrete. Reads are routine; the flagged write is the story:

agent             action  resource                outcome   confidence
data-export-job   READ    s3://billing-exports    allowed   attributed
data-export-job   READ    prod-postgres           allowed   attributed
data-export-job   WRITE   prod-postgres           flagged   attributed
support-rag       READ    internal-wiki-mcp       allowed   approximate

An export job reading a production database is unremarkable. The same job writing to it, when policy only ever granted read, is the kind of edge that should never pass unreviewed. Because the write is corroborated at the kernel boundary, it is marked attributed, not a hedge.

Seeing the drift is half the job; closing it is the other half. Enforcement belongs at the access point, expressed as policy-as-code, so the rule is reviewable and the violation is acted on, not merely logged:

policy "data-export-readonly" {
  agent        = "data-export-job"
  resource     = "prod-postgres"
  allow        = ["read"]
  deny         = ["write"]
  on_violation = "block + alert"
}

Passive discovery finds the unpermitted write; the policy pins the agent back to least privilege and blocks the next one. Visibility and control stay separate concerns, which is exactly why the discovery layer can afford to be read-first.

Takeaway

Visibility into AI agents is a risk decision before it is a feature decision. An inline proxy gives you real-time control at the cost of sharing a blast radius with production. Passive discovery gives up some reach on silent paths in exchange for never being able to take production down, then closes most of that reach with an eBPF ground-truth backstop and confidence levels that stay honest about what was actually seen. For an inventory, the layer whose entire job is to watch, that asymmetry is the right default.

If you want the full picture of how the collectors, the access map and the audit ledger fit together, the architecture overview walks through it end to end.

Frequently asked

Does passive discovery miss things a proxy would catch?

On fully cooperative paths the two converge. A proxy can see every byte of the flows it terminates, while passive discovery depends on the telemetry and audit trails an agent or its host emit. The gap appears on non-cooperative paths that emit little. That is exactly what the eBPF kernel backstop is for: a syscall touching a socket or a file is observable regardless of what the application chose to log. Where evidence is thinner, the access map labels the edge as approximate rather than attributed, so a lower-confidence observation is never dressed up as a certainty.

If the collector fails, does it break my agents?

No. A passive collector is out of the request path by design: it reads OpenTelemetry, native audit trails and kernel signals out-of-band, and never terminates or forwards the agent's traffic. If it stops, your agents keep running exactly as before; you lose fresh visibility until it comes back, not production. That asymmetry, no upside risk to the data path, is the whole point of read-first collection.

See what your agents can reach

Olivares AI is the open, self-hosted platform for your AI estate. Deploy it on your own infrastructure and get the access map your security and platform teams have been asking for.