Back to skill

Security audit

Model-Selector

Security checks for vulnerabilities and agentic risk

Overview

This model-routing skill broadly matches its stated purpose, but it automatically stores full user prompts locally without clear notice, consent, access controls, or an opt-out.

Review before installing. Do not use this skill with secrets, credentials, proprietary text, or personal data unless you are comfortable with prompts being saved locally in plaintext. Prefer disabling or removing full-query logging, adding explicit opt-in and deletion controls, and pinning dependencies before production use.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/model_router.py:110
Finding

Full User Queries Stored in Plaintext Without Explicit Consent or Access Hardening

Content
View full analysis

Vulnerability Details

File Location: scripts/model_router.py, lines 110-132
Vulnerability Type: Plaintext sensitive-data retention
Risk Level: Medium

Vulnerable Code:

python
def _log_query(self, query, tier):
    """Logs the query for future keyword refinement."""
    try:
        history = []
        if os.path.exists(self.history_file):
            with open(self.history_file, 'r', encoding='utf-8') as f:
                try:
                    history = json.load(f)
                except:
                    history = []
        
        history.append({"query": query, "tier": tier, "timestamp": os.path.getmtime(self.history_file) if os.path.exists(self.history_file) else 0})
        
        # Keep only last 1000 queries
        if len(history) > 1000:
            history = history[-1000:]
            
        with open(self.history_file, 'w', encoding='utf-8') as f:
            json.dump(history, f, ensure_ascii=False, indent=2)
    except Exception as e:
        pass

Technical Analysis

Every call to route() invokes _log_query(), which appends the complete query to a local JSON file. Queries can contain credentials, source code, personal information, financial data, or proprietary business content. The implementation neither redacts sensitive values nor encrypts the stored content. It also creates the history file using default process permissions rather than explicitly restricting it to the owning user.

Retention is limited to 1,000 entries, but this still permits a substantial quantity of sensitive prompt data to accumulate. The documented rolling-adjustment feature does not clearly disclose that full query text is automatically retained, and the implementation provides no explicit consent, opt-out, or deletion mechanism.

Attack Path

  1. A user submits a query containing sensitive information.
  2. ModelRouter.route() processes the query and au ...[truncated 907 chars]
Remediation
View remediation

Remediation Suggestions

  • Disable full-query logging by default and require an explicit configuration option and informed user consent.
  • Store only the minimum routing metadata needed for refinement, such as tier, confidence, and anonymized aggregate features.
  • Redact credentials, API keys, access tokens, personal data, and other sensitive patterns before persistence.
  • Create the history file with owner-only permissions, such as mode 0600, and verify permissions when opening an existing file.
  • Use a configurable, short retention period and provide deletion and logging opt-out mechanisms.
  • Keep history outside source and package directories, and exclude it from version control, archives, telemetry, and backups where appropriate.
  • If complete prompts are operationally necessary, encrypt the data at rest and protect encryption keys separately.
  • Replace the blanket exception handler with controlled error reporting that does not expose prompt content.

T08 · Insecure Dependencies

Note
Location
scripts/requirements.txt:1
Finding

Unbounded Third-Party Dependency Versions Create Supply-Chain Risk

Content
View full analysis

Vulnerability Details

File Location: scripts/requirements.txt, lines 1-4
Vulnerability Type: Unpinned and unnecessarily broad dependencies
Risk Level: Low

Vulnerable Code:

text
litellm>=1.0.0
sentence-transformers>=2.2.2
torch>=2.0.0
numpy>=1.24.0

Technical Analysis

Each dependency specifies only a minimum version, allowing the package resolver to install any later release. Consequently, an installation performed after this audit may retrieve package code that was not reviewed with the project. No lockfile or package hashes are present to ensure reproducible, integrity-verified installations.

The declared litellm dependency is not used by the reviewed Python files, unnecessarily increasing the number of packages and transitive dependencies trusted by the installation. This finding does not establish that any currently named package is malicious; the risk arises from mutable resolution and an avoidably broad dependency surface.

Attack Path

  1. An operator installs the dependencies from scripts/requirements.txt.
  2. The package resolver selects versions newer than those available or reviewed when the project was published.
  3. If a selected release or transitive dependency has been compromised, contains a malicious installation hook, or introduces an exploitable vulnerability, its code is installed into the environment.
  4. Malicious or vulnerable dependency code may run during installation or when imported by the router.

Successful exploitation depends on a compromised or vulnerable dependency release or package index; no such compromise was confirmed in the audited artifact.

Impact Assessment

Dependency installation normally executes with the privileges of the user or automation account running the package manager. A malicious dependency could therefore access files, environment variables, credentials, and network resources available to that account or alter it ...[truncated 204 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove litellm unless it is required by functionality not present in the reviewed code.
  • Pin dependencies and relevant transitive dependencies to exact, reviewed versions.
  • Generate and commit a reproducible lockfile appropriate to the deployment workflow.
  • Require cryptographic hashes during installation, for example through a hash-locked requirements file and pip --require-hashes.
  • Install packages only from approved indexes over authenticated TLS connections.
  • Run dependency vulnerability and provenance checks in continuous integration.
  • Test and review dependency upgrades before updating the lockfile.
  • Perform installation and execution under a dedicated, least-privileged account or isolated environment.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill's declared behavior does not match its apparent implementation: it reportedly logs queries to a local file, lacks the promised cost-efficiency logic, and may contain broken routing code. This is dangerous because users and integrators may trust the skill with sensitive prompts under false assumptions, while undeclared persistence creates privacy and compliance risk and the broken logic can cause unsafe or unreliable model selection.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill appears to use local file read/write capabilities without declaring any tool scope or permissions boundary. Hidden file access is dangerous because it prevents operators from understanding what data the skill can persist or inspect, and in this context it may enable silent logging of user queries or other local data access beyond the advertised routing purpose.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The router stores full user queries to disk in query_history.json even though its stated purpose is only model selection. User queries can contain secrets, credentials, internal business data, or personal information, so persistent logging creates an unnecessary privacy and data-retention risk and broadens the attack surface if the file is later accessed by other local users, tools, or processes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

Queries are logged silently with no user-facing notice or consent mechanism. Because prompts often contain sensitive operational, personal, or proprietary information, undisclosed storage violates least surprise and can expose users to privacy harm if the local file is inspected, backed up, or exfiltrated.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill implements persistent collection of query history plus a later analysis/refinement workflow that is not necessary for basic routing. This expands the skill from transient inference into user-behavior collection, increasing the risk of surveillance, unintended profiling, and secondary use of sensitive prompts beyond the user's expectation of a model router.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The intent matrix embeds support for specific languages by listing only English and Chinese example phrases, effectively shaping routing behavior around those locales. There is no natural-language indication that language coverage is limited or that users can select or opt into a preferred language/locale.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The docstring claims the method will analyze history and update the intent mapping, suggesting behavior that changes routing logic. In reality, the function merely loads the history file and returns a count string, so the documentation overstates what the code does.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

This JSON stores natural-language queries in both English and Traditional Chinese, but provides no surrounding policy context about language selection or user opt-in. Because SQP-3 applies to all file types and covers language/locale policy concerns, this may indicate an undocumented multilingual behavior or dataset policy gap.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency is specified with a lower bound only, which allows future unreviewed versions to be installed and makes builds non-reproducible. In a security-sensitive skill that routes model requests, this increases supply-chain risk because a later vulnerable or malicious package release could be pulled in without code changes.

Content

Scanner excerpt · scripts/requirements.txt (reported line 1)May include surrounding context.

text
litellm>=1.0.0
sentence-transformers>=2.2.2
torch>=2.0.0
numpy>=1.24.0

Unverifiable Dependency: litellm has 16 known advisory(ies) (CVE-2024-4888 (Arbitrary file deletion in litellm); CVE-2024-2952 (LiteLLM has Server-Side Template Injection vulnerability in /completions endpoin); CVE-2026-59819 (LiteLLM: Local file read via request-supplied OIDC file references) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
93% confidence
Finding

litellm has multiple known advisories, and because the requirement is not pinned, there is no way to verify whether deployment will resolve to a safe version. In this skill's context, litellm is especially sensitive because it likely handles external prompts, model routing, and networked LLM calls, so dependency-level flaws could affect confidentiality or code/data handling.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

Using sentence-transformers>=2.2.2 permits installation of any newer release, preventing reproducible builds and weakening dependency review. While not immediately exploitable by itself, it creates a supply-chain exposure where future compromised or breaking versions may be silently adopted.

Content

Scanner excerpt · scripts/requirements.txt (reported line 2)May include surrounding context.

text
litellm>=1.0.0
sentence-transformers>=2.2.2
torch>=2.0.0
numpy>=1.24.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The unpinned torch dependency allows uncontrolled upgrades to versions that may introduce known vulnerabilities or unsafe behavior. Given that ML frameworks often process complex model artifacts and serialized data, version drift can materially increase attack surface.

Content

Scanner excerpt · scripts/requirements.txt (reported line 3)May include surrounding context.

text
litellm>=1.0.0
sentence-transformers>=2.2.2
torch>=2.0.0
numpy>=1.24.0

Unverifiable Dependency: torch has 16 known advisory(ies) (CVE-2025-2953 (PyTorch susceptible to local Denial of Service); CVE-2022-45907 (PyTorch vulnerable to arbitrary code execution); CVE-2025-32434 (PyTorch: `torch.load` with `weights_only=True` leads to remote code execution) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
92% confidence
Finding

torch has numerous published advisories, and the absence of version pinning makes it impossible to determine whether the installed package is affected. This matters more here because ML stacks frequently load models and tensors from external artifacts, so vulnerable framework versions can elevate risk beyond a normal utility library.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

numpy>=1.24.0 is not deterministic and allows later releases to be installed without explicit review. This is a classic dependency hygiene issue that can expose the environment to vulnerable or malicious transitive behavior over time.

Content

Scanner excerpt · scripts/requirements.txt (reported line 4)May include surrounding context.

text
litellm>=1.0.0
sentence-transformers>=2.2.2
torch>=2.0.0
numpy>=1.24.0

Unverifiable Dependency: numpy has 16 known advisory(ies) (CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding

numpy has known advisories, and without an exact version the manifest cannot establish whether an affected release will be installed. The direct danger is lower than for network-facing or model-loading libraries, but it still contributes to unverifiable supply-chain exposure.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.