Back to skill

Security audit

Codebase Intelligence

Security checks for vulnerabilities and agentic risk

Overview

This codebase-analysis skill is mostly purpose-aligned, but it automatically loads a project-local pickle cache that can execute code from an untrusted repository.

Use this only on trusted repositories unless the pickle cache issue is fixed. Before running it on a repo, delete or ignore any existing .codebase-intelligence/codebase_index.pkl, prefer a private trusted cache directory outside the repo, and remember that local cache/export files may include snippets of source code.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/indexer.py:498
Finding

Unsafe Deserialization of a Repository-Controlled Pickle Cache

Content
View full analysis

Vulnerability Details

File Location: scripts/indexer.py, lines 498–499
Vulnerability Type: Unsafe Python pickle deserialization
Risk Level: High

Vulnerable Code

python
if self.cache_file.exists():
    with open(self.cache_file, 'rb') as f:
        return pickle.load(f)

The cache path is established under the analyzed project in scripts/indexer.py, lines 124–129:

python
def _get_default_cache_dir(self) -> Path:
    """Get default cache directory"""
    # Store cache in project's .codebase-intelligence directory
    cache_dir = self.root / '.codebase-intelligence'
    cache_dir.mkdir(exist_ok=True)
    return cache_dir

Technical Analysis

Python pickle data is executable serialization rather than a safe data-only format. During pickle.load(), specially crafted objects can invoke attacker-selected callables through pickle reduction operations.

The default cache file is <analyzed-project>/.codebase-intelligence/codebase_index.pkl. Because the Skill is designed to inspect arbitrary projects, that file may be supplied by an untrusted repository author. The implementation checks only whether the file exists; it does not verify its origin, integrity, signature, ownership, or expected schema before deserializing it.

Indexer.build_index() attempts to load this cache before rebuilding the index. The same vulnerable behavior is therefore reachable through documented operations that build or access an index, including the analyze, ask, and index commands.

Catching exceptions around deserialization does not mitigate this issue because a malicious reduction callable can execute before pickle.load() returns or raises an error.

Attack Path

  1. An attacker creates a malicious pickle whose deserialization reduction invokes an arbitrary Python callable, such as a process-launching or file-writing function.
  2. The attacker places it at .codebase-intelligence/codebase_index.pkl in a repository.
  3. A victim clones ...[truncated 1138 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove pickle from the cache format. Use a data-only format such as JSON, which the project already writes, and reconstruct CodebaseIndex and FileIndex objects after validation.
  2. Validate the complete cache schema. Enforce expected field names, primitive types, path constraints, collection size limits, and cache-version compatibility before accepting cached data.
  3. Keep trusted cache state outside analyzed repositories. Store caches in a user-controlled cache directory and key each entry using a canonical project path or repository identifier. This reduces exposure to files committed by repository authors.
  4. Authenticate caches if non-JSON serialization is unavoidable. Verify a keyed MAC or digital signature before parsing. Authentication keys must not be stored in the analyzed repository.
  5. Never use pickle.load() on untrusted or repository-controlled files. Restricted unpicklers and exception handling are not reliable substitutes for a non-executable serialization format.
  6. Harden file handling. Reject symbolic-link cache files, verify ownership and permissions where supported, use restrictive permissions, and write updates atomically through a safely created temporary file followed by replacement.
  7. Invalidate legacy caches. After deploying the fix, ignore or delete existing .pkl caches without deserializing them and rebuild the index from source files.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
Findings (22)

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

The code substantially matches the general theme of codebase analysis: it explores project structure, identifies modules/directories, analyzes some dependencies/imports, and summarizes the codebase. However, the declared description includes two notable capabilities not present in the code: caching and answering questions about the codebase. The supplied code is only a standalone analyzer/report generator with no cache storage/reuse and no conversational or query-handling interface. Additionally, it supports writing reports to disk via --output, which is a meaningful behavior not mentioned in the description, though secondary to the main purpose. Therefore this is a partial but material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The code partially matches the description because it does answer questions about a codebase and builds a lightweight index of files, functions, and classes. However, several central declared capabilities are not actually implemented. There is no caching at all. Dependency analysis is explicitly unimplemented and deferred to another tool. Project structure/module analysis is minimal: the script recursively scans files and records contents, but does not meaningfully identify modules or analyze relationships beyond basic name lookup and term matching. Because these missing features are core parts of the declared purpose rather than minor implementation details, this is a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
87% confidence
Finding

There is substantial overlap with the declared purpose because the script does answer codebase questions using an index and local search over files/symbols. However, the description specifically claims broader intelligent codebase analysis with caching, automatic exploration of project structure/modules/dependencies, and the file’s own docstring suggests LLM usage. In the supplied chunk, the primary behavior is a heuristic CLI Q&A wrapper around an Indexer: it builds an index, searches, classifies questions by keywords, and formats responses. It does not show caching, direct module/project-structure exploration logic, or real dependency analysis beyond suggesting another command. It also accepts an LLM-related flag but never uses it. Therefore the description is only partially accurate and overstates capabilities present in this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

The code does perform dependency analysis and can help understand code relationships, which partially aligns with the description. However, several declared core capabilities are not present in the supplied code: there is no caching mechanism, no interactive question-answering capability, and no substantial module-identification or broader codebase-understanding logic beyond simple import extraction and reporting. The actual code is a narrow dependency-report generator rather than an 'intelligent codebase analysis and understanding' system. Therefore the description overstates and materially misrepresents the behavior of this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The code does perform partial codebase analysis: it explores the filesystem, identifies top-level modules, and extracts some dependencies. However, the declared description emphasizes 'intelligent codebase analysis and understanding with caching' and the ability to 'answer questions about the codebase.' This code contains no caching layer, no question-answering interface, and no broader understanding features beyond lightweight dependency extraction. Its actual primary function is generating architecture diagrams from simple static analysis. That is related to codebase understanding, but materially narrower and differently focused than the declared purpose, so this is a mismatch.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/indexer.py (reported line 69)May include surrounding context.

python
DEFAULT_IGNORE = [
        '.git', '.svn', '.hg',
        'node_modules', 'vendor', '__pycache__',
        '.venv', 'venv', 'env', '.env',
        'dist', 'build', 'target', 'out',
        '*.min.js', '*.min.css', '*.map',
        '.DS_Store', 'Thumbs.db',

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises and demonstrates shell execution, file writes, and project-wide analysis behavior, but it does not declare any tool scope such as permissions or allowed-tools. This is dangerous because consumers and enforcement layers cannot clearly constrain what the skill is permitted to access, increasing the risk of over-broad execution against arbitrary repositories or local files.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
78% confidence
Finding

SQP-3 applies to all file types and covers language or locale policy violations. This skill presents core instructions and labels primarily in Chinese while example prompts and command content are partly in English, yet it does not state whether the skill is intended for Chinese-speaking users only or offer an opt-in language choice.

Content

No source excerpt is available for this finding.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/analyze.py (reported line 285)May include surrounding context.

python
"# Codebase Analysis Report",
            "",
            f"**Root Directory**: `{self.root}`",
            f"**Generated**: {__import__('datetime').datetime.now().isoformat()}",
            "",
            "## Overview",
            "",

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest describes an analysis/understanding skill with caching, which implies inspecting code and producing answers or reports, but does not mention modifying the filesystem beyond any cache mechanism. The CLI supports arbitrary report creation via --output and writes content to a user-specified path, which is a behaviorally broader operation than the read-oriented description suggests.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The module docstring says it is an "Enhanced Natural Language Query Script with LLM" and specifically mentions using OpenClaw's kimi_search for intelligent understanding. In the actual code, answer() routes questions through _classify_question() keyword matching and _gather_context() local index searches, with no LLM or external kimi_search integration anywhere in the file.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The answer(self, question, use_llm: bool = True, ...) signature and CLI help text Use local search only (no LLM) suggest two behaviors: LLM-assisted and local-only. However, use_llm is never referenced in answer(), and the CLI flag only toggles an unused argument, so the documentation actively misrepresents runtime behavior.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Using pickle for cache loading is unjustified for this feature set because the index consists of simple structured metadata that can be safely stored as JSON or another non-executable format. In a repository-analysis skill, unsafe deserialization materially increases risk since opening or re-indexing a malicious project could trigger code execution via a poisoned cache.

Content

No source excerpt is available for this finding.

Insecure deserialization: pickle.load()

Medium
Category
Dangerous Code Execution
Confidence
97% confidence
Finding

The code deserializes a cache file using pickle.load(), which can execute arbitrary code during loading if the cache file is modified by an attacker. Because the cache path may be inside the repository or user-specified via --cache-dir, this becomes dangerous in a code-analysis tool that may run on untrusted projects or shared workspaces.

Content

Scanner excerpt · scripts/indexer.py (reported line 499)May include surrounding context.

python
try:
            if self.cache_file.exists():
                with open(self.cache_file, 'rb') as f:
                    return pickle.load(f)
        except Exception as e:
            print(f"  ⚠️  Could not load cache: {e}")
        return None

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The indexer persists a JSON cache containing content_preview values, which are the first 500 characters of each indexed file. This can store source code, secrets, tokens, or proprietary content to disk without clear user warning, increasing exposure on shared machines, backups, or if the repository itself is later shared with the .codebase-intelligence directory included.

Content

No source excerpt is available for this finding.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/main.py (reported line 33)May include surrounding context.

python
print(f"\n📊 Codebase Analysis Report")
        print(f"{'='*50}")
        print(f"Root Directory: {stats['root']}")
        print(f"Generated: {__import__('datetime').datetime.now().isoformat()}")
        print(f"\n## Overview")
        print(f"- **Total Files**: {stats['total_files']}")
        print(f"- **Total Lines**: {stats['total_lines']:,}")

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

python
cmd.extend(['--format', args.format])
    if args.output:
        cmd.extend(['--output', args.output])
    subprocess.run(cmd)


def run_ask(args):

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

python
cmd.extend(['--format', args.format])
    if args.output:
        cmd.extend(['--output', args.output])
    subprocess.run(cmd)


def run_ask(args):

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The ask command enables LLM use by default and may transmit user questions plus codebase-derived context externally without an explicit runtime disclosure or confirmation. In a codebase-intelligence skill, that context can include proprietary source, secrets, internal architecture, or regulated data, creating a real confidentiality risk if users assume analysis is local.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation states that running analysis will create a cache directory and supports exporting indexes, but it does not prominently warn that the tool writes into the target project or user-specified paths. This can surprise users, alter repositories unintentionally, and create risk in sensitive or read-only workspaces, especially when used in automation like hooks or CI.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The script automatically calls self.indexer.build_index() before answering any question, which implies scanning and reading the user's project files. In this file there is no confirmation prompt or user-facing disclosure explaining that local code contents and metadata will be indexed as part of answering a query.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The index command performs a filesystem write by exporting JSON to the path supplied in --export. While this behavior is functional and expected for an export feature, the code at the write site has no confirmation prompt or inline warning/comment about overwriting or creating files, so the write lacks local disclosure in the implementation.

Content

No source excerpt is available for this finding.