Find the AI use happening outside your controls
Five evidence sources, and a coverage report that refuses to call a dead feed a clean estate.
On this page
The survey, the procurement list, and the green banner over a dead feed
The first attempt is to ask. A survey goes round, teams list the AI tools they use, and the result is an inventory of the tools people were willing to write down, assembled at one moment, out of date by the end of the quarter. It is not worthless — it is where the vendor bindings and the known integrations come from — but it answers a different question from the one that was asked, because the usage that matters is the usage nobody thought to declare.
The second is the procurement list, which finds the tools somebody paid for through a purchase order and misses every one paid for on a personal card, every free tier, and every service-account key minted by an engineer during an outage two years ago and never revoked. It is also silent about the commonest bypass there is, which is not a tool at all: a coding assistant whose base URL was never set, falling back to the vendor’s own endpoint, on a machine where nothing looks misconfigured.
The third is a discovery tool with a findings page, and this is where the reporting-integrity problem starts. Any tool can produce a list of findings; the hard part is the sentence underneath the list when it is empty. A console that renders no findings as a green banner has made a claim about your estate, and on most days it has no idea whether it is entitled to. The export could have stopped three weeks ago, the credential it arrives on could have been revoked this morning, or the exporter could be posting on schedule into a mapping that reads none of it. All of those emit exactly the same bytes as a clean estate.
That failure is not hypothetical and Token Observe records the version of it that it shipped. Arrival used to be recorded as a batch arriving, which meant an exporter delivering an empty page every hour held its source at fresh indefinitely — with a row count of zero stored beside the claim, where no state machine read it. A wrong window, a page that came back empty, a permission quietly downgraded to one that returns nothing: those are the commonest ways a real exporter fails, and each is worse than having no feed at all, because coverage was affirmatively asserting freshness over the top.
How to actually do it
Each step is something you can go and do. Where a step depends on a decision somebody has to make rather than a setting somebody has to change, it says so.
- 01
Mint an ingest credential and decide where it will live
Minting is an admin action; revoking is an operator action, deliberately, because a credential nobody can revoke without finding an admin is a credential that stays live through the incident. The credential may only post evidence rows for the streams it was scoped to — it cannot read findings, run a scan, change a policy or reach any other surface, since no resolver outside the ingest route looks it up. - 02
Send the vendor master bill first
It runs first among the detectors because it is ground truth for what was actually spent, and because no other source can find usage that left no network, identity or endpoint trace at all. Vendor lines for a calendar month are compared against metered spend for the same month, and a gap has to exceed both one dollar and five per cent of the larger side before anything is reported, because rounding, currency conversion and mid-month proration make small gaps meaningless. - 03
Declare which invoice accounts belong to which provider row
Vendor lines are keyed by invoice name and account; metered lines are keyed by the provider name an operator registered, which is free text. Token Observe refuses to guess that join, so per-provider attribution happens only where you have declared the binding — an account claimed by two provider rows falls back to the month-level aggregate rather than being resolved by list order. - 04
Add egress, service-account keys and IDE telemetry
Each answers a narrower question: destinations matched against a fixed list of vendor API hostnames by exact match or subdomain plus a shape match for regional Bedrock endpoints; provider keys past a rotation window, unknown to the gateway, or idle long enough to revoke; and coding agents whose configured base URL is not this gateway. An unset base URL is the finding worth reading first, because it means the tool falls back to the vendor’s own endpoint. - 05
Read the coverage report before you read the findings
The report is attached to the findings list, the scan response, the coverage route and the dashboard summary where it is built, so no surface can quietly decide an empty list is good news. Only connected_fresh permits an unqualified all-clear; the other four each name a different thing being wrong, and connected_empty says both halves out loud — the connector is alive and the estate has not been observed. - 06
Route the findings to a person with the authority to act
A finding is a lead to investigate rather than proof, and each carries the evidence it was raised from. Findings sit at auditor rank because they carry workstation hostnames, staff usernames, service-account identifiers and, on a seat row, an employee’s address; the coverage report sits at viewer rank on purpose, because it is what a console must render beside nothing found. Every discovery surface additionally requires an organisation-wide evidence scope.
Two clocks per feed, and why an empty delivery is not no delivery
Coverage records two facts per source and computes one of five states from them. A delivery proves the connector is alive. A delivery carrying at least one row proves the estate was observed. Those are different facts about the world and they are kept in different columns, because they were once the same column and the consequence was a source held at fresh indefinitely by an exporter delivering nothing.
An empty delivery is not meaningless either. A genuinely quiet hour on an egress feed is a real answer, and calling a working exporter silent is how a status surface gets muted, after which it reports nothing at all. So an empty hour keeps the connector alive and moves no observation clock, and connected_empty exists as its own state rather than being folded into a neighbour — fresh would be the lie, and stale would send somebody to fix a connector that is running perfectly.
The silence bounds are a product judgement rather than a constant somebody picked, and the rule behind each is roughly two expected cycles rounded up so a jittery scheduler does not flap. A vendor master bill is published once a calendar month, so the natural gap is already about thirty-one days at its widest and forty-five is the smallest gap that unambiguously means somebody stopped exporting. Egress gets six hours rather than twenty-four for one reason: it keeps the detection window inside a working day, and it is the only source that can catch an exfiltration channel while it is still open.
Freshness alone is always late, though, and that is the gap the third input closes. A credential revoked this morning would leave a billing source reading fresh until well into the following month, so pull-connector runs, push-delivery outcomes and the liveness of the ingest credential a stream arrives through are all joined into the coverage report. Where any of them says collection has demonstrably stopped, a fresh or empty source is demoted to feed_failing — reporting the earlier of two true answers rather than the later one. A verdict that is already unreassuring is left as it is, because stale and never-connected are older and larger facts than a connector that broke this morning. Rotating a credential the normal way, minting the new one before revoking the old, is a normal Tuesday and never reads as an outage.
- connected_fresh
- Evidence arrived inside the bound. The only state a clean result can stand on, and the only one that permits an unqualified all-clear anywhere in the product.
- connected_empty
- Deliveries are still arriving and none recently carried a row. The connector is alive and the estate has not been observed.
- feed_failing
- The evidence is still inside its bound and the thing that fetches or delivers it has stopped. Freshness alone would go on reporting this source as covered for the rest of the bound.
- connected_stale and never_connected
- Evidence has arrived before and not recently enough, or nothing has ever arrived. Stale is the dangerous one, because everything still looks configured: the connector exists, the credential exists, and the last scan succeeded over evidence that is now weeks old.
What each source can actually prove, and where each one refuses to guess
Bill reconciliation is the only detector that can find usage leaving no network, identity or endpoint trace, and it is also the one most likely to produce a spectacular false positive, so its joins are conservative. Matching vendor lines to metered providers by string would report every provider whose registered name differs from its invoice name as unmetered spend — the most severe finding the product emits — for money that was metered perfectly. Severity is taken as the worse of a ratio reading and an absolute reading, so a ninety per cent gap on twelve dollars and a six per cent gap on forty thousand are both reportable and neither hides behind the other. Over-metering is reported and capped, because it is a price-table problem that should reach an engineer rather than the risk register.
Per-user seat spend is the first shape whose subject is an employee, and what travels where is deliberate. The finding detail carries the address, the months, the amounts and the internal user id where one matches, because there is no version of this feature that withholds them. The summary and the dedup key carry no address at all, because both leave the process into an alert and an alert lands in a channel with a far wider readership than the console — so the key is the first twelve hex characters of a digest of the address, stable and unique per person and meaningless to a recipient.
The service-account key audit reports three shapes that make a bypass durable — keys past a rotation window, keys the gateway has no record of using, and keys idle long enough to revoke outright — with the key itself as the identity, given as the provider, the account and a twelve-character digest of the key id, never the raw value. One credential ageing through three thresholds therefore advances one finding rather than opening three.
The fifth source needs no export and cannot go stale between them, because it reads the gateway’s own tables. Its strongest finding is the unpriced model: cost is computed at zero when no price row matches, so a model nobody registered is metered at nothing while the vendor bills for it in full, and that finding names by key the exact billing-gap findings its months explain. The predicate is narrower than zero cost alone, because a response served from the gateway’s own cache is also metered at zero on purpose — requiring input plus output tokens above zero excludes every cache hit without parsing a byte of payload. The same source reports credentials in daily use on agents nobody activated, active agents with no usable credential, and sustained pressure from callers presenting credentials the gateway refuses, gated at five attempts across at least three distinct hours so that a deploy going wrong is not read as a channel.
When a finding is allowed to close, and why that is the hardest operation
A finding is identified by its source plus a stable dedup key, and that pair names a condition rather than an observation — so re-scanning against a fresh export advances the counters on the finding that already exists and leaves whoever is triaging it alone. Each pass is a set difference against what was true last time, producing the transitions an operator acts on: new, recurring, escalated, de-escalated, regressed and cleared. A condition that had been resolved and has come back reopens its finding, because that is news.
Closing by absence is deliberately the hardest operation in the whole subsystem, because a wrongly resolved finding is worse than a stale one: it is a condition that was true, is still true, and is now filed as handled. Four things have to hold at once. The run for that source reported completed, since a failed or timed-out run produced a partial picture and I did not see it is not it is not there. The source is one where absence is evidence, which is only the source that reads the gateway’s own tables — a scan of an export sees exactly the rows somebody posted, and an export that omits last month’s shadow key has not remediated it. The source actually ran in that pass, so switching a detector off cannot quietly close everything it ever reported. And the detection side saw its whole population, because a condition that fell past a row ceiling is missing from the observed set for exactly the same reason a remediated one is.
Every bound at the receiver refuses whole rather than truncating, for the same reason: a silently shortened batch leaves you believing Token Observe holds evidence it does not hold. Ten thousand records or eight megabytes per delivery, a burst ceiling on delivery rate, and a cap of fifty unconsumed batches per stream — that last one meaning detection has stopped rather than that the exporter is too fast, which is what the message says. The single tolerance that is not all-or-nothing is the mapping ratio, and it is two-sided on purpose: a few junk rows are dropped and counted, never silently, and a delivery past five per cent is refused whole with the ratio named, because half not mapping is what a wrong mapping looks like rather than what a dirty feed looks like.
Unattended scanning is off by default, and when you switch it on the schedule lives in the database rather than in a process timer. The obvious implementation resets its clock on every restart, so a process redeployed every forty minutes with an hourly interval never scans at all and nothing anywhere reports it — the schedule looks enabled, the logs look healthy, and the radar is simply never asked a question. Instead the next due time is a column written when a run finishes, so a restart changes nothing.
What this still does not solve
Doing everything above leaves a residue. It is smaller than what you started with and it is not nothing, and knowing its shape in advance is the difference between a control you trust correctly and one you trust too much.
- Discovery blocks nothing. It cannot stop a workstation talking to a vendor API, and it cannot tell you where a workload the gateway refused went next — that is the question the finding tells you to go and ask.
- Egress detection matches a fixed list of vendor API hostnames plus a shape match for regional Bedrock endpoints, and IDE detection recognises six named coding agents. A model endpoint or an agent CLI outside those lists is not detected, and adding one is a code change rather than a setting.
- Neither shipped pull connector has been run against a live vendor tenant. Cisco Umbrella’s query parameters, pagination and field names, and GitHub Copilot’s endpoint path and field names, are written to recorded-shape fixtures and each vendor’s published documentation, and a field a vendor has since renamed lands as a typed schema error on the connector status surface rather than as silence.
- A finding is a lead rather than proof, and some of them are structurally ambiguous. A silent endpoint seat cannot be told from a person on leave, and the finding says so in as many words, because an operator who reads it as tampering will chase the wrong thing and one who reads every instance as leave will eventually miss the real one.
If one of those residues is the thing that actually worries you, that is the conversation worth having rather than the one about the steps above it.
Talk it throughThe parts of the platform this uses
Shadow AI radar
Five evidence sources for AI activity that never touched the gateway, and a coverage model that refuses to call a dead feed a clean estate.
No billing, network or IAM access — you send the export
Endpoint seats
Policy enforced inside each vendor’s own administrator hook, decided offline against a signed bundle, because a hook that phones home fails open.
Preview. Not an inline gateway on an unmanaged device.
Agent registry
One record per agent, and it is the record the gateway enforces against.
An overdue review never suspends the agent itself
Spend controls
Hard USD ceilings, per-minute rate limits and a kill switch, all decided before the request leaves your network.
One billable egress: no retry, no failover
The other jobs
How do you tell a dead feed from a clean estate?
By recording two facts per source and reporting them beside every clean result. Coverage stores when a delivery last arrived, which proves the connector is alive, and when a delivery carrying at least one row last arrived, which is what freshness is computed from. Those produce five states, and only connected_fresh entitles a console to render an unqualified all-clear; the others name the source, say when it last delivered, and say what its silence means. The report is attached where it is built — to the findings list, the scan response, the coverage route and the dashboard summary — so no surface can quietly decide an empty list is good news.
Does Token Observe need access to our finance system or our firewall?
No, and the direction of the connection is the security argument rather than a deployment convenience. Your own exporter pushes to a receiver on a credential Token Observe issued, and that credential may only post evidence rows for the streams it was scoped to. Two optional pull connectors do hold a vendor credential you supply — Cisco Umbrella hourly for egress and GitHub Copilot six-hourly for seat spend — and both are off until you configure them. The alternative was considered and rejected: a governance gateway holding read access to the finance system and the flow logs is a more attractive target than the thing it protects.
How quickly do you notice when an ingest credential is revoked?
The same day, rather than at the end of the freshness bound. Coverage alone cannot answer this in time, because bounds are measured in cycles of the export and a vendor bill is allowed forty-five days of silence. So the credential registry, the pull-connector run history and the push-delivery ledger are joined into the coverage report, and a source whose feed has demonstrably stopped is demoted to feed_failing while its evidence is still inside its bound. Nothing new had to be stored to make that work; it was a join that was missing.
Can a finding close itself once the problem is fixed?
Only for the source that reads the gateway’s own tables, and only when four things hold at once: the run completed, the prior-state snapshot was not truncated, the source actually ran in that pass, and the detection side saw its whole population. The four operator-fed sources never clear by absence, because a scan sees exactly the rows somebody posted and an export that omits last month’s shadow key has not remediated anything. The reasoning is that a wrongly resolved finding is worse than a stale one: it is a condition that was true, is still true, and is now filed as handled.
What do we do with a finding once we have one?
Treat it as a lead and read the evidence it carries. The practical sequence is to identify the owner, decide whether the usage should be brought inside the gateway or stopped, and then use the controls that do enforce — register the agent, issue it a credential, point it at the gateway, and revoke the key it was using. For a developer subscription the enforcement route is a managed seat rather than a network gateway, and Token Observe cannot revoke a subscription in any case: retiring a seat stops it reaching Token Observe, and the vendor’s own administration console is what ends the entitlement.
Describe the version of this you actually have.
The steps above are the general shape. Which of them matter, and in what order, depends on what your agents do and which of them worries you — say that and you will get a straight answer, including when the answer is that Token Observe is not what you need for it.
no form · no qualification step · no sales desk · the other three ways in