T05 · Unauthorized Access and Privilege Escalation
- Location
src/index.py:428- Finding
Caller-Controlled Paths Permit Unauthorized File Read and Write
- Content
View full analysis
Vulnerability Details
File Location:
src/index.py, lines 428-440
Vulnerability Type: Path traversal and unrestricted filesystem access
Risk Level: HighVulnerable Code
python async def handler(input: dict[str, Any], _context: Any) -> dict[str, Any]: skill_root = Path(__file__).resolve().parent.parent template_file = input.get("template_file") or "PPT_Template.pptx" template_path = skill_root / template_file if not template_path.exists(): raise FileNotFoundError(f"Template not found: {template_path}") mode = (input.get("mode") or "xml").strip().lower() if mode != "xml": raise ValueError("Only xml mode is supported") title = input.get("title", "Corporate Deck") output_filename = input.get("output_filename", "openclaw_generated_xml.pptx") output_path = skill_root / output_filenameThe resulting paths are subsequently used without confinement checks:
python prs = Presentation(str(template_path)) ... prs.save(str(output_path))Technical Analysis
Both
template_fileandoutput_filenameare controlled by the caller. Joining an untrusted path toskill_rootdoes not ensure that the result remains inside the skill directory:- A path containing
../can traverse outside the intended directory. - If the supplied path is absolute, Python's
pathlibdiscards the precedingskill_root. - The implementation does not call
resolve()and verify that the resolved path is beneath an approved directory. - The output path has no extension restriction, overwrite protection, or collision check.
The template input must be a file that
python-pptxcan successfully parse, which limits arbitrary reading to compatible PowerPoint files. Nevertheless, the caller can select any accessible compatible file outside the skill directory. More critically, the output operation can create or overwrite any file writable by the skil ...[truncated 1415 chars]- A path containing
- Remediation
View remediation
Remediation Suggestions
- Define separate, explicit directories for approved templates and generated output.
- Reject absolute caller-supplied paths.
- Resolve each candidate path and verify that it remains beneath the corresponding approved directory.
- Restrict both template and output files to the
.pptxextension. - Treat caller input as a filename rather than an unrestricted path when subdirectories are unnecessary.
- Refuse to overwrite existing files unless overwrite behavior is explicitly authorized.
- Ensure the output path cannot equal the template path.
- Run the skill under a dedicated account with minimal filesystem permissions.
Example hardening logic:
python def confined_pptx_path(base: Path, supplied: str) -> Path: if not supplied: raise ValueError("A filename is required") untrusted = Path(supplied) if untrusted.is_absolute(): raise ValueError("Absolute paths are not allowed") if untrusted.suffix.lower() != ".pptx": raise ValueError("Only .pptx files are allowed") resolved_base = base.resolve() candidate = (resolved_base / untrusted).resolve() if not candidate.is_relative_to(resolved_base): raise ValueError("Path escapes the approved directory") return candidate template_path = confined_pptx_path(template_directory, template_file) output_path = confined_pptx_path(output_directory, output_filename) if output_path == template_path: raise ValueError("Output path cannot overwrite the template") if output_path.exists(): raise FileExistsError(f"Output already exists: {output_path}")Where atomic output creation is required, write to a securely created temporary file inside the approved output directory and atomically rename it after successful generation.
