Back to skill

Security audit

model-inventory

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed local AI-CLI inventory tool; it collects sensitive account/model metadata but does not steal secrets, install backdoors, or perform hidden actions.

Install only if you are comfortable with a tool mapping your local AI CLIs, credential-presence signals, configured/default models, and verified model access. Use a quick scan when you want local-only detection, and treat ~/.claude/model-inventory.json as sensitive because other local tools may read it.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Findings (1)

other

Note
Location
scripts/scan.sh:54
Finding

Sensitive AI Tooling and Authentication Posture Reconnaissance

Content
View full analysis
/dev/null; then printf 'likely-authenticated|oauthAccount present in ~/.claude.json'; return fi printf 'unknown|no credentials file, oauthAccount, or env key found' } auth_codex() { local out out=$(run_to codex login status) case "$out" in *"ot logged in"*) printf 'unauthenticated|codex login status: %s' "$out" | head -c 250; return ;; *"ogged in"*) printf 'likely-authenticated|codex login status: %s' "$out" | head -c 250; return ;; esac if [ -f "$HOME/.codex/auth.json" ]; then printf 'likely-authenticated|~/.codex/auth.json exists'; return; fi if [ -n "${OPENAI_API_KEY:-}" ]; then printf 'likely-authenticated|env OPENAI_API_KEY is set'; return; fi printf 'unknown|login status inconclusive; no auth.json or env key' } auth_gemini() { if [ -n "${GEMINI_API_KEY:-}" ]; then printf 'likely-authenticated|env GEMINI_API_KEY is set'; return; fi if [ -n "${GOOGLE_API_KEY:-}" ]; then printf 'likely-authenticated|env GOOGLE_API_KEY is set'; return; fi if [ -f "$HOME/.gemini/oauth_creds.json" ]; then printf 'likely-authenticated|~/.gemini/oauth_creds.json exists'; return; fi printf 'unknown|no env key or oauth_creds.json found' } auth_copilot() { if [ -d "$HOME/.copilot" ]; then printf 'unknown|~/.copilot config dir present; live probe needed to confirm'; return; fi printf 'unknown|no auth signal found' } auth_opencode() { if ...[truncated 5981 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (22)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The code partially matches the broad scanning theme but materially underdelivers on key declared behavior. The description promises a full inventory workflow with three evidence tiers, including live one-line model probes as the ground truth for whether an account is active and which models are usable, plus caching the result to a specific file with routing chains for downstream consumers. This script explicitly states it is only tier 1-2 detection, spends zero tokens, and leaves tier-3 live probing to the caller. For most CLIs it only checks binary presence, --version, credential-file/env-var heuristics, and local config for default model; the listed models are merely seeded as unverified placeholders. Only Ollama gets actual verification via ollama list. Additionally, the script prints JSON to stdout and never writes the declared cache file or any role-based routing structure. There is also an extra scanned CLI (qwen) not mentioned in the declared description. These are material description-versus-behavior differences, so this should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 23)May include surrounding context.

md
| 1 `installed` | `scripts/scan.sh`: `command -v` + `--version` | zero tokens | the binary exists |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 34)May include surrounding context.

md
| 1 `installed` | `scripts/scan.sh`: `command -v` + `--version` | zero tokens | the binary exists |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 59)May include surrounding context.

md
| 1 `installed` | `scripts/scan.sh`: `command -v` + `--version` | zero tokens | the binary exists |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 67)May include surrounding context.

md
| 1 `installed` | `scripts/scan.sh`: `command -v` + `--version` | zero tokens | the binary exists |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 88)May include surrounding context.

md
| 1 `installed` | `scripts/scan.sh`: `command -v` + `--version` | zero tokens | the binary exists |

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

The skill explicitly instructs scan logic to inspect credential-bearing locations such as ~/.claude/.credentials.json and auth-related fields in ~/.claude.json. Even if the stated purpose is only heuristic presence checks, touching credential stores increases exposure risk because future implementations may over-read, mishandle, or log sensitive authentication material, and the skill is designed to enumerate account state across providers.

Content

Scanner excerpt · references/cli-registry.md (reported line 37)May include surrounding context.

md
## claude (Claude Code)

- **Invocation for consumers:** `agent-tool` — sub-agents spawned via the Agent tool ride the current session's auth; probes here verify the *plan* (e.g. is fable included), not connectivity.
- **Auth heuristics (scan.sh):** env `ANTHROPIC_API_KEY` → `~/.claude/.credentials.json` (Windows/Linux) → `oauthAccount` in `~/.claude.json` (covers macOS Keychain storage).
- **Seed models:** the stable tier aliases `haiku sonnet opus fable` — never dated model ids; aliases resolve at spawn time and don't rot.
- **Probe:** `claude -p "Reply with exactly: ok" --model <alias>`

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

Scanner excerpt · references/cli-registry.md (reported line 44)May include surrounding context.

md
## codex (OpenAI Codex CLI)

- **Auth heuristics:** `codex login status` output → `~/.codex/auth.json` → env `OPENAI_API_KEY`.
- **Default model:** `model =` in `~/.codex/config.toml`; probe banner prints a `model: ...` session line.
- **Seed models:** `default` only — bash workers just need "the CLI works"; add explicit `-m <id>` probes only if the user asks for a specific model.
- **Probe:** `codex exec --skip-git-repo-check "Reply with exactly: ok"`

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

Scanner excerpt · scripts/scan.sh (reported line 111)May include surrounding context.

sh
## codex (OpenAI Codex CLI)

- **Auth heuristics:** `codex login status` output → `~/.codex/auth.json` → env `OPENAI_API_KEY`.
- **Default model:** `model =` in `~/.codex/config.toml`; probe banner prints a `model: ...` session line.
- **Seed models:** `default` only — bash workers just need "the CLI works"; add explicit `-m <id>` probes only if the user asks for a specific model.
- **Probe:** `codex exec --skip-git-repo-check "Reply with exactly: ok"`

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

Scanner excerpt · references/cli-registry.md (reported line 51)May include surrounding context.

md
## gemini (Gemini CLI)

- **Auth heuristics:** env `GEMINI_API_KEY` → env `GOOGLE_API_KEY` → `~/.gemini/oauth_creds.json`.
- **Default model:** `"model"` key in `~/.gemini/settings.json`; note gemini silently falls back pro→flash under quota pressure, so config ≠ guaranteed.
- **Seed models:** `default`.
- **Probe:** `gemini -p "Reply with exactly: ok"` (specific model: add `-m <id>`)

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

Checking for ~/.claude/.credentials.json is credential-related file access, and even existence-based probing leaks sensitive information about whether the user is authenticated with a provider. In this skill, the data is intentionally aggregated into an inventory cache for downstream automation, which increases the privacy and account-enumeration risk if the cache or output is exposed.

Content

Scanner excerpt · scripts/scan.sh (reported line 49)May include surrounding context.

sh
auth_claude() {
  if [ -n "${ANTHROPIC_API_KEY:-}" ]; then printf 'likely-authenticated|env ANTHROPIC_API_KEY is set'; return; fi
  if [ -f "$HOME/.claude/.credentials.json" ]; then printf 'likely-authenticated|~/.claude/.credentials.json exists'; return; fi
  if [ -f "$HOME/.claude.json" ] && grep -q '"oauthAccount"' "$HOME/.claude.json" 2>/dev/null; then
    printf 'likely-authenticated|oauthAccount present in ~/.claude.json'; return
  fi

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

The script reads ~/.gemini/settings.json to infer a default model, which is direct access to an agent-specific configuration file. In the context of an inventory skill, this creates privacy and information-disclosure risk because it inspects local state beyond mere installation detection and may expose user configuration choices to downstream consumers via the generated cache.

Content

Scanner excerpt · scripts/scan.sh (reported line 105)May include surrounding context.

sh
case $1 in
    opencode) cfg_model "$HOME/.config/opencode/opencode.json" "~/.config/opencode/opencode.json" && return ;;
    qwen)     cfg_model "$HOME/.qwen/settings.json" "~/.qwen/settings.json" && return ;;
    gemini)   cfg_model "$HOME/.gemini/settings.json" "~/.gemini/settings.json" && return ;;
    copilot)  cfg_model "$HOME/.copilot/config.json" "~/.copilot/config.json" && return ;;
    claude)   cfg_model "$HOME/.claude/settings.json" "~/.claude/settings.json" && return ;;
    codex)

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

The script reads ~/.gemini/settings.json to infer a default model, which is direct access to an agent-specific configuration file. In the context of an inventory skill, this creates privacy and information-disclosure risk because it inspects local state beyond mere installation detection and may expose user configuration choices to downstream consumers via the generated cache.

Content

Scanner excerpt · scripts/scan.sh (reported line 105)May include surrounding context.

sh
case $1 in
    opencode) cfg_model "$HOME/.config/opencode/opencode.json" "~/.config/opencode/opencode.json" && return ;;
    qwen)     cfg_model "$HOME/.qwen/settings.json" "~/.qwen/settings.json" && return ;;
    gemini)   cfg_model "$HOME/.gemini/settings.json" "~/.gemini/settings.json" && return ;;
    copilot)  cfg_model "$HOME/.copilot/config.json" "~/.copilot/config.json" && return ;;
    claude)   cfg_model "$HOME/.claude/settings.json" "~/.claude/settings.json" && return ;;
    codex)

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

The script reads ~/.claude/settings.json to determine a default model, which is another direct inspection of agent configuration data in the user's home directory. In this skill's context, that is more concerning because the broader skill is designed to aggregate and cache provider/account availability, so local preference data can become part of a centralized inventory consumed by other agents.

Content

Scanner excerpt · scripts/scan.sh (reported line 107)May include surrounding context.

sh
qwen)     cfg_model "$HOME/.qwen/settings.json" "~/.qwen/settings.json" && return ;;
    gemini)   cfg_model "$HOME/.gemini/settings.json" "~/.gemini/settings.json" && return ;;
    copilot)  cfg_model "$HOME/.copilot/config.json" "~/.copilot/config.json" && return ;;
    claude)   cfg_model "$HOME/.claude/settings.json" "~/.claude/settings.json" && return ;;
    codex)
      if [ -f "$HOME/.codex/config.toml" ]; then
        m=$(grep -E '^[[:space:]]*model[[:space:]]*=' "$HOME/.codex/config.toml" 2>/dev/null | head -n 1 | sed -e 's/.*=[[:space:]]*//' -e 's/^"//' -e 's/"[[:space:]]*$//')

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

The script reads ~/.claude/settings.json to determine a default model, which is another direct inspection of agent configuration data in the user's home directory. In this skill's context, that is more concerning because the broader skill is designed to aggregate and cache provider/account availability, so local preference data can become part of a centralized inventory consumed by other agents.

Content

Scanner excerpt · scripts/scan.sh (reported line 107)May include surrounding context.

sh
qwen)     cfg_model "$HOME/.qwen/settings.json" "~/.qwen/settings.json" && return ;;
    gemini)   cfg_model "$HOME/.gemini/settings.json" "~/.gemini/settings.json" && return ;;
    copilot)  cfg_model "$HOME/.copilot/config.json" "~/.copilot/config.json" && return ;;
    claude)   cfg_model "$HOME/.claude/settings.json" "~/.claude/settings.json" && return ;;
    codex)
      if [ -f "$HOME/.codex/config.toml" ]; then
        m=$(grep -E '^[[:space:]]*model[[:space:]]*=' "$HOME/.codex/config.toml" 2>/dev/null | head -n 1 | sed -e 's/.*=[[:space:]]*//' -e 's/^"//' -e 's/"[[:space:]]*$//')

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

Scanner excerpt · scripts/scan.sh (reported line 109)May include surrounding context.

sh
copilot)  cfg_model "$HOME/.copilot/config.json" "~/.copilot/config.json" && return ;;
    claude)   cfg_model "$HOME/.claude/settings.json" "~/.claude/settings.json" && return ;;
    codex)
      if [ -f "$HOME/.codex/config.toml" ]; then
        m=$(grep -E '^[[:space:]]*model[[:space:]]*=' "$HOME/.codex/config.toml" 2>/dev/null | head -n 1 | sed -e 's/.*=[[:space:]]*//' -e 's/^"//' -e 's/"[[:space:]]*$//')
        if [ -n "$m" ]; then printf '%s|model= in ~/.codex/config.toml' "$m"; return; fi
      fi ;;

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
87% confidence
Finding

Reading ~/.codex/config.toml to extract the configured model is access to agent config data stored in the user's home directory. While the script appears to read only a model setting, this still crosses a trust boundary because agent config files can contain sensitive operational preferences or additional metadata, and the access occurs as part of an inventory scan that may be invoked broadly.

Content

Scanner excerpt · scripts/scan.sh (reported line 110)May include surrounding context.

sh
claude)   cfg_model "$HOME/.claude/settings.json" "~/.claude/settings.json" && return ;;
    codex)
      if [ -f "$HOME/.codex/config.toml" ]; then
        m=$(grep -E '^[[:space:]]*model[[:space:]]*=' "$HOME/.codex/config.toml" 2>/dev/null | head -n 1 | sed -e 's/.*=[[:space:]]*//' -e 's/^"//' -e 's/"[[:space:]]*$//')
        if [ -n "$m" ]; then printf '%s|model= in ~/.codex/config.toml' "$m"; return; fi
      fi ;;
  esac

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Reading ~/.codex/config.toml to extract the configured model is access to agent config data stored in the user's home directory. While the script appears to read only a model setting, this still crosses a trust boundary because agent config files can contain sensitive operational preferences or additional metadata, and the access occurs as part of an inventory scan that may be invoked broadly.

Content

Scanner excerpt · scripts/scan.sh (reported line 110)May include surrounding context.

sh
claude)   cfg_model "$HOME/.claude/settings.json" "~/.claude/settings.json" && return ;;
    codex)
      if [ -f "$HOME/.codex/config.toml" ]; then
        m=$(grep -E '^[[:space:]]*model[[:space:]]*=' "$HOME/.codex/config.toml" 2>/dev/null | head -n 1 | sed -e 's/.*=[[:space:]]*//' -e 's/^"//' -e 's/"[[:space:]]*$//')
        if [ -n "$m" ]; then printf '%s|model= in ~/.codex/config.toml' "$m"; return; fi
      fi ;;
  esac

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill directs live probes of installed AI CLIs to verify account/model availability, which necessarily transmits prompts or metadata to third-party services. Without an explicit privacy and network-transmission warning, users may not realize that verification goes beyond local inspection and could disclose machine usage patterns, account presence, model entitlements, or probe text to providers.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
91% confidence
Finding

The skill creates a durable inventory file in the user's home directory containing installed CLIs, auth-status evidence, usable models, and routing preferences for future agent runs. That persistence can leak sensitive operational metadata across sessions, be consumed by other tools without fresh consent, and become stale in ways that influence later agent behavior.

Content

Scanner excerpt · SKILL.md (reported line 37)May include surrounding context.

md
1. **Tiers 1–2 — run the scan.** Execute `scripts/scan.sh` (bash; runs on Git Bash/macOS/Linux) and show the user the per-CLI result. Zero tokens spent, nothing sent anywhere.
2. **Tier 3 — probe, unless the user said "quick scan".** For each installed CLI, run the probe command from [references/cli-registry.md](references/cli-registry.md) once per seed model (claude: all four aliases; other CLIs: `default` only) and classify by the table there: `verified` / `unavailable` / `blocked-by-auth` / `quota-exhausted` / `unknown`. A login error flips the CLI's `auth.status` to `unauthenticated` and marks all its models `blocked-by-auth` — the "installed but account not active" case, with the error line quoted. A timeout is `unknown`, never `unavailable`. One attempt per model; retry once only after changing one named thing; second failure → record `unknown` with the quoted error and move on. Ollama needs no probe — `ollama list` already verified its models locally.
3. **Build the routing table** per the rules below, from probe results only.
4. **Write `~/.claude/model-inventory.json`** (schema below), then report: a per-CLI table (version, auth status, each model's status with evidence), what was probed vs. assumed, and total probe cost. Zero usable CLIs is a valid outcome — write the inventory anyway so consumers see an honest empty rather than a missing file.

## Routing rules

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script inspects sensitive authentication signals such as API-key environment variables and local credential files to infer login state, but it does so automatically and without any explicit user confirmation or minimization boundary. Even though it does not print secret values, this is still security-sensitive data collection because it reveals the presence of credentials and account linkage across multiple AI providers.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill explicitly instructs writing a persistent file under ~/.claude/model-inventory.json, which modifies the user's home directory and creates session-persistent state. While not inherently malicious, doing so without an explicit warning/consent step can surprise users, leave stale metadata behind, and expose local environment details to other tools that read the file later.

Content

No source excerpt is available for this finding.