Back to skill

Security audit

Docxtpl

Security checks for vulnerabilities and agentic risk

Overview

The skill is generally a document-generation helper, but its batch script can let CSV data control output paths and write outside the chosen folder.

Review this skill before installing if you plan to batch-render from CSV or TSV files you did not create. Avoid using --overwrite with untrusted data, inspect ID columns for path characters, and run the scripts in a limited working directory or sandbox. Pin docxtpl in controlled environments if reproducible installs matter.

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/docxtpl-render-batch.py:80
Finding
CSV-Controlled Path Traversal in Batch Output Filenames## Vulnerability Details **File Location**: `scripts/docxtpl-render-batch.py`, lines 80–100 **Vulnerability Type**: Path traversal and arbitrary file write **Risk Level**: High ### Vulnerable Code ```python for i, row in enumerate(rows): base_name = row[args.id_column].strip() if not base_name: print(f"Warning: Row {i} has empty {args.id_column}, skipping", file=sys.stderr) skipped += 1 continue output_path = out_dir / f"{base_name}{args.suffix}.docx" if output_path.exists() and not args.overwrite: print(f"Skip (exists): {output_path}", file=sys.stderr) skipped += 1 continue if args.dry_run: print(f"[DRY RUN] Would generate: {output_path}") generated += 1 continue tpl.render(row, autoescape=args.autoescape) tpl.save(str(output_path)) tpl.reset_replacements() ``` ### Technical Analysis The value used as `base_name` comes directly from the attacker-controllable CSV or TSV ID column. It is combined with the output directory without validating filename separators, parent-directory components, or absolute paths. A value such as `../../outside/report` causes the resulting path to escape the intended output directory. An absolute identifier can cause `pathlib` to disregard the configured output directory entirely. The application does not resolve the final path and verify that it remains beneath `out_dir`. The `--overwrite` option increases the impact by allowing an existing writable target to be replaced. Without that option, the script can still create a new file at an unintended writable location if the destination and its parent directories are available. ### Attack Path 1. An attacker creates or modifies the CSV/TSV data file used for batch rendering. 2. The attacker places a traversal path or absolute path in the configured ID column, for example: ```csv id,name ../../outside/report,Alice ``` 3. A user runs `docxtpl-render-batch.py` with ...[truncated 965 chars]
Remediation
## Remediation Suggestions 1. Treat the ID column as a filename identifier rather than a path: - Reject absolute paths. - Reject `/`, `\`, `..`, null bytes, and platform-specific path separators. - Allow only a conservative character set such as letters, digits, underscores, and hyphens. 2. Resolve and validate the final output path before writing: ```python import re safe_id_pattern = re.compile(r"^[A-Za-z0-9_-]+$") base_name = row[args.id_column].strip() if not safe_id_pattern.fullmatch(base_name): raise ValueError(f"Unsafe output identifier: {base_name!r}") root = out_dir.resolve() output_path = (root / f"{base_name}{args.suffix}.docx").resolve() try: output_path.relative_to(root) except ValueError: raise ValueError("Output path escapes the configured output directory") ``` 3. Validate `args.suffix` under the same filename policy because it also contributes to the resulting path. 4. Perform containment validation regardless of whether `--overwrite` is enabled. 5. Prefer exclusive creation for non-overwrite operations and avoid relying solely on a separate `exists()` check, which can introduce a time-of-check/time-of-use race. 6. Add tests covering parent traversal, absolute paths, alternate separators, symbolic links, and valid identifiers.

T08 · Insecure Dependencies

Note
Location
SKILL.md:16
Finding
Unpinned Third-Party Dependency Installation## Vulnerability Details **File Location**: `SKILL.md`, lines 16–19 **Vulnerability Type**: Unpinned dependency and supply-chain exposure **Risk Level**: Low ### Vulnerable Code ```bash pip install docxtpl # For subdocuments support: pip install "docxtpl[subdoc]" ``` ### Technical Analysis The installation instructions request `docxtpl` without a fixed version, constraints file, lock file, or package hashes. Consequently, installation resolves whatever compatible release and transitive dependencies are available from the configured Python package index at installation time. This makes installations non-reproducible and permits code that was not part of the audited project state to be installed later. The reviewed package name appears consistent with the declared project, so there is no evidence of deliberate typosquatting or dependency confusion. The risk arises from unrestricted future dependency resolution and possible upstream compromise or unexpected breaking changes. ### Attack Path 1. A user follows the documented installation command. 2. `pip` queries the configured package index and resolves the latest available `docxtpl` package and its transitive dependencies. 3. A future compromised, malicious, or unexpectedly incompatible release is selected because no audited version or hash is required. 4. Package installation hooks or imported package code execute with the privileges of the user running the installation or rendering scripts. This path depends on compromise or unsafe modification of an upstream package or package index; no such compromise was identified in the audited repository. ### Impact Assessment If an upstream dependency is compromised, malicious package code could execute with the permissions of the installing or invoking user. Potential impact could include access to files, environment variables, and network resources available to that user. The repository itself contains no evidence of a malicious dependency name, custom packag ...[truncated 179 chars]
Remediation
## Remediation Suggestions 1. Pin `docxtpl` to a reviewed version: ```bash python3 -m pip install "docxtpl==0.20.1" ``` The selected version should be verified against the version actually tested by the project. 2. Maintain a lock or constraints file that pins transitive dependencies. 3. Use hash verification, for example through a requirements file generated with trusted tooling: ```text docxtpl==<reviewed-version> --hash=sha256:<verified-hash> ``` 4. Install dependencies in an isolated virtual environment rather than into the system Python environment. 5. Configure a trusted package index explicitly in controlled deployments and review dependency updates before changing pins. 6. Add automated dependency vulnerability and integrity scanning to the release process.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The CLI example includes `-o` with an inline `# overwrite` note, but it does not clearly warn that this may replace an existing output document and affect user data. Because this is markdown guidance for a potentially destructive file operation, a more explicit warning is warranted.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
optional arguments:
  -h, --help      Show help and exit
  -o, --overwrite Overwrite existing output without confirmation
  -q, --quiet     Suppress unnecessary messages
```
Confidence
75% confidence
Finding
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.

Missing User Warnings

Low
Confidence
93% confidence
Finding
The skill documentation instructs users to save rendered output with `doc.save("output.docx")` and presents a workflow ending in `doc.save(path)`, which affects user files. In a markdown skill description, file-writing behavior should be disclosed with a brief warning when it could affect user data or existing documents.

Static analysis

No suspicious patterns detected.