Back to skill

Security audit

Local-First LLM

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly coherent, but its setup guide tells users to run unverified downloaded code, which deserves careful review before installing.

Install only after replacing the provider setup steps with verified package-manager or pinned checksum/signature flows. Treat any cloud routing decision as permission to send the prompt externally only after you explicitly approve it, especially for private or regulated data.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T03 · Remote Payload Retrieval and Execution

Error
Location
references/local-providers.md:7
Finding

Unverified Remote Installer Is Piped Directly into a Shell

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
references/local-providers.md:58
Finding

Downloaded llamafile Executable Is Run Without Integrity Verification

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The supplied code is a narrow availability checker for local LLM providers. It queries localhost endpoints for Ollama, LM Studio, and llamafile, parses model metadata, and outputs availability plus a preferred local provider. That behavior is only a small supporting piece of the declared skill. The declared description promises a broader system that routes requests to local models first, falls back to cloud APIs when needed, and tracks savings in a persistent dashboard. None of those major capabilities appear in this code chunk. While the providers listed are consistent with the description, the actual primary purpose here is provider detection, not request routing or dashboard/cost tracking.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a full routing system with provider support, cloud fallback, and persistent savings/dashboard tracking. The supplied code only makes a heuristic routing decision and prints it as JSON. It does not send requests to any model, interface with Ollama/LM Studio/llamafile, contact cloud APIs, store metrics, or expose a dashboard. While the code is related to routing logic, it implements only a narrow decision component, so the description materially overstates the skill's actual behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a broader skill whose primary purpose is request routing between local and cloud LLMs, with provider support and a dashboard. The supplied code chunk is only a bookkeeping utility for savings metrics persisted to ~/.openclaw/local-first-llm/savings.json. While the tracking portion partially aligns with the description, the core advertised behavior—routing requests to local models first, falling back to cloud APIs, and supporting specific local providers—is absent from this code. Therefore the description materially overstates the implemented capabilities.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill promotes cloud fallback but does not clearly warn that prompts may be sent to external APIs when local handling is unavailable or deemed unsuitable. In a privacy-focused routing skill, omission of that disclosure is especially dangerous because users may rely on the skill specifically to keep sensitive prompts local.

Content

No source excerpt is available for this finding.

External Script Fetching

High
Category
Supply Chain
Confidence
98% confidence
Finding

Piping a remotely fetched script directly into sh executes unverified code from the network without giving the user a chance to inspect or validate it. If the hosting site, connection path, or install script is compromised, this can lead to arbitrary code execution on the user's machine.

Content

Scanner excerpt · references/local-providers.md (reported line 12)May include surrounding context.

brew install ollama

Linux

curl -fsSL https://ollama.ai/install.sh | sh

text

**Start server**

Chaining Abuse

High
Category
Tool Misuse
Confidence
98% confidence
Finding

The | sh construct is dangerous because it turns downloaded content into immediate shell execution, collapsing download and execution into a single opaque step. In documentation aimed at setting up local LLM tooling, this increases the chance that users will run privileged or persistent code they have not reviewed.

Content

Scanner excerpt · references/local-providers.md (reported line 12)May include surrounding context.

brew install ollama

Linux

curl -fsSL https://ollama.ai/install.sh | sh

text

**Start server**

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding

The skill advertises and demonstrates shell execution, network access, and persistent file writes, but does not declare any tool scope such as permissions or allowed-tools. That creates an implicit capability surface where an agent may invoke sensitive operations without an explicit least-privilege contract, increasing the chance of unsafe or surprising behavior.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The activation text includes a broad trigger: 'any request where local-vs-cloud routing should be decided automatically.' Broad auto-activation can cause the skill to engage in contexts the user did not clearly request, which is risky here because the skill influences network routing, privacy decisions, and persistent logging.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Ollama

bash
curl http://localhost:11434/api/generate \
  -d '{"model": "llama3.2", "prompt": "YOUR_PROMPT", "stream": false}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/local-providers.md (reported line 33)May include surrounding context.

Test

bash
curl http://localhost:11434/api/generate \
  -d '{"model":"llama3.2","prompt":"Hello","stream":false}'

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/routing-logic.md (reported line 7)May include surrounding context.

md
Each request is scored before routing. Higher = more complex = prefer cloud.

| Factor                                                                                                                                                                                   | Score Change |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| Keyword match: `analyze`, `synthesize`, `compare`, `reason`, `architecture`, `code review`, `multi-step`, `evaluate`, `critique`, `refactor`, `design`, `implement`, `debug`, `strategy` | +2 per match |
| Keyword match: `summarize`, `translate`, `list`, `what is`, `define`, `explain briefly`, `convert`, `format`, `reformat`, `spell check`                                                  | −1 per match |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/routing-logic.md (reported line 11)May include surrounding context.

md
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| Keyword match: `analyze`, `synthesize`, `compare`, `reason`, `architecture`, `code review`, `multi-step`, `evaluate`, `critique`, `refactor`, `design`, `implement`, `debug`, `strategy` | +2 per match |
| Keyword match: `summarize`, `translate`, `list`, `what is`, `define`, `explain briefly`, `convert`, `format`, `reformat`, `spell check`                                                  | −1 per match |
| Token count > 4,000                                                                                                                                                                      | +2           |
| Token count < 500                                                                                                                                                                        | −1           |

## Decision Tree

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · references/routing-logic.md (reported line 12)May include surrounding context.

md
| Keyword match: `analyze`, `synthesize`, `compare`, `reason`, `architecture`, `code review`, `multi-step`, `evaluate`, `critique`, `refactor`, `design`, `implement`, `debug`, `strategy` | +2 per match |
| Keyword match: `summarize`, `translate`, `list`, `what is`, `define`, `explain briefly`, `convert`, `format`, `reformat`, `spell check`                                                  | −1 per match |
| Token count > 4,000                                                                                                                                                                      | +2           |
| Token count < 500                                                                                                                                                                        | −1           |

## Decision Tree

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/dashboard.py (reported line 14)May include surrounding context.

python
def run(args: list) -> dict:
    try:
        result = subprocess.run(
            [PY] + args, capture_output=True, text=True, timeout=5
        )
        return json.loads(result.stdout) if result.returncode == 0 and result.stdout.strip() else {}

Static analysis

No suspicious patterns detected.