Back to skill

Security audit

Audit Case Rag

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent local audit-document search tool, but it loads Joblib index files unsafely from a user-controlled case path, which can enable local code execution if a malicious index file is selected.

Review before installing. Use this only in an isolated virtual environment on trusted case folders and trusted index directories. Do not run query against .joblib files supplied or replaceable by others, and avoid case values containing path separators until the script validates case IDs and replaces or authenticates Joblib serialization. Pin and hash dependencies before operational use with sensitive audit evidence.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/audit_case_rag.py:259
Finding

Path Traversal into Unsafe Joblib Deserialization

Content
View full analysis
None: out_dir = Path(expand(args.out_dir)).resolve() idx_path = out_dir / f"{args.case}.joblib" if not idx_path.exists(): raise SystemExit(f"Index not found: {idx_path}. Run index first.") bundle = joblib.load(idx_path) ``` ### Technical Analysis The user-controlled `--case` value is interpolated directly into a file name without validating its format or confirming that the resulting path remains inside `out_dir`. A value containing traversal sequences such as `../../` can therefore resolve to a Joblib file outside the intended index directory. The selected file is subsequently passed to `joblib.load()`. Joblib uses Python's pickle-based serialization mechanism and must not be used with untrusted files because deserialization can invoke attacker-controlled Python callables. Merely loading a malicious Joblib file can consequently execute arbitrary code. This vulnerability is exploitable when an attacker can both: 1. Place or identify a malicious Joblib-compatible file readable by the victim; and 2. Influence the `--case` command-line argument used by the query operation. ### Attack Path 1. The attacker constructs a malicious Joblib or pickle-compatible object containing a deserialization payload. 2. The attacker places it at a location readable by the user running the skill, such as `/tmp/malicious.joblib`. 3. The query command is invoked with a traversal value, for example: ```bash python3 scripts/audit_case_rag.py query \ --out-dir /path/to/audit_rag_db \ --case ../../tmp/malicious \ "question" ``` 4. The constructed path escapes the configured output directory and targets the malicious file. 5. `joblib.load(idx_path)` deserializes the file. 6. The embedded payl ...[truncated 660 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/requirements.txt:2
Finding

Unpinned and Unhashed Third-Party Dependencies

Content
View full analysis
=0.3.0 scikit-learn>=1.5.0 pypdf>=4.2.0 pandas>=2.2.0 openpyxl>=3.1.2 pyyaml>=6.0.1 joblib>=1.3.0 numpy>=1.26.0 ``` The documented installation command at `SKILL.md:41` installs these unconstrained ranges: ```bash pip install -r scripts/requirements.txt ``` ### Technical Analysis Every dependency uses an open-ended `>=` constraint, and no package hashes or lock file are supplied. As a result, separate installations can resolve to different package versions, including future releases that were never reviewed with this project. The installation process also lacks artifact integrity pinning. Package names and minimum versions alone do not establish that the retrieved wheel or source distribution is the exact artifact audited by the project. This increases exposure to compromised upstream releases, package-index compromise, unsafe dependency resolution, and unexpected incompatible changes. Several declared packages are not imported directly by the reviewed script, including `pandas`, `openpyxl`, and `pyyaml`. Unless they are required transitively or for an undocumented workflow, retaining them unnecessarily expands the supply-chain attack surface. ### Attack Path 1. A future or compromised package release satisfies one of the open-ended version ranges. 2. A user follows the documented command: ```bash pip install -r scripts/requirements.txt ``` 3. Pip resolves and retrieves the new artifact because no exact version or expected hash is enforced. 4. Malicious code may execute during source-package build or when the affected dependency is subsequently imported by the script. 5. The payload runs with the privileges of the user performing installation or invoking the skill. This finding does not establish that any currently lis ...[truncated 705 chars]
Remediation
View remediation
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (24)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 34)May include surrounding context.

md
pip install -r scripts/requirements.txt

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill instructs the user to run shell commands, create a virtual environment, install packages, and execute a local script that writes files, but it does not declare any tool scope or permissions boundaries. That omission makes the operational capabilities opaque to reviewers and agents, increasing the risk of unintended file modification or command execution in a sensitive local environment.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The natural-language description and workflow require case folders named with Chinese fields and use Chinese-only examples such as '项目问题编号__标题' and Chinese query text. This appears to impose a language/locale constraint on users without opt-in or an explicit statement that the skill is limited to a Chinese-language/regional audit context.

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

python
str(out_dir),
        str(input_path),
    ]
    proc = subprocess.run(cmd, capture_output=True, text=True)
    if proc.returncode != 0:
        raise RuntimeError(
            "LibreOffice conversion failed\n"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script serializes extracted document text, metadata, embeddings, and index structures into a persistent .joblib bundle, and earlier writes a manifest.jsonl into the case directory. Although these writes are part of indexing, there is no confirmation prompt or user-facing warning in the runtime output before storing potentially sensitive audit data locally.

Content

No source excerpt is available for this finding.

Insecure deserialization: joblib.load()

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

joblib.load() deserializes pickle-based data and can execute arbitrary code during loading if the .joblib file is attacker-controlled or replaced. In this skill, the index path is derived from user-controlled inputs and loaded from disk without integrity checks, so a malicious local file can turn a query operation into code execution.

Content

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

python
if not idx_path.exists():
        raise SystemExit(f"Index not found: {idx_path}. Run index first.")

    bundle = joblib.load(idx_path)
    texts: list[str] = bundle["texts"]
    metas: list[dict[str, Any]] = bundle["metas"]
    vec = bundle["tfidf_vectorizer"]

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The CLI defaults to the model name "BAAI/bge-small-zh-v1.5", which hard-codes a Chinese-language preference. This imposes a locale/language default without offering an explicit user choice or documenting that the tool is intentionally restricted to Chinese-language use.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The heading and directory naming template use Chinese text such as 事件驱动, 项目问题编号, and 标题 without explaining whether language is configurable or intended for a specific locale. This may impose a language/locale expectation on users without opt-in or documented justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file explicitly states that manifest.jsonl will be written into the case directory and <out_dir>/<case_id>.joblib will be created as a local persistent index. Because these are file-writing and persistence behaviors that may affect user data or local storage, the description should include a brief user warning or disclosure.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency is specified with a lower bound only, which allows future installs to resolve to different versions over time. This weakens supply-chain reproducibility and can unintentionally pull in vulnerable or breaking releases, especially in a document-processing RAG stack that handles complex third-party files.

Content

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

text
# Local-first audit/investigation RAG (no cloud APIs)
fastembed>=0.3.0
scikit-learn>=1.5.0
pypdf>=4.2.0
pandas>=2.2.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

Using scikit-learn with only a minimum version makes builds non-reproducible and leaves the actual installed version dependent on resolver state and install time. Because this package has had security advisories, lack of pinning increases the chance of unknowingly deploying an affected release.

Content

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

text
# Local-first audit/investigation RAG (no cloud APIs)
fastembed>=0.3.0
scikit-learn>=1.5.0
pypdf>=4.2.0
pandas>=2.2.0
openpyxl>=3.1.2

Unverifiable Dependency: scikit-learn has 6 known advisory(ies) (CVE-2020-13092 (scikit-learn Deserialization of Untrusted Data); CVE-2024-5206 (scikit-learn sensitive data leakage vulnerability); CVE-2020-28975 (scikit-learn Denial of Service) +3 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
91% confidence
Finding

The manifest does not pin scikit-learn, so it is impossible to verify whether the installed version is affected by known advisories. This is dangerous because the package may be installed at a vulnerable version without visibility, undermining assurance for a system that may process sensitive case data.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

pypdf is used to parse untrusted PDF content, so allowing an unbounded newer version range increases operational and security uncertainty. If a vulnerable or regressed version is resolved, malformed PDFs could trigger denial of service or parser flaws in this local document-ingestion workflow.

Content

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

text
# Local-first audit/investigation RAG (no cloud APIs)
fastembed>=0.3.0
scikit-learn>=1.5.0
pypdf>=4.2.0
pandas>=2.2.0
openpyxl>=3.1.2
pyyaml>=6.0.1

Unverifiable Dependency: pypdf has 16 known advisory(ies) (CVE-2026-84310 (pypdf: Possible long runtimes/large memory usage when retrieving outlines); CVE-2026-48156 (pypdf: Possible long runtimes for zero-only width values in cross-reference stre); CVE-2026-24688 (pypdf has possible Infinite Loop when processing outlines/bookmarks) +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
95% confidence
Finding

pypdf is directly exposed to attacker-controlled document inputs in this RAG workflow, and the unpinned dependency means affected versions cannot be ruled out. Given multiple parser-related advisories, this uncertainty is more dangerous here because malformed PDFs could cause denial of service or excessive resource consumption during ingestion.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

A minimum-only pandas requirement permits uncontrolled version drift across environments. While not directly exploitable by itself, this creates supply-chain uncertainty and can expose the application to vulnerable transitive behavior if an affected release is installed.

Content

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

text
fastembed>=0.3.0
scikit-learn>=1.5.0
pypdf>=4.2.0
pandas>=2.2.0
openpyxl>=3.1.2
pyyaml>=6.0.1
joblib>=1.3.0

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
84% confidence
Finding

Because pandas is not pinned, the security posture of the installed version cannot be validated against known advisories. The direct exploitability depends on how pandas is used, but the inability to verify versions still represents a supply-chain weakness.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

openpyxl processes spreadsheet files, which are externally supplied content in this audit/investigation workflow. Not pinning the version can lead to deployment of a release with parser-related flaws, increasing the attack surface for crafted XLSX/XML inputs.

Content

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

text
scikit-learn>=1.5.0
pypdf>=4.2.0
pandas>=2.2.0
openpyxl>=3.1.2
pyyaml>=6.0.1
joblib>=1.3.0
numpy>=1.26.0

Unverifiable Dependency: openpyxl has 2 known advisory(ies) (CVE-2017-5992 (Improper Restriction of XML External Entity Reference in Openpyxl); CVE-2017-5992 (Openpyxl 2.4.1 resolves external entities by default, which allows remote attack)), 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

openpyxl has historical XML entity-related issues, and the unpinned requirement prevents confirmation that a safe version is installed. In a workflow that likely opens externally sourced spreadsheets from case folders, this uncertainty increases the risk from crafted office documents.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

PyYAML has a history of unsafe deserialization issues, so leaving it unpinned increases the risk that an unsafe or vulnerable release is installed. In a skill that may ingest configuration or metadata files from case folders, this makes supply-chain and parser risk more significant than a generic library pinning issue.

Content

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

text
pypdf>=4.2.0
pandas>=2.2.0
openpyxl>=3.1.2
pyyaml>=6.0.1
joblib>=1.3.0
numpy>=1.26.0

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
96% confidence
Finding

PyYAML has multiple known deserialization-related advisories, and without a pinned version there is no assurance that installs avoid affected releases. This is particularly relevant if YAML metadata or configuration files in case directories are parsed, since unsafe parsing can lead to code execution or logic compromise.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

joblib has had arbitrary code execution concerns tied to unsafe deserialization patterns, and an unpinned version increases uncertainty about what gets installed. In ML/RAG tooling, joblib is often used with serialized artifacts, so version drift can have real security implications if untrusted model or cache files are ever loaded.

Content

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

text
pandas>=2.2.0
openpyxl>=3.1.2
pyyaml>=6.0.1
joblib>=1.3.0
numpy>=1.26.0

Unverifiable Dependency: joblib has 2 known advisory(ies) (CVE-2022-21797 (joblib vulnerable to arbitrary code execution); CVE-2022-21797 (The package joblib from 0 and before 1.2.0 are vulnerable to Arbitrary Code Exec)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
95% confidence
Finding

joblib is not pinned, so the environment may resolve to versions affected by known arbitrary code execution advisories. This matters in ML-oriented tooling because serialized caches or artifacts are common, and loading untrusted joblib content can become a high-risk path if present elsewhere in the skill.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

An unpinned numpy dependency introduces the same reproducibility and supply-chain uncertainty as the other minimum-only requirements. Although numpy itself is foundational, leaving its resolved version uncontrolled can still expose the stack to known defects or security regressions.

Content

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

text
openpyxl>=3.1.2
pyyaml>=6.0.1
joblib>=1.3.0
numpy>=1.26.0

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
88% confidence
Finding

Since numpy is unpinned, the manifest cannot prove that the deployed version is free from known advisories. This is primarily a dependency-governance issue rather than a direct exploit path in the manifest itself, but it still weakens the security baseline.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.