Back to skill

Security audit

Zotero PDF Local Import

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent Zotero PDF importer, but it requires an automatic unpinned Python package install that can change the user's environment.

Install only if you are comfortable with the agent reading the PDFs or folders you name, sending those PDFs to your local Zotero connector, and potentially reading your Zotero database for the check command. Before use, prefer installing dependencies yourself in a dedicated virtual environment with a pinned `requests` version, and do not let the agent run `--auto-install-deps` without explicit approval.

Vulnerability Patterns
  • 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
  • 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)

T08 · Insecure Dependencies

Warning
Location
scripts/zotero_tool.py:237
Finding

Mandatory Runtime Installation of an Unpinned Dependency

Content
View full analysis
=2.31.0"], capture_output=True, text=True) if r.returncode != 0: print("dep_requests=install_failed") print((r.stderr or r.stdout or "").strip()[:500]) return 10 import importlib req_mod = importlib.import_module("requests") print(f"dep_requests=installed version={getattr(req_mod, '__version__', 'unknown')}") ``` The dependency declaration is also unpinned: ```text requests>=2.31.0 ``` The Skill instructions make this installation path part of the mandatory execution flow: ```text Required execution flow: 1. Run `doctor --auto-install-deps` 2. If successful, run `import` ``` ### Technical Analysis The `doctor --auto-install-deps` command invokes pip to retrieve and install any version of `requests` satisfying `>=2.31.0`. The package version is not pinned, no artifact hashes are verified, and no trusted package index is explicitly selected. Consequently, the code executed by the Skill can differ from the code originally audited. If dependency resolution is influenced by a compromised package repository, compromised upstream release, malicious mirror, or local pip configuration, pip may install an attacker-controlled artifact. A source distribution can involve build-backend code during installation, and the installed package is subsequently imported with `importlib.import_module("requests")`. This behavior is not required for Zotero's local import semantics. D ...[truncated 1601 chars]
Remediation
View remediation
``` 3. Generate a lock file containing cryptographic hashes and install with hash verification: ```bash python -m pip install --require-hashes -r requirements.lock ``` 4. Restrict installation to a trusted, explicitly configured package index and avoid inheriting untrusted pip configuration where feasible. 5. Install dependencies in an isolated virtual environment rather than modifying the agent's or system's shared Python environment. 6. Prefer a deployment process that installs and verifies dependencies before the Skill is invoked. The runtime `doctor` command should only validate their presence and approved versions. 7. If runtime installation must remain available, display the package source and resolved version, obtain user confirmation, reject unexpected versions or indexes, and verify artifacts against maintained hashes. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill instructs the agent to execute shell commands, access local files, contact a localhost HTTP service, and potentially install dependencies, but it does not declare any explicit tool scope or allowed-tools/permissions metadata. That mismatch increases the chance an agent grants broader capabilities than users expect, enabling unintended local file access or command execution in a workflow that handles user-supplied paths and network parameters.

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

python
if sys.platform.startswith("win"):
        os.startfile(url)  # type: ignore[attr-defined]
    elif sys.platform == "darwin":
        subprocess.run(["open", url], check=True)
    else:
        subprocess.run(["xdg-open", url], check=True)
    time.sleep(1.2)

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

python
elif sys.platform == "darwin":
        subprocess.run(["open", url], check=True)
    else:
        subprocess.run(["xdg-open", url], check=True)
    time.sleep(1.2)

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Automatic package installation is beyond the stated purpose of importing PDFs into Zotero and materially increases the trust boundary of the skill. It enables network-based dependency retrieval and environment mutation, which can expose users to supply-chain compromise, unexpected package resolution, or breaking changes in the local Python setup.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The tool can run pip and modify the active Python environment without presenting a clear safety warning about side effects, trust implications, or scope of changes. In a local-agent context, silent environment mutation is dangerous because users may not realize the command downloads and installs executable third-party code.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
94% confidence
Finding

The doctor command can modify the user's Python environment by invoking pip to install packages, which exceeds the core import/check functionality and creates a supply-chain and environment-integrity risk. Even though it uses a fixed package name and no shell, it still performs code-fetching and package installation from configured indexes, which can introduce untrusted code or unexpected system changes.

Content

Scanner excerpt · scripts/zotero_tool.py (reported line 250)May include surrounding context.

python
print("dep_requests=missing")
        if args.auto_install_deps:
            print("dep_requests=installing")
            r = subprocess.run([sys.executable, "-m", "pip", "install", "requests>=2.31.0"], capture_output=True, text=True)
            if r.returncode != 0:
                print("dep_requests=install_failed")
                print((r.stderr or r.stdout or "").strip()[:500])

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

python
if sys.platform.startswith("win"):
            print("url_opener=ok method=os.startfile")
        elif sys.platform == "darwin":
            r = subprocess.run(["which", "open"], capture_output=True, text=True)
            print("url_opener=ok method=open" if r.returncode == 0 else "url_opener=fail missing=open")
            ok = ok and (r.returncode == 0)
        else:

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

python
print("url_opener=ok method=open" if r.returncode == 0 else "url_opener=fail missing=open")
            ok = ok and (r.returncode == 0)
        else:
            r = subprocess.run(["which", "xdg-open"], capture_output=True, text=True)
            print("url_opener=ok method=xdg-open" if r.returncode == 0 else "url_opener=fail missing=xdg-open")
            ok = ok and (r.returncode == 0)
    except Exception as e:

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified as requests>=2.31.0, which allows installation of any future version and does not ensure reproducible builds. Unpinned dependencies increase supply-chain risk because different environments may resolve to different releases, including versions with regressions or newly introduced vulnerabilities.

Content

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

text
requests>=2.31.0

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +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
90% confidence
Finding

Because the manifest does not pin requests to a specific version, it is impossible to verify whether the installed package version avoids the listed advisories. In a skill that communicates with a local HTTP service on 127.0.0.1, dependency behavior matters; leaving the version unconstrained weakens assurance that a safe, reviewed release will be used.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The message hardcodes Chinese output ('我的文库') for the default target selection. This imposes a specific language in user-facing behavior without any opt-in or locale selection, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.