Back to skill

Security audit

ollama-migrator

Security checks for vulnerabilities and agentic risk

Overview

This Ollama migration skill matches its stated purpose, but its optional cleanup can delete original models even when verification fails, so it needs careful review before use.

Install only if you are comfortable reviewing and manually supervising a local migration script. Do not use --cleanup until you have independently verified the destination models, and avoid choosing a target path inside or overlapping the existing ~/.ollama/models directory. Back up important models first.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/migrate_ollama.py:188
Finding

Source Models Are Deleted Even When Migration Verification Fails

Content
View full analysis

Vulnerability Details

File Location: scripts/migrate_ollama.py:97-110, scripts/migrate_ollama.py:188-201
Vulnerability Type: Improper migration validation before destructive cleanup
Risk Level: High

Vulnerable Code

python
# Verify size
source_size = sum(f.stat().st_size for f in self.source.rglob("*") if f.is_file())
target_size = sum(f.stat().st_size for f in self.target.rglob("*") if f.is_file())

source_gb = round(source_size / (1024**3), 2)
target_gb = round(target_size / (1024**3), 2)

print(f"  Source size: {source_gb} GB")
print(f"  Target size: {target_gb} GB")

if abs(source_size - target_size) > 1024:
    print("Warning: sizes do not match!")
    return False
python
if not self.verify_migration():
    print("Warning: verification failed, but migration may have succeeded")
    print("Run 'ollama list' manually to verify")

# Cleanup
if cleanup:
    print("\nCleaning source files...")
    try:
        shutil.rmtree(self.source)
        print(f"Source directory deleted: {self.source}")
    except Exception as e:
        print(f"Cleanup failed: {e}")

Technical Analysis

Migration verification is not enforced as a prerequisite for source deletion. When verify_migration() returns False, execution only prints a warning and then continues into the cleanup block. If the user supplied --cleanup, shutil.rmtree(self.source) recursively deletes the original model directory despite the failed verification.

The preceding copy verification is also insufficient for destructive cleanup. It compares only the aggregate byte size of the source and target directories. It does not verify:

  • Cryptographic hashes of individual files.
  • The complete set of relative file paths.
  • Whether files at the target predated the current migration.
  • Whether each copied model can be loaded successfully.
  • Whether files changed while the copy was in progress.

...[truncated 1484 chars]

Remediation
View remediation

Remediation Suggestions

  1. Immediately abort the migration when verify_migration() returns False; never enter cleanup after a failed verification.
  2. Build a fixed source manifest before copying. Record each relative path, file size, and a cryptographic digest such as SHA-256.
  3. Compare the destination against that manifest after copying rather than comparing aggregate directory sizes.
  4. Distinguish files copied during the current operation from files that already existed at the destination.
  5. Stop cleanup if any file is missing, has a mismatched size or digest, or cannot be read.
  6. Require a separate explicit confirmation immediately before destructive deletion.
  7. Prefer renaming the source to a dated rollback directory and retaining it until a later, separate cleanup operation.
  8. Record verification results and cleanup decisions in a durable migration log.
  9. Where practical, test loading at least one migrated model in addition to listing model metadata.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/migrate_ollama.py:79
Finding

Unvalidated Nested Target Path Can Cause Recursive Copying and Disk Exhaustion

Content
View full analysis

Vulnerability Details

File Location: scripts/migrate_ollama.py:16-18, scripts/migrate_ollama.py:79-95
Vulnerability Type: Unsafe source and destination path relationship
Risk Level: Medium

Vulnerable Code

python
def __init__(self, target: str):
    self.target = Path(target)
    self.user_home = Path.home()
    self.source = self.user_home / ".ollama" / "models"
    self.freed_space = 0
    self.errors = []
python
def copy_models(self) -> bool:
    """Copy model files."""
    print("\nCopying model files...")
    print(f"  Source: {self.source}")
    print(f"  Target: {self.target}")

    try:
        # Create target directory
        self.target.mkdir(parents=True, exist_ok=True)

        # Copy files
        for item in self.source.rglob("*"):
            if item.is_file():
                rel_path = item.relative_to(self.source)
                dest = self.target / rel_path
                dest.parent.mkdir(parents=True, exist_ok=True)
                shutil.copy2(item, dest)

Technical Analysis

The user-controlled target path is converted to a Path but is not canonicalized or checked for a safe relationship with the source directory. In particular, the script does not reject a target that is equal to the source or located inside the source.

The copy loop performs a live recursive traversal with self.source.rglob("*"). If the target is a descendant of the source, files written into the target can become visible to the same traversal. Those generated files can then be copied into progressively deeper target paths. The resulting behavior depends on filesystem traversal semantics, but it can cause recursive directory growth, excessive I/O, disk exhaustion, path-length failures, or an incomplete migration.

Path relationship checks based only on textual paths would also be insufficient because symbolic links, junctions, relative components, and c ...[truncated 1532 chars]

Remediation
View remediation

Remediation Suggestions

  1. Resolve the source and target to canonical absolute paths before any disk-space check, directory creation, or copy operation.
  2. Reject a target that is equal to the source, located beneath the source, or is an ancestor containing the source.
  3. Account for Windows path case normalization, junctions, symbolic links, and reparse points when evaluating path relationships.
  4. Refuse to traverse symlinked directories unless they are explicitly supported and validated.
  5. Generate a fixed source-file manifest before creating the destination or copying files. Iterate over that immutable manifest instead of a live recursive traversal.
  6. Consider copying into a newly created staging directory outside the source tree and atomically renaming it after successful verification.
  7. Recheck available space during long migrations and stop safely before the destination volume becomes critically full.
  8. Add tests covering identical paths, descendant targets, ancestor targets, relative paths, junctions, and symbolic links.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

声明描述将该技能定位为“模型迁移技能”,核心能力应包括把 Ollama 模型从 C 盘迁移到其他磁盘。代码中并没有任何复制、移动、修改配置、更新环境变量、创建软链接或其他迁移相关操作;它仅检查模型路径、环境变量、目录大小、模型文件数量以及磁盘空间,并根据剩余空间给出是否建议迁移的提示。因此,虽然代码覆盖了声明中的部分辅助场景(检查模型占用空间),但没有实现其核心宣称用途(迁移模型),也没有实现“验证迁移后模型可用性”。这构成了描述与实际行为的实质性不匹配。

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill advertises shell, environment-variable, and file-write capabilities through its documented workflow, but it does not declare any explicit tool scope such as permissions or allowed-tools. That creates an execution-boundary problem: an agent may invoke powerful operations without clear restriction, increasing the chance of unintended file modification, environment tampering, or risky shell execution during migration.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains user-facing natural-language strings and documentation in Chinese, beginning with the module docstring title. The file does not offer any language opt-in or explain that the skill is intended only for a Chinese-speaking or region-specific audience, which creates a language/locale policy concern.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest describes migrating Ollama model files, checking disk usage, and verifying model availability. While stopping Ollama may be operationally useful, this implementation uses an OS-level forced process termination command (taskkill /F) against ollama.exe, which is a privileged host-control action not explicitly justified by the stated skill scope.

Content

No source excerpt is available for this finding.

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/migrate_ollama.py (reported line 70)May include surrounding context.

python
print("\n停止 Ollama 服务...")
        try:
            # Windows
            subprocess.run(["taskkill", "/F", "/IM", "ollama.exe"], 
                         capture_output=True, timeout=5)
            print("Ollama 服务已停止")
            return True

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest focuses on moving Ollama models and checking/validating migration results. This code goes beyond file migration by writing OLLAMA_MODELS into HKEY_CURRENT_USER\Environment, a persistent system-configuration change that is not clearly declared in the skill’s stated purpose.

Content

No source excerpt is available for this finding.

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/migrate_ollama.py (reported line 147)May include surrounding context.

python
try:
            # 运行 ollama list
            result = subprocess.run(["ollama", "list"], 
                                  capture_output=True, text=True, timeout=10)
            
            if result.returncode == 0:

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This Python file contains user-facing natural-language text such as the module docstring and function docstrings only in Chinese. Under the policy rule for language/locale, forcing a specific language without user opt-in can be a natural-language policy violation when no alternative or justification is provided.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.