T03 · Remote Payload Retrieval and Execution
- Location
README.md:27- Finding
Remote Installer Content Is Executed Without Integrity Verification
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill mostly fits its wiki/Zotero purpose, but it needs review because some install and Zotero/MCP paths can expose credentials or write through a different backend than the user selected.
Install only from a pinned release or reviewed commit, avoid copy-pasting remote installer pipes, and treat Zotero/MCP configuration as security-sensitive. Before enabling Zotero writes, prefer memory-only authorization, verify the target library and backend, and be aware that the current `zotero-refresh --write-backend local` option appears not to be honored by the inspected CLI path.
README.md:27Remote Installer Content Is Executed Without Integrity Verification
README.md:32Installation Uses Mutable Git State and Unbounded Future Dependency Versions
src/llm_wiki/zotero/mcp_client.py:47Configuration-Selected MCP Process Inherits the Entire Parent Environment
The explicit | sh pattern is a direct remote-code-execution anti-pattern because it removes the user's chance to inspect the downloaded script before execution. In this skill's context, the danger is amplified: the project is designed for AI-agent-assisted command execution, so unsafe installation guidance can be copied or enacted by automation with less scrutiny than a human would apply.
# 1. Install uv once (https://docs.astral.sh/uv/)
# Windows: powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
# macOS/Linux: curl -LsSf https://astral.sh/uv/install.sh | sh
# 2. Install llm-wiki straight from GitHub (uv fetches it for you)
uv tool install git+https://github.com/Nemo4110/llm-wiki.git
The declared description centers on runtime llm-wiki knowledge-base operations: ingesting source files, answering questions from wiki pages, running agent-bridge commands, preserving provenance metadata, and interacting with Zotero. The code shown does none of those things. Instead, it performs software packaging and release assembly. While it writes a starter wiki/index.md and includes project files, that is incidental to building a distributable release bundle, not to operating the wiki itself. This is a materially different primary purpose, so the description does not accurately represent the code chunk.
The declared description covers broad llm-wiki knowledge-base operations such as wiki ingestion, wiki question answering, agent-bridge status/lint/link/relink/merge/query/index tasks, provenance handling, and Zotero-based literature discovery. The actual code shown does not implement those functions. Instead, it provides a command-line helper for reading PDF text and extracting images/figures from PDFs. While PDF processing could be a supporting component of a larger ingestion pipeline, this chunk’s primary behavior is specifically PDF content/image extraction, which is not explicitly represented in the declared purpose and is materially narrower/different from the stated skill behavior.
The declared description focuses on operating an llm-wiki knowledge base and related agent-bridge/Zotero workflows. The supplied code does not implement wiki ingestion, wiki question answering, provenance management, indexing, linking, querying, or Zotero relocation/discovery. Instead, it performs a distinct document-processing task: extracting images and rendered vector figures from PDF files to disk. This is a materially different primary purpose and an undeclared capability, so the description does not accurately represent the code chunk.
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
## 知识主体
<!--
根据来源内容地图选择并命名章节,不要机械保留下列所有示例:
- 根本问题与关键矛盾
- 机制、推导或系统数据流
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
## 知识主体
<!--
根据来源内容地图选择并命名章节,不要机械保留下列所有示例:
- 根本问题与关键矛盾
- 机制、推导或系统数据流
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
## 知识主体
<!--
根据来源内容地图选择并命名章节,不要机械保留下列所有示例:
- 根本问题与关键矛盾
- 机制、推导或系统数据流
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
## 知识主体
<!--
根据来源内容地图选择并命名章节,不要机械保留下列所有示例:
- 根本问题与关键矛盾
- 机制、推导或系统数据流
Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.
Do not assume that ~/.config/zotero-mcp/config.json controls the active MCP access mode. That file primarily stores semantic-search, database-path, extraction, and index-update settings. Local/Web mode and Web credentials are normally supplied by the MCP client's process environment. However, zotero-mcp v0.11.0 was observed to also load Web credentials from that file's client_env block when the process environment does not provide them — so treat the file as a potential credential source, and do not assume that "no ZOTERO_API_KEY in the client process env" means a write will stay local or fail.
For Codex, inspect the configured server entry in ~/.codex/config.toml (or the equivalent host-managed MCP configuration). A hybrid configuration keeps local access enabled while retaining Web credentials for write-capable operations:
[mcp_servers.zotero-mcp]
The CLI advertises --write-backend web|local, implying operators can keep writes on the MCP/web path, but the implementation for zotero-refresh --apply-safe ignores that control and always follows the local writer flow. In a security-sensitive agent skill, misleading write-path controls can cause unexpected direct local API mutations, bypassing intended operational boundaries, audit assumptions, or approval expectations.
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.
"target_dir", nargs="?", default=".", help="Directory to initialize"
)
init_parser.add_argument(
"--force", action="store_true", help="Overwrite existing files"
)
# ingest
Using the entire process environment as the basis for a child-process environment is a classic secret-exposure pattern because it forwards potentially sensitive variables to code outside the current trust boundary. Here that boundary is especially important because the MCP server executable is selected from configuration and then executed, so any malicious or swapped server binary gains access to inherited credentials immediately at startup.
if not command:
raise ZoteroMCPError(f"MCP server {self.server_name!r} has no command")
env = {**os.environ}
env.update(
{str(key): str(value) for key, value in (server.get("env") or {}).items()}
)
The document instructs agents to start a section with ### 时间定位 / ### Temporal Position, but the later detailed formatting guidance repeatedly mandates Chinese-first heading conventions such as ### 时间定位 and ### 来源摘要. This creates a language/locale constraint in user-facing wiki content without explicit user opt-in or a documented region-specific justification.
These lines require agents to use Chinese labels like 时间范围, 阶段判断, and 时间信息 in generated markdown structure. That is a natural-language locale policy constraint and may force output into a specific language even when the user has not requested it.
The README recommends installing/running code directly from a Git repository default branch via uvx --from git+https://github.com/Nemo4110/llm-wiki.git, without pinning a tag or commit. That creates a supply-chain risk: future upstream compromise, force-pushes, or malicious commits could change what users execute, and the risk is higher here because this skill is explicitly meant for agent/tool execution.
The decision record at L202-L215 sets an explicit boundary: llm-wiki should keep Zotero connectivity in an external Agent skill workflow and not claim unsupported native integration. However, L221-L229 later expands scope to a worker that launches Zotero MCP and performs external DOI/citation/metrics refreshes using Crossref and OpenAlex, which materially broadens the integration model beyond the earlier stated boundary and creates a documentation-level contradiction about what is and is not part of llm-wiki.
The skill requests or implies broad capabilities including shell, network, file read/write, environment access, and MCP operations, but it does not declare an explicit tool scope such as permissions or allowed-tools. This creates an overbroad trust boundary: an agent may invoke powerful tools during normal skill execution without a machine-readable restriction layer, increasing the chance of unintended filesystem modification, network access, or external-system writes.
The file title and all operative guidance are written as mandatory Chinese-language instructions, with no indication that the user can choose another language or locale. Under the policy scope, forcing a specific language without opt-in is a natural-language policy violation unless the locale restriction is explicitly justified.
The template's instructional and content text is written in Chinese and directs authors to produce page content in Chinese, such as the summary and section guidance. This constitutes a language/locale policy concern because it imposes a specific language without offering user choice or documenting a justified region-specific requirement.
The file’s instructional content is written as prescriptive guidance entirely in Chinese, starting with direct requirements about how the summary should be produced. There is no indication that the user may choose another language or that the Chinese-only constraint is required for a region-specific or compliance-related purpose, which can violate language/locale policy expectations.
The title and introductory description are written entirely in Chinese, and the rest of the document consistently uses Chinese as the sole language of instruction. Under the policy criteria, forcing a specific language without user opt-in or a documented locale-specific justification can be a natural-language policy violation.
The document title and core framing are entirely in Chinese, and it presents the skill architecture evaluation in that language without any indication that language selection is optional. Under the policy rule, forcing a specific language without user opt-in is a natural-language locale violation unless it is clearly documented as region-specific or user-selectable.
The document authorizes a reusable local API key to be stored in var/zotero-local.json and describes a direct local write path that bypasses the normal MCP boundary. Even though it is gitignored and mode-0600, this creates credential persistence and an alternate write channel; compromise of the workspace or agent runtime could expose a long-lived key with broad write access to editable libraries.
**Local API writes — desktop capability exists; zotero-mcp has not adopted it; llm-wiki adds a temporary direct path (most important):**
- Zotero 10 added **Local API write support** at the desktop level.
- The integrated zotero-mcp (≤ v0.11.0) **still routes its own writes through the Zotero Web API**; local mode remains **read-only for writes** ("fast local reads, web API writes"). This is unchanged.
- Consequence for the MCP path: `metadata_write_backend = local` is **not reachable through zotero-mcp** today; the MCP metadata write gate and the hybrid-mode warning below still stand for anything written via zotero-mcp.
- **Temporary opt-in exception:** llm-wiki now offers a direct local write path that bypasses zotero-mcp only for the exact authorized targets. Collection discovery, snapshots, sources, and bibliographic reads still go through MCP; direct local GETs are permitted only as precondition and post-write verification barriers for those targets. One-time `agent-bridge.py zotero-local-auth` stores a reusable key under gitignored `var/zotero-local.json`; then either `zotero-refresh --apply-safe --write-backend local` or the restricted reviewed `zotero-writeback` workflow writes via the local API. `zotero-writeback --memory-authorize` can instead keep a one-run key only in process memory. See "Temporary Direct Local Writes" below. **Remove this exception once zotero-mcp adopts local writes.**
This section documents and permits temporary direct local write paths outside the normal MCP route (zotero-refresh --write-backend local, zotero-writeback, zotero-relocate). The text includes safety gates, but it still expands the trusted computing boundary and introduces a second mutable backend path, increasing the chance of state divergence, authorization mistakes, or writes occurring through a less-audited channel.
| Local | Any | Web | `divergent` or `unknown` | Stop writes and reconcile or re-audit first |
| Any | Any | `unavailable` | Read-only work only |
Do not infer backend consistency from configuration values alone. A valid API key, an exposed write tool, or a successful single-item write proves only that one route is writable; it does not prove that local and Web state agree.
> **Note on `metadata_write_backend = local`:** not reachable *through zotero-mcp* — v0.11.0 routes its writes through the Web API even against Zotero 10. The `local` write backend is reachable only via the temporary direct local paths (`zotero-refresh --write-backend local`, reviewed `zotero-writeback`, or reviewed `zotero-relocate`); the gate's Web-backend rows still govern anything written through zotero-mcp. See "Temporary Direct Local Writes".
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.
- Never expose Zotero API keys, library credentials, private annotations, or local absolute paths in committed files or logs.
- Do not overwrite item metadata, replace all tags, move collections, attach files, or delete Zotero content without explicit authorization.
- Do not import large item or full-text batches without confirmation.
- Do not treat a search result, abstract, or generated summary as a verified original attachment.
- Do not use untrusted files with unsafe deserialization or execute scripts embedded in source material.
- If item identifiers or titles mismatch, stop ingest and report the expected versus observed metadata.