> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blindsight.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Triage & governance

> Work the Shadow AI inventory: how risk is ranked, what sanction / block / onboard actually do, the Insights read on the estate, and the exportable report.

The inventory is a worklist, not a dashboard. Every row is an AI
service somebody reached from a managed device, and every row wants
one of three decisions.

Open it at **Runtime Security → Shadow AI**.

## The worklist

### Figures

| Figure | What it counts |
| - | - |
| **AI services** | Distinct services in scope, with how many are new in the last 7 days. |
| **Needs review** | Services with no decision recorded. This is your backlog. |
| **High risk** | Unsanctioned services the risk model ranks high. |
| **Governed** | Share of services that have any decision: sanctioned, blocked, or managed. |

### Filters

One search box over host and provider, a row of state chips, and quiet
scoping controls on the right.

| Control | Options |
| - | - |
| **Chips** | All · Needs review · High risk · Unknown host · Workflow · Sanctioned · Blocked · Managed |
| **Sort** | Highest risk (default) · Most active · Recently seen · Most devices |
| **Device** | Drill into one device's services. |
| **User** | Drill into one identity's services. |
| **Time range** | Last 7 / 30 / 90 days, or all time. |

Chips only appear when they can match something, so an empty
**Workflow** chip means no automation platform has been seen at all.

### Columns

| Column | What it shows |
| - | - |
| **Service** | The hostname, with the provider slug underneath. |
| **Category** | **Known AI**, **Unknown host**, or **Managed**. Suffixed `· workflow` for automation platforms. |
| **Risk** | High / Medium / Low, or `—` for a service that already has a decision. |
| **Decision** | Needs review · Sanctioned · Blocked · Managed. |
| **Devices** | Distinct devices that reached it. |
| **Activity** | Cumulative observed connections. |
| **Last seen** | Time since the most recent observation. |

Click any row to expand it. The detail strip shows **Why this
ranking** (the reasons behind the risk level), exact first and last
seen timestamps, and the three action buttons.

## How risk is ranked

Risk is derived from signals the inventory already carries. There is
no hidden score and no model: recognition, capability, and exposure.

| Signal | Effect | Reason shown |
| - | - | - |
| Known AI, not sanctioned | Medium | "Known AI, not sanctioned" |
| Not in the catalog (**Unknown host**) | **High** | "Unrecognised host: not in the AI catalog" |
| Workflow automation platform | **High** | "Automation platform: can move data between systems" |
| Seen on 5 or more devices | **High** | "Broad exposure: seen on N devices" |
| Seen on 2 to 4 devices | Medium | "Seen on N devices" |

Unknown hosts rank high because nobody has verified where the data
goes. Workflow platforms rank high because an AI step inside an
automation can relay records between systems without a human in the
loop. Device spread ranks high because a tool on twenty laptops is a
policy problem, not an individual one.

## When the automatic action passes a service over

A workspace can set **Newly discovered AI** so that anything the fleet
finds is inspected, or protected, or blocked, without waiting for a
person. That action does not reach every discovered row, and the row now
says so rather than leaving you to guess.

Only a **corroborated** candidate is acted on automatically. A host the
classifier recognised on a single weak signal stays a candidate for a
person to decide about, and a host nobody probed is acted on only when its
name alone clears the bar.

| What the row says | What it means |
| - | - |
| *Automatic inspection skips this one: the name alone is not enough evidence, so it waits for you* | Nothing looked at the host itself, and its name does not read as AI. |
| *Automatic inspection skips this one: a single signal is not enough, so it waits for you* | Something looked, and found one signal. One is not enough to decrypt a host nobody has reviewed. |
| *Automatic inspection never acts on this kind of host, whatever the evidence says* | The host is on the never-promote list: banks, healthcare, content networks, telemetry. |
| *Infrastructure: automatic inspection never writes a rule for it* | A CDN or similar, which is not a service anybody uses. |

The bar is deliberate. An earlier build promoted a **bank** to protected
off a single refused request, and a rule that decrypts a bank on one weak
signal is worse than a service nobody inspected. Anything held back is
still listed, still ranked, and can be inspected or blocked by hand in one
click; the automation simply will not decide for you.

> [!NOTE]
>
> Risk is only meaningful for undecided services. Anything sanctioned,
> blocked, or managed resolves to low by definition, so the worklist
> shows `—` rather than pretending the ranking still says something.

## The decisions

All of these require the `endpoint.ai_services.manage` permission (formerly
`runtime_security.ai_services.manage`, see
[Endpoint permissions](https://docs.blindsight.io/endpoint/permissions.md)) and write an audit record.

Three of them are **decisions about the service**, and they move
`status`:

| Action | Status becomes | What it does |
| - | - | - |
| **Sanction** | `sanctioned` | Marks the service as an approved tool. It stays in the inventory with its history, drops out of the shadow count, and is excluded from the report entirely. Also writes an `observe` rule, which clears any earlier `block`, so approving a tool is a real way back from banning it. |
| **Block** | `blocked` | Writes a `block` host rule. Agents refuse the connection on their next policy pull. |
| **Onboard as app** | `promoted` | Creates a managed App keyed from the hostname, links the row to it, **and writes an `inspect` rule** so the traffic is fully inspected. |

> [!NOTE]
>
> Onboarding used to create the App and push no rule at all, which
> left the service governed on paper but never decrypted. It now
> writes its own `inspect` rule, so the one status that means "fully
> managed" gets the full treatment. If you onboarded a service before
> August 2026 and added the `inspect` rule by hand, that rule is
> yours and is left alone.

### Protect: inspect without deciding

**Protect** is not a decision about whether the company wants the
service, so it leaves `status` alone and the row stays in the review
queue.

| Action | What it does |
| - | - |
| **Protect** | Writes a `protect` host rule. The agent inspects the traffic, personal data is pseudonymized before the prompt leaves the device, and injection is scored and logged. **The person using it is never blocked.** |
| **Unprotect** | Drops the service's own rule, so it falls back to the workspace posture. If the "protect unapproved AI" floor is on, this writes an explicit `observe` rule instead, which is the only way to stop inspecting one host while the posture stays on. |

Protect is the middle ground between letting something happen unseen
and banning it: you get visibility and redaction on a tool nobody has
vetted, without breaking anybody's day while you decide.

> [!WARNING]
>
> Protect and unprotect are **refused with `409`** on a service
> somebody has already blocked or onboarded, because either one writes
> a rule that lets traffic through:
>
> * On a **blocked** service, protecting it would un-ban it. Sanction
>   it first if you want it inspected rather than denied.
> * On an **onboarded** service, either one is a way to stop it being
>   fully inspected. It is already inspected, and protect is the
>   weaker posture: it can never block a prompt.

### Which decision to reach for

| Situation | Decision |
| - | - |
| An approved vendor tool that you do not need to inspect | **Sanction** |
| A companion / roleplay service, or an unknown host nobody claims | **Block** |
| A tool a team genuinely needs, on sensitive work | **Onboard as app** |
| A tool you have not decided on, but do not want unseen either | **Protect**. Visibility now, decision later. |
| A service you have not investigated yet | Leave it. **Needs review** is an honest state. |

## A weekly triage pass

**1. Filter to Needs review, sorted by highest risk**

The default sort already does this. Set the time range to the last
7 days for the new arrivals, or all time to clear the backlog.

**2. Start with the unknown hosts**

Expand each row and read **Why this ranking**. Resolve the
hostname: is it an internal gateway, a new vendor, or something
nobody can account for?

**3. Check exposure before deciding**

A service on one device is usually a person to talk to. A service
on twenty is a policy to write. Use the device and user filters to
see who is behind it.

**4. Decide**

Sanction, block, or onboard. Every row you leave undecided is a
row the report will call ungoverned.

**5. Confirm the block landed**

Blocked services push a host rule to the fleet. Policy propagates
within about 30 seconds, or immediately if you **Push policy**
from **Endpoint → Devices**.

## Insights

**Runtime Security → Shadow AI → Insights** is the read on the estate,
where the worklist is the read on individual services. It deliberately
repeats nothing from the inventory.

| Section | What it answers |
| - | - |
| **AI traffic over time** | Daily connections to AI destinations, this window against the previous one. Read from the per-day rollup, so it says *when*, not just how much. |
| **Governance funnel** | How much of the discovered estate has a decision. |
| **Sensitive data to AI** | What the firewall found in prompts to *managed* apps: verdict mix and PII categories. The bridge between discovery and inspection. |
| **What drives the risk** | Aggregate risk drivers among the unsanctioned: broad exposure, unrecognised hosts, workflow platforms. |
| **Account type** | Observing devices split into SSO / directory-bound and off-SSO. |
| **Top devices / users / departments** | Distinct AI services seen per device, identity, and group. |
| **Recent alerts** | Newly discovered services, and ones that have been waiting too long for a decision. |

The trend needs at least a day of rollup data. Until agents have
reported, it says so rather than drawing a flat zero line.

## Export the report

**Export** on the Shadow AI page generates a PDF built server-side.

| Option | Values |
| - | - |
| **Type** | Full report, or summary. |
| **Sections** | Discovered services inventory · Risk analysis & traffic trend · Usage & exposure · Methodology & definitions. The executive summary is always included. |
| **Range** | Last 7 / 30 / 90 days, or all time. |
| **Anonymize** | Replaces user and device names with `User 1`, `Device 1`. Departments are kept. |

The report leads with a narrative summary, then the risk-ranked
inventory, the traffic trend against the prior period, exposure
breakdowns, and a methodology section that states plainly that
detection is passive and destination-only.

> [!NOTE]
>
> Sanctioned services are approved tools, not shadow AI, so they are
> excluded from the report everywhere: the table, the totals, and the
> breakdowns. The inventory in the console still shows them, filtered
> behind the **Sanctioned** chip.

Filenames are stamped, `shadow-ai-report-20260729.pdf` or
`shadow-ai-summary-20260729.pdf`, so a monthly export drops cleanly
into an evidence folder.

## API

The discovery routes live under `/api/runtime-security/` and use the
same workspace authentication as the rest of the dashboard API.
`endpoint.discovery.view` reads; `endpoint.ai_services.manage` acts.

> [!NOTE]
>
> Both permissions were renamed in August 2026. Reading the inventory
> used to require the endpoint policy key, which took Shadow AI away from
> roles that could see Runtime Security but were never given policy
> read, so the inventory now has a permission of its own. See
> [Endpoint permissions](https://docs.blindsight.io/endpoint/permissions.md).

| Endpoint | What it does |
| - | - |
| `GET /api/runtime-security/discovery` | The inventory: services, totals, and the device / user / department breakdowns. |
| `GET /api/runtime-security/discovery/activity` | Daily connection counts for a window and the one before it. |
| `GET /api/runtime-security/discovery/catalog` | Inspected providers plus every passively detectable host. |
| `POST /api/runtime-security/discovery/{id}/protect` | Inspect and pseudonymize it without blocking. `409` if already blocked or onboarded. |
| `POST /api/runtime-security/discovery/{id}/unprotect` | Stop protecting it. `409` if already blocked or onboarded. |
| `POST /api/runtime-security/discovery/{id}/sanction` | Mark a service as approved. |
| `POST /api/runtime-security/discovery/{id}/block` | Block it and push the host rule. |
| `POST /api/runtime-security/discovery/{id}/promote` | Onboard it as a managed App and write its `inspect` rule. |
| `POST /api/runtime-security/discovery/report` | Render the PDF report. |
| `POST /api/runtime-security/agent/discovery` | Agent ingest. Device-token authenticated, not for dashboard clients. |

`{id}` is the service's `uuid`. Every decision route returns the
updated service row.

`GET /discovery` accepts `status`, `days`, `device_id`, and `user`
query parameters, matching the console's filters:

```bash theme={null}
# Everything still awaiting a decision in the last 30 days
curl -s "$API_BASE/api/runtime-security/discovery?status=new&days=30" \
  -H "Authorization: Bearer $TOKEN" | jq '.totals, .services[0]'
```

```bash theme={null}
# Block a service by its id
curl -s -X POST \
  "$API_BASE/api/runtime-security/discovery/$SERVICE_ID/block" \
  -H "Authorization: Bearer $TOKEN"
```

## Audit trail

Every decision is recorded in the [audit trail](https://docs.blindsight.io/compliance/audit-trail.md)
against the `rs_discovered_service` entity, with the acting user and
the hostname.

| Event type | Recorded when |
| - | - |
| `runtime_security.discovery.sanctioned` | A service is marked approved. |
| `runtime_security.discovery.blocked` | A service is blocked (severity medium). |
| `runtime_security.discovery.promoted` | A service is onboarded as an App. |

Forward them to your SIEM with the
[audit webhook](https://docs.blindsight.io/data-security/integrations.md) if shadow-AI decisions
are part of your control evidence.

## Common workflows

> **Build the case for enforcement**
>
> 1. Run the fleet observe-only for two weeks.
> 2. Export the full report for the last 14 days.
> 3. Walk the risk drivers and the department breakdown with the
>    data-protection owner.
> 4. Decide the enforcement policy with real numbers rather than
>    hypotheticals.

> **Clear the high-risk backlog**
>
> 1. Chip: **High risk**. Sort: **Most devices**.
> 2. Work top-down. Broad exposure first, since it affects the most
>    people.
> 3. Blocked services push a host rule immediately; tell the affected
>    teams before you block a tool they use daily.

> **Investigate one team**
>
> 1. Set the **User** filter to a team member, or read the
>    department breakdown on Insights.
> 2. Switch the drill-down between device and user while staying
>    filtered, the breakdowns stay populated.
> 3. Sanction the tools the team genuinely needs and onboard the one
>    handling sensitive data.

> **Bring a discovered service under full inspection**
>
> 1. **Onboard as app** on the row. An App is created and linked.
> 2. Configure thresholds, custom PII rules, and tool policy on the
>    new App, see [Apps](https://docs.blindsight.io/runtime-security/apps.md).
> 3. Add an `inspect` host rule for the hostname pointing at that
>    App, in **Endpoint policy → AI host rules**.
> 4. Confirm events start arriving with `source=agent` in
>    [Observability](https://docs.blindsight.io/runtime-security/observability.md).

> **Prove coverage to an auditor**
>
> 1. Export the full report with **Anonymize** on if the audience
>    should not see identities.
> 2. Pair it with the audit trail export for the same period, which
>    carries the decisions and who made them.
> 3. The methodology section states the detection limits explicitly,
>    which is usually the auditor's first question.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.