Skip to content

Shadow AI Discovery

The gateway governs traffic that points at it. Shadow AI Discovery answers the other question: what AI is running in the organization that doesn’t? Collectors and scanner adapters run in your infrastructure — CI, a host, a scheduled job — and send cryptographically signed discovery events to the platform, which reconciles them against the real gateway configuration and surfaces the result in the AI Asset Registry as governed, ungoverned or unknown.

Discovery Integrations — BYO-scanner adapters and collector keys

Collectors POST events to POST /v1/discovery/events on the Control Plane. There is no admin JWT on this endpoint — the Ed25519 signature is the authentication:

  1. Register a collector key (POST /v1/admin/discovery/collector-keys) — a base64 Ed25519 public key with a trust_tier: first_party · channel · customer · community.
  2. The collector signs each event (canonical JSON, minus the signature block) with its private key and sends signature: {alg: "ed25519", key_id, value}.
  3. The platform verifies the signature against the registered key. Missing/bad signature or unknown/revoked key → 401.

Idempotency and dedup are built in: event_id is unique per tenant (a duplicate is a {"status": "duplicate"} no-op), and events deduplicate into one discovered asset per (tenant, asset_key) — re-discovering a dismissed asset re-activates it.

Two properties are platform-computed and never taken from the event:

  • Confidence — strongest evidence wins (passive network 0.9 > active probe 0.7 > host-derived 0.5), multiplied by the collector key’s trust tier. A collector’s own confidence claim is ignored.
  • Governance status — reconciled against live config: an llm_endpoint is matched to llm_providers by host, an mcp_server to mcp_servers.base_url, an a2a_agent to agent_cards.source_url. Matched to an enabled row → governed; unmatched or disabled → ungoverned; no host to match → unknown.

The broadest first-party collector reads destination hostnames from egress proxy, firewall or DNS logs (Zscaler, Palo Alto, Squid) and emits an llm_endpoint event per known AI-provider host — OpenAI, Azure OpenAI, Anthropic, Google (Gemini + Vertex), AWS Bedrock, Mistral, Cohere, Groq, Perplexity.

Terminal window
pip install brutor-discovery
brutor-egress-collector --input /var/log/squid/access.log \
--gateway https://control.example.com --key collector.key

Evidence lands as tls_sni, passive — the highest-confidence class.

Already running an AI scanner? brutor-ingest converts its output into signed discovery events — no bespoke collector required. Four adapters ship in the Discovery SDK (catalog: GET /v1/admin/discovery/ingest-adapters):

Adapter Modality Ingests
cyclonedx-aibom static CycloneDX 1.5/1.6 ML/AI-BOM from any code/container scanner (Cisco AI-BOM, Trusera, cdxgen) — models, SDKs, agent frameworks, MCP servers
agentsonar runtime Knostic AgentSonar process→domain AI classifications — traffic bypassing the gateway
snyk-agent-scan config Snyk agent-scan / mcp-scan — MCP servers from local client configs (Claude Desktop, Cursor, …) incl. tool-poisoning findings, skills, agents
safedep-vet static SafeDep vet ai discover / vet code scan — coding agents, MCP servers, IDE extensions, AI-SDK usage in Go/Python/JS-TS
Terminal window
# Feed a CycloneDX AI-BOM from CI
brutor-ingest --adapter cyclonedx-aibom -i aibom.json
# Feed AgentSonar runtime classifications, thresholded
brutor-ingest --adapter agentsonar -i pairs.jsonl --set min_ai_score=0.6

asset_typellm_endpoint · mcp_server · a2a_agent · inference_runtime · agent_framework · sdk_usage · unknown_ai, with provider/endpoint details, computed_confidence, governance_status (+ governed_ref when matched), lifecycle status (active · onboarded · dismissed), evidence count and first/last seen. Evidence rows carry the type (dns_resolution, tls_sni, netflow, process, env_var, package_manifest, config_file, well_known_probe, registry_entry, api_inventory), the collector and its trust tier.

Method Path Purpose
GET /v1/admin/discovery/assets List discovered assets + coverage counts
GET /v1/admin/discovery/assets/{id} Detail with evidence
POST /v1/admin/discovery/assets/{id}/onboard Returns a pre-fill config payload; marks onboarded
POST /v1/admin/discovery/assets/{id}/dismiss Mark not-relevant
POST /v1/admin/discovery/reconcile Re-run governance matching for all assets
GET / POST /v1/admin/discovery/collector-keys Manage collector keys (POST .../{key_id}/revoke to revoke)
Terminal window
curl -s -X POST http://localhost:5050/v1/admin/discovery/assets/dasset-01K0.../onboard \
-H "Authorization: Bearer $ADMIN_JWT"
{
"status": "onboarded",
"prefill": {
"kind": "mcp_server",
"name": "internal-crm-mcp",
"base_url": "http://crm-tools.internal:8080"
}
}

Discoveries surface in two places: the AI Asset Registry (the ungoverned list, coverage scorecard, and onboard/dismiss actions — Discovery Integrations is a drill-down from its header) and Mission Control’s Governance tab (shadow-AI signals).