Back to skill

Security audit

Doc-to-LoRA

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent Doc-to-LoRA purpose, but setup and checkpoint loading create review-worthy code-execution risk unless users tightly control the repository, dependencies, and model files.

Install only in a trusted Doc-to-LoRA repository clone, inspect the repository's install_mac.sh before setup, prefer pinned/locked dependencies, and load only official or hash-verified checkpoints. Protect HF_TOKEN and avoid the unpinned npx install path unless you trust the installer and source revision.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/internalize.py:67
Finding
Arbitrary Code Execution Through Unsafe PyTorch Checkpoint Deserialization<![CDATA[ ## Vulnerability Details **File Location**: `scripts/internalize.py:67` **Vulnerability Type**: Unsafe deserialization of a user-selectable checkpoint **Risk Level**: High ### Vulnerable Code ```python # weights_only=False is needed: checkpoint contains config dataclasses # (AggregatorConfig, LoraConfig, HypernetConfig) not just tensors. # Only load from trusted sources. state_dict = torch.load(checkpoint_path, map_location="cpu", weights_only=False) ``` The checkpoint path is exposed through a command-line argument: ```python parser.add_argument( "--checkpoint", default="trained_d2l/gemma_demo/checkpoint-80000/pytorch_model.bin", help="Path to D2L checkpoint (only load from trusted sources)", ) ``` ### Technical Analysis `torch.load(..., weights_only=False)` supports Python pickle-compatible object deserialization. Pickle is not a data-only serialization format: specially constructed objects can invoke attacker-controlled functions while being deserialized. The `--checkpoint` option allows the caller to select an arbitrary local checkpoint. The warning that checkpoints must be trusted is documentation only and does not enforce provenance, file integrity, an approved directory, or a cryptographic digest. The default checkpoint is also obtained from an external model repository without an immutable revision or an application-level hard-coded digest. Consequently, local checkpoint replacement, a malicious checkpoint supplied by another user, or compromise of the model distribution chain can reach this dangerous deserialization operation. ### Attack Path 1. An attacker creates a malicious PyTorch checkpoint containing a serialized object with a code-execution reduction method. 2. The attacker convinces a user or agent to run the Skill with `--checkpoint /path/to/malicious.bin`, replaces the checkpoint at the default path, or compromises an upstream checkpoint source. 3. `load_model()` passes the file to `torch.load()` with `weights_ ...[truncated 784 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace pickle-based checkpoints with a data-only format such as Safetensors. 2. Use `torch.load(..., weights_only=True)` wherever possible. 3. If legacy configuration objects are unavoidable, explicitly allowlist only the minimum required classes instead of permitting unrestricted object reconstruction. 4. Pin the official checkpoint to an immutable repository revision and verify it against a hard-coded SHA-256 digest before deserialization. 5. Restrict checkpoint loading to an approved model directory and reject symbolic links or unexpected file types. 6. Treat integrity verification as mandatory and fail closed if the revision, digest, or expected checkpoint structure does not match. 7. Consider converting the trusted legacy checkpoint to a safe tensor-only representation in an isolated environment and distributing only the converted artifact. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/setup.sh:44
Finding
Execution of an Unverified Setup Script From the Enclosing Repository<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh:44-57` **Vulnerability Type**: Unverified third-party setup-script execution **Risk Level**: Medium ### Vulnerable Code ```bash if [ ! -f "install_mac.sh" ]; then echo "ERROR: install_mac.sh not found in $REPO_ROOT" echo "This skill must be used inside a doc-to-lora repository clone." echo "Clone it: git clone https://github.com/Manojbhat09/doc-to-lora-hyper-skill" exit 1 fi # 2. Install Python dependencies (via install_mac.sh which uses uv pip install) if [ ! -d ".venv" ]; then echo "[2/4] Installing Python dependencies (Mac-compatible, via uv pip install)..." bash install_mac.sh else echo "[2/4] .venv already exists, skipping dependency install." fi ``` ### Technical Analysis The Skill calculates a repository root outside its own directory and executes `install_mac.sh` from that enclosing repository. The executed file is not part of the audited Skill artifact, and the setup process does not verify its repository commit, signature, ownership, or cryptographic digest. Checking only whether the file exists does not establish that it is the expected script. Any party able to create or replace `install_mac.sh` at the calculated repository root can control all commands executed by setup. This also makes the effective setup behavior broader than the code contained in the reviewed Skill package. ### Attack Path 1. A user installs the Skill inside a modified, compromised, or incorrectly structured repository. 2. That repository contains an attacker-controlled `install_mac.sh` at the path selected by `REPO_ROOT`. 3. The user or agent runs `bash scripts/setup.sh`. 4. The existence check succeeds, and `.venv` does not yet exist. 5. `bash install_mac.sh` executes the attacker-controlled commands with the current user's privileges. ### Impact Assessment The external script receives arbitrary command-execution capability under the invoking user account. It can read ...[truncated 332 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bundle the required installation logic inside the audited Skill package. 2. If an external repository is mandatory, require a specific immutable commit and verify that the current repository is at that commit. 3. Store and verify a trusted SHA-256 digest for `install_mac.sh` before execution. 4. Reject symbolic links and ensure the resolved script path remains within the expected repository. 5. Display the verified source and revision before executing the script. 6. Fail closed when validation cannot be completed. 7. Document the complete commands and dependencies executed by the external script so the actual setup behavior can be independently audited. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/setup.sh:62
Finding
Unpinned Python Dependencies Installed From a Mutable Package Source<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh:62-64` **Vulnerability Type**: Unpinned dependency installation and suppressed installation failure **Risk Level**: Medium ### Vulnerable Code ```bash # 3. Install MLX dependencies for fast Apple Silicon inference echo "[3/4] Installing MLX dependencies (via uv pip install)..." uv pip install mlx mlx-lm safetensors 2>/dev/null || true ``` ### Technical Analysis The setup process installs `mlx`, `mlx-lm`, and `safetensors` without exact versions, hashes, or a lockfile. Each setup can therefore resolve to different package artifacts. A compromised package release, registry account, package index, or transitive dependency can introduce attacker-controlled installation or runtime code. The `|| true` suffix forces setup to continue after any installation failure, while `2>/dev/null` suppresses diagnostic output. This behavior can conceal dependency-resolution, integrity, or build failures and leave an inconsistent environment. The code contradicts the setup comments and Skill documentation claiming that dependency installations use pinned versions. ### Attack Path 1. An attacker compromises a package release, a transitive dependency, or the package source used by `uv`. 2. The user runs `scripts/setup.sh`. 3. `uv pip install` resolves the mutable latest package versions because no versions or hashes are specified. 4. A malicious package or build backend executes during installation, or malicious package code runs when `query_mlx.py` imports it. 5. Errors that might reveal an abnormal installation can be hidden by stderr redirection and ignored by `|| true`. ### Impact Assessment A malicious dependency can execute code with the privileges of the user running setup or inference. It may access project files, documents, adapters, model data, credentials in the environment, and available network resources. The absence of version locking also creates reproducibility and compatibility risks e ...[truncated 46 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin every direct and transitive dependency to an exact reviewed version. 2. Use a committed lockfile generated by `uv` and enforce locked installations. 3. Require cryptographic hashes for downloaded artifacts where supported. 4. Configure an explicit trusted package index rather than relying on ambient configuration. 5. Remove `2>/dev/null || true`; installation failures should stop setup and display actionable diagnostics. 6. Regularly review locked dependency updates and use automated vulnerability and provenance scanning. 7. Update the documentation so its dependency-pinning claims accurately reflect the enforced setup behavior. ]]>

T08 · Insecure Dependencies

Note
Location
README.md:39
Finding
Documentation Recommends Unpinned npx Installer Execution<![CDATA[ ## Vulnerability Details **File Location**: `README.md:39-42` **Vulnerability Type**: Execution of a mutable package installer without version or integrity pinning **Risk Level**: Low ### Vulnerable Code ```markdown ### From skills.sh ```bash npx skills add <owner>/doc-to-lora-skill ``` ``` ### Technical Analysis The documented installation command invokes `npx` without pinning the `skills` package to an exact reviewed version. Depending on the local npm cache and configuration, `npx` can retrieve and execute package code from a remote registry. The Skill repository reference is also represented as a mutable owner/repository identifier rather than an immutable commit. Therefore, both the installer implementation and the installed Skill content may change after this audit. This is a documentation-driven supply-chain risk rather than malicious code embedded in the supplied project. ### Attack Path 1. A user replaces the placeholder with a repository identifier and follows the documented command. 2. `npx` resolves a mutable version of the `skills` package from its configured package source. 3. A compromised or malicious package version executes as part of the installation workflow. 4. The installer may then retrieve mutable Skill content from the referenced repository. 5. The downloaded code executes with the permissions of the user running the command. ### Impact Assessment A compromised installer can execute arbitrary commands with the invoking user's privileges and can read or modify user-accessible files and credentials. It may also install altered Skill instructions or scripts that affect future agent sessions. The practical likelihood is lower than the directly invoked setup issues because exploitation requires the user to choose this optional installation method and an upstream compromise or malicious source. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the `skills` package to an exact version, for example through an explicitly reviewed `package@version` reference. 2. Pin the Skill source to an immutable commit or signed release tag. 3. Publish expected checksums or signatures for release artifacts. 4. Prefer a transparent manual installation method that copies reviewed files without executing a remotely fetched installer. 5. Document how users can verify package provenance, repository ownership, and release integrity before installation. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (5)

Credential Access

High
Category
Privilege Escalation
Content
if [ -z "$HF_TOKEN" ]; then
    echo "ERROR: HF_TOKEN is not set."
    echo "Gemma 2 2B is a gated model requiring a HuggingFace access token."
    echo "1. Get a token at: https://huggingface.co/settings/tokens"
    echo "2. Accept Gemma license at: https://huggingface.co/google/gemma-2-2b-it"
    echo "3. Run: export HF_TOKEN=hf_your_token_here"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
The README instructs users to run `npx skills add <owner>/doc-to-lora-skill` without pinning an exact package version or commit, which can cause execution of whatever package version is current at install time. If the referenced package or one of its transitive dependencies is compromised, users may execute unintended code during installation.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill describes use of environment secrets (HF_TOKEN) and file read/write operations, but it does not declare any explicit tool scope or allowed-tools restrictions. That creates an authorization gap: an agent may execute the skill with broader capabilities than intended, increasing the chance that sensitive files or environment variables are accessed or written without clear policy boundaries.

Insecure deserialization: torch.load() without weights_only=True

Medium
Category
Dangerous Code Execution
Content
# weights_only=False is needed: checkpoint contains config dataclasses
    # (AggregatorConfig, LoraConfig, HypernetConfig) not just tensors.
    # Only load from trusted sources.
    state_dict = torch.load(checkpoint_path, map_location="cpu", weights_only=False)
    if device_map != "cuda":
        state_dict["ctx_encoder_args"].quantize_ctx_encoder = False
    else:
Confidence
97% confidence
Finding
The code explicitly calls torch.load(..., weights_only=False), which uses Python pickle-style deserialization and can execute attacker-controlled code during checkpoint loading. Although the script warns to use only trusted checkpoints, the --checkpoint argument is user-controllable and the safety relies entirely on operator discipline rather than technical enforcement.

Missing User Warnings

Low
Confidence
77% confidence
Finding
This code loads a model by name using `load(args.model, ...)`, which commonly fetches model artifacts from a remote repository if not already cached. Although the script prints the model name, it does not explicitly warn users that running it may initiate network access or remote downloads.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/internalize.py:82