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

# Inventory & Risk Scoring

> What the Guardway CLI detects on an endpoint, the risk levels, the two scoring engines, the offline evasion-resistant passes, and how vet verdicts map.

## What this is for

This page explains what `gw-cli discover` finds on a machine and how each artifact is scored. The inventory is broad — the whole agent extension surface, not just skills — and the scoring is layered: a primary engine, plus offline augmentation passes designed to catch the evasion techniques that beat file-only scanners.

## The inventory surface

`discover --deep` walks the machine and records every AI artifact it finds:

| Category | What it covers |
| - | - |
| **AI tools / apps** | Desktop apps, CLIs, and editor extensions — Claude Code, Claude Desktop, Cursor, Codex, Gemini CLI, GitHub Copilot, Cline, Continue, Goose, Amazon Q, and many more. |
| **Accounts** | For each tool, whether the signed-in account is **corporate** or **personal**, from the tool's own sign-in. See [Signed-in accounts](#signed-in-accounts). |
| **Agent projects** | Folders that carry agent configuration — skills, MCP configs, and add-ons. |
| **Skills** | `SKILL.md` skills, scored individually and grouped by project. |
| **MCP servers** | Registered MCP server configs. |
| **Commands** | Slash/command definitions. |
| **Hooks** | Lifecycle hooks that run shell on agent events. |
| **Subagents** | Delegated agents and the tools they're granted. |
| **Plugins** | Packaged extensions. |

## Risk levels

Every scored artifact is normalized to one of five levels, ordered lowest to highest:

| Level | Meaning |
| - | - |
| **None** | No risky patterns detected. |
| **Low** | Only minor findings. |
| **Medium** | Some risky patterns worth a review. |
| **High** | High-risk behavior — flagged. |
| **Critical** | Secret-exfiltration, destructive, or injection patterns — flagged. |

**High** and **Critical** are the *flagged* levels — the ones the dashboard badges and `vet` blocks on by default.

## Scoring engines

`gw-cli` scores with one of two engines. It auto-detects which is available and prints the active engine in its output.

<Tabs>
  <Tab title="SkillSpector (recommended)">
    NVIDIA **SkillSpector** — a thorough analysis engine. When present on the machine, `gw-cli` uses it automatically. Install it once:

    ```sh theme={null}
    curl -LsSf https://astral.sh/uv/install.sh | sh
    uv tool install --python 3.12 git+https://github.com/NVIDIA/skillspector.git
    gw-cli discover --deep      # now scores with engine = SkillSpector
    ```

    A thorough engine can emit *hundreds* of findings per artifact — use `gw-cli vet ... --summary` for a per-category digest instead of the full per-line dump.
  </Tab>

  <Tab title="Built-in (default)">
    A built-in heuristic rule engine that runs with **zero network** and no dependencies. It deliberately **over-flags** — it favors false positives over misses — so it's a safe default but noisier than SkillSpector. This is what `--air-gap` forces.
  </Tab>
</Tabs>

MCP configs are always scored by a **config-aware analyzer** (reliable on JSON) rather than the skill engine — it flags hardcoded secrets in `env`, non-TLS `http://` endpoints, and shell-launch commands. Hooks and commands are scored with shell + network heuristics; subagents are flagged for overly broad tool grants.

## Offline augmentation

On top of the primary engine, **every** scan record runs through offline augmentation passes. These counter the techniques research has shown beating file-only scanners (including SkillSpector), and they need no network:

| Code | What it catches |
| - | - |
| **`IOC-KNOWN`** | Exact match of a disclosed campaign indicator → escalated to **Critical**. |
| **`PADDING`** | An oversized instruction file with a low-entropy tail — a size-cap evasion trick. |
| **`HIDDEN-UNICODE`** | Strips zero-width, Tag, and bidirectional codepoints, then re-scans the de-obfuscated text. |

<Note>
  So a hardcoded token in an MCP config, a `curl … | bash` hidden with invisible characters, or a known malicious indicator all surface as findings — even against an artifact crafted to slip past a plain file scan.
</Note>

## External-reference index

Beyond flagging suspicious links, the scanner builds a **typed, persisted index** of every external resource an artifact points the agent at — the durable graph the drift watcher diffs and a future network trust-scorer will enrich. Each reference records its **kind** (URL, repository, npm/PyPI package, release download, remote skill/instructions, paste host, wallet address), a coarse **host class** (vendor, code host, registry, paste, free-tier/throwaway, IP), its **version spec**, and whether it is **pinned** to an exact version/tag/commit. Only the host/package identity and version metadata are stored — never a raw URL that might carry a token.

The offline **external-reference classifier** turns high-signal references into findings:

| Code | What it catches |
| - | - |
| **`EXT-REMOTE-SKILL`** | Fetches a remote `SKILL.md` / instructions file the agent will follow. |
| **`EXT-PASTE`** | References a paste/snippet host (rentry, pastebin, glot, …). |
| **`EXT-RELEASE`** | Downloads a release/binary artifact. |
| **`EXT-LOOKALIKE`** | A brand-lookalike domain (edit-distance 1 from a known vendor). |
| **`EXT-TYPOSQUAT`** | An npm/PyPI package that typosquats a popular one. |

## Post-approval drift

An artifact that scored clean can be edited — or silently auto-updated — into something malicious *after* you first trusted it (a rug-pull / TOCTOU). On every scan the mutation watcher diffs the fresh record against the **last-stored (approved) baseline** for that path and raises drift findings:

| Code | What it catches |
| - | - |
| **`DRIFT-NEW-REF`** | The artifact added an external reference it did not have before — a new host, package, paste, remote skill, or wallet. A new paste/remote-skill/wallet reference is **High**. |
| **`DRIFT-LOST-PIN`** | A reference that used to be pinned to an exact version dropped its pin and now floats — the classic "install `pkg@1.2.3`, later float to a malicious release." **High**. |
| **`DRIFT-ESCALATION`** | The artifact's overall risk rose since the baseline. |

This is the on-endpoint-detectable half of the flagship supply-chain attack (CVE-2025-54136). `discover` prints a one-line summary (`Post-approval drift: N change(s)…`) when anything drifted.

## Install-lifecycle & CI-workflow analysis

The highest-severity confirmed payloads often hide in install plumbing rather than the skill body. A dedicated pass inspects each artifact's files:

| Code | What it catches |
| - | - |
| **`LIFECYCLE-FETCH-EXEC`** | Remote content piped into an interpreter (`curl … \| bash`, `bash -c "$(curl …)"`, `iwr … \| iex`) in a script or "prerequisite" block. **High**. |
| **`CI-FETCH-EXEC`** | The same fetch-exec inside a GitHub Actions workflow or `action.yml`. **Critical**. |
| **`NPM-LIFECYCLE-FETCH`** | A `preinstall` / `install` / `postinstall` script in `package.json` that fetches remote content on install. **Critical**. |
| **`CI-UNTRUSTED-CHECKOUT`** | A `pull_request_target` workflow that checks out untrusted PR code. **High**. |
| **`CI-INJECTION`** | Untrusted `${{ github.event.* }}` data interpolated into a `run:` shell step. **High**. |
| **`INSECURE-DESERIALIZE`** | `pickle.loads` / `marshal.loads` / `yaml.load` without a safe loader. **Medium**. |

## Metadata, posture & MCP scope

Three more offline passes catch risks that live in the *declaration* and *environment* around a skill rather than its code:

| Code | What it catches |
| - | - |
| **`META-MISSING`** | A `SKILL.md` with no frontmatter, or missing the `name` / `description` identity fields the platform expects — the signature of a skill ported from another format with its metadata stripped. |
| **`META-MISMATCH`** | The declared tool list omits shell execution, but the body runs shell — the manifest understates what the skill does. |
| **`META-UNDECLARED-NET`** | The description discloses no network use, but the body runs egress commands (`curl`, `wget`, `iwr`, raw sockets). |
| **`POSTURE-BYPASS`** | An agent settings file disables permission prompts (`bypassPermissions`) — every skill runs unattended. |
| **`POSTURE-ALLOW-ALL`** | A wildcard shell allowlist (`Bash(*)`, `*`) pre-approves arbitrary commands. |
| **`POSTURE-HOOK`** | An auto-run lifecycle hook pipes a download into a shell, evals, elevates, or deletes recursively. |
| **`MCP-EXFIL`** | A filesystem MCP server granted a root of `/`, `~`, or a whole home directory — broad read paired with the agent's network reach is the minimum exfiltration kit. |

## Skills that ship with an AI tool

Some AI tools install skills of their own, for example Anthropic's `docx`, `xlsx` and `pptx`
skills in Claude Desktop. Scored like any downloaded skill, they would read High or Critical on
every machine that runs the tool. Guardway tells them apart, but location alone never quiets a
skill: a modified copy in a vendor's folder is exactly where an attacker would hide one. The
folder says which tool ships the skill; the skill's content hash decides how it is scored.

| Tool | Folder it ships skills into |
| - | - |
| **Claude Desktop** | Its Cowork skills cache, and the copies it syncs to `~/.claude/skills/synced/` |
| **Codex** | `~/.codex/skills/.system` |
| **Cursor** | `~/.cursor/skills-cursor` |
| **Antigravity** | `~/.gemini/antigravity/builtin/skills` |
| **Grok Build** | `~/.grok/bundled/skills` |
| **Junie** | `~/.junie/versions/<build>/skills` |

Each skill in one of these folders gets one of three results:

| Code | Shown in the console as | Meaning | Scoring |
| - | - | - | - |
| **`VENDOR-SKILL-VERIFIED`** | Shipped with *tool* · verified | The content matches, byte for byte, a release of the tool that Guardway verified. | Capped at **Low**. Its other findings stay visible as information. When every copy across the fleet is verified, the Skills Marketplace page shows the skill as shipped with the tool and its Low-credibility distribution check as clear. |
| **`VENDOR-SKILL-CHANGED`** | *Tool* skill · changed | The tool ships a skill by this name, but this content matches none of its known releases: a newer release not verified yet, or a modified copy. | At least **Medium**. The console raises it to **High** when only this machine has that content while other machines run the skill, and notes "likely a new release" when many machines share it. |
| **`VENDOR-SKILL-SHIPPED`** | In *tool*'s folder · not verified | The skill is in the tool's folder, but its name is not one the tool is known to ship. | Scored like any other skill. |

A skill with the same name in any other folder, such as `~/.claude/skills/xlsx`, is scored like
any other skill. Line endings are ignored when hashing, so the same release matches on macOS,
Linux and Windows.

**How the list of known releases stays current.** The agent carries a built-in list, and it pulls
a signed list from the console that adds new releases without an agent update. A release joins
the signed list when the same content is seen in the tool's own folder on at least 10 machines
across at least 3 organizations, counting only organizations older than 30 days and machines older
than 7 days. Agents pick up a new list within 6 hours.

## Signed-in accounts

For each AI tool, the agent reads the tool's own sign-in, read-only, and says whether the account
is **corporate**, **personal** or **unknown**. It keeps only the email's **domain** (never the
full address), the plan name and how the tool signed in. Tokens and API keys are never kept, and a
sign-in the tool encrypts is never read.

| Tool | Read from | Corporate when | Personal when |
| - | - | - | - |
| **Claude Code** | `~/.claude.json` | Team or Enterprise plan, an assigned seat, or a company email domain | Free, Pro or Max plan with a consumer email domain |
| **Claude Desktop** | Its `config.json`: the account it last signed in to | Same rules as Claude Code, when it is the same account as Claude Code | Same rules as Claude Code |
| **Cursor** | Cursor's local state | Business, Team or Enterprise plan, or a company email domain | Free, Pro or Pro+ plan with a consumer email domain |
| **Codex / ChatGPT** | `~/.codex/auth.json` | ChatGPT Team, Enterprise, Business or Edu plan, or a company email domain | Free, Plus or Pro plan with a consumer email domain |
| **Gemini CLI** | `~/.gemini/oauth_creds.json` | A Google Workspace account, or a company email domain | A consumer Google account |
| **Antigravity** | Its Google sign-in in `~/.gemini/` | A Google Workspace account, or a company email domain | A consumer Google account |
| **Kiro** | `~/.aws/sso/cache/kiro-auth-token.json` | Signed in through the company's IAM Identity Center or identity provider | Signed in with Google, GitHub or an AWS Builder ID |
| **GitHub Copilot** | GitHub CLI and Copilot sign-ins | Signed in to a GitHub Enterprise host | Not decided: a github.com username alone does not tell a company account from a personal one |
| **Grok Build** | `~/.grok/auth.json` | The company's own sign-in (SSO), a Team principal, or a company email domain | A consumer email domain |
| **Devin Desktop** | Devin's local state: the last sign-in email | A company email domain | A consumer email domain |
| **OpenCode** | The OpenCode console sign-in in `opencode.db` | A company email domain | A consumer email domain |
| **Junie** | Junie's own log: the sign-in kind and licence (no email) | A JetBrains Enterprise sign-in or licence | Not decided: Junie keeps the account itself in the keychain |

**Unknown** means the tool is signed in but nothing in its sign-in decides the question, for
example a Codex sign-in with an API key, which carries no account.

**Claude Desktop** keeps its sign-in encrypted, so the agent reads only which account it last
signed in to. When that is Claude Code's account, Claude Code's identity is shown for both. When it
is a different account, Claude Desktop shows as signed in with no identity.

**Junie** keeps its sign-in in the operating system's keychain, which the agent never reads. Its
own log says whether it is signed in, how (JetBrains Account, JetBrains Enterprise, a Junie API key
or your own provider key) and the licence; that is all Junie's row shows.

In the console's Tools inventory, **No sign-in** means the agent read the tool's sign-in and found
none; **Not checked** means the agent does not read that tool's sign-in at all (for example VS Code
or Slack).

**Kiro** records no email, so its rows show no domain. Its plan (Free, Pro, Pro+ or Power) comes
from the account's monthly credit limit.

## OWASP Agentic Skills Top 10

Every rule Guardway raises is tagged with the [OWASP Agentic Skills Top 10](https://owasp.org/www-project-agentic-skills-top-10/top10) item it detects (AST01–AST10), and the CLI + dashboards compute a **compliance level** per machine from those findings. Guardway has **detection-side coverage of all ten items** — it detects and reports; it never blocks or sandboxes.

| Item | What it covers | Example rules |
| - | - | - |
| **AST01** Malicious Skills | credential stealers, reverse shells, injection | `NET1`, `E1`, `COMBO`, `PI1`, `SH1`, `IOC-KNOWN` |
| **AST02** Supply Chain | typosquats, look-alikes, unsigned releases | `EXT-TYPOSQUAT`, `EXT-LOOKALIKE`, `RP*`, `CI-*` |
| **AST03** Over-Privilege | over-broad skill / MCP scope | `MCP1`, `MCP-EXFIL`, `CRED`, `LP*` |
| **AST04** Insecure Metadata | understated / mismatched manifests | `META-MISMATCH`, `META-UNDECLARED-NET` |
| **AST05** External Instructions | mutable remote content the skill follows | `EXT-REMOTE-SKILL`, `EXT-PASTE` |
| **AST06** Weak Isolation | no sandbox / bypassed prompts | `POSTURE-BYPASS`, `POSTURE-ALLOW-ALL`, `MCP-SHELL` |
| **AST07** Update Drift | silent post-approval mutation | `DRIFT-NEW-REF`, `DRIFT-LOST-PIN`, `DRIFT-ESCALATION` |
| **AST08** Scanner Evasion | padding, hidden unicode, obfuscation | `PADDING`, `HIDDEN-UNICODE`, `OB1` |
| **AST09** Governance | no inventory / approval / audit | `GOV-UNAPPROVED` (see below) |
| **AST10** Cross-Platform Reuse | ported skill missing its metadata | `META-MISSING` |

### Compliance scoring

Each item is scored from the findings present on the machine:

| Status | Meaning |
| - | - |
| **PASS** | no finding maps to this item |
| **ATTENTION** | only minor findings map (severity \< 25) |
| **FAIL** | at least one serious finding maps (severity ≥ 25) |

A machine's **compliance %** = (PASS = 1 · ATTENTION = 0.5 · FAIL = 0) across the ten items ÷ 10. `gw-cli scan` prints each finding's AST tag (e.g. `META-UNDECLARED-NET … (AST04)`); the [local dashboard](/endpoint-ai-risk/agent/dashboard) shows an OWASP panel; the Guardway console rolls it up across the fleet.

<Note>
  **AST vs ASI — two different OWASP frameworks.** The endpoint side (this CLI) maps to the **Agentic Skills Top 10 (AST)** — threats in installed skills **at rest**. The platform **[Agents](/platform/agents)** page maps to the **Agentic Security Initiative (ASI)** — threats in a **running agent**. They are complementary, not the same list: `AST07` Update Drift and `AST09` Governance have no runtime equivalent; `ASI06` Memory Poisoning and `ASI10` Rogue Agents have no static-skill equivalent. AST is the risk *at rest* (the leading indicator); ASI is the *live exploitation* — e.g. an over-privileged skill (`AST03`) is what a running agent later abuses (`ASI03`).
</Note>

### Governance (AST09)

Inventory only governs if new arrivals are surfaced. Run [`gw-cli approve`](/endpoint-ai-risk/agent/cli-reference#approve) after reviewing a `discover` run to record the current skills, commands, subagents, and MCP configs as the **approved baseline** (path + content hash → `<data-dir>/approved.json`). From then on `discover` flags anything **new** or **changed** outside that baseline:

| Code | What it catches |
| - | - |
| **`GOV-UNAPPROVED`** | An artifact that appeared or changed outside the approval flow — even if its content scans clean, because nobody approved it. |

Governance is opt-in and local — no baseline file, no findings. Until you run `approve`, **AST09** reads as **ATTENTION** ("no approval baseline"); a baseline with no violations makes it **PASS**.

## Vet verdicts

`gw-cli vet` collapses an artifact's overall risk into a single headline verdict word plus one-line advice. The mapping:

| Overall risk | Verdict | Advice |
| - | - | - |
| **Critical / High** | **DO NOT INSTALL** | High-risk behavior found. Do not install without a careful manual review. |
| **Medium** | **REVIEW FIRST** | Some risky patterns found. Review the flagged artifacts before installing. |
| **Low** | **LIKELY OK** | Only minor findings. Skim the flagged lines, then it's likely safe. |
| **None** | **CLEAN** | No risky patterns detected. Still review the code before granting access. |

The process exits **non-zero at or above `--fail-on`** (default `high`), so you can gate an install:

```sh theme={null}
gw-cli vet owner/repo && echo "clone + install…"    # only proceeds if the vet passed
```

## Limits

* The built-in engine over-flags by design; install SkillSpector for production-grade scoring.
* Detection is **static** — it inspects files, it does not execute them. Drift detection catches the *local* mutation of an approved artifact (the on-endpoint half of a TOCTOU/rug-pull); confirming that a *remote* URL's served content has flipped, or judging live runtime intent, requires the network and is out of scope for on-endpoint static analysis.
* Drift needs a baseline: the **first** scan of an artifact establishes it, so drift findings appear from the **second** scan onward. Keep the inventory fresh (see `schedule`) so the baseline stays current.
* On Windows, some app-config paths (e.g. the Claude desktop app under `%APPDATA%`) are still being added; Claude Code and project-folder artifacts are covered today.

## Related

* [CLI Reference](/endpoint-ai-risk/agent/cli-reference) — `discover`, `scan`, and `vet` flags.
* [Local Dashboard](/endpoint-ai-risk/agent/dashboard) — where these findings are shown.
* [Overview](/endpoint-ai-risk/agent/overview) — install and the end-to-end flow.


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