T09 · Insecure Skill Coding Practices
- Location
SKILL.md:88- Finding
Untrusted Converter Executable Resolution Enables Arbitrary Code Execution
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 88-93, 96-98, 126-131, and 168-176
Vulnerability Type: Untrusted executable resolution and PATH hijacking
Risk Level: HighVulnerable Code
python # Default converter paths DEFAULT_CONVERTERS = { 'revit': 'RvtExporter.exe', 'ifc': 'IfcExporter.exe', 'dwg': 'DwgExporter.exe', 'dgn': 'DgnExporter.exe' } def __init__(self, converter_dir: str = ".", converters: Dict[str, str] = None): self.converter_dir = Path(converter_dir) self.converters = converters or self.DEFAULT_CONVERTERSpython def _get_converter(self, format_name: str) -> Optional[Path]: """Get converter path for format.""" if format_name not in self.converters: return None converter = self.converter_dir / self.converters[format_name] if converter.exists(): return converter # Try in system PATH return Path(self.converters[format_name])python # Build command cmd = [str(converter), str(input_path)] if options: cmd.extend(options) # Execute try: result = subprocess.run(cmd, capture_output=True, text=True, timeout=3600)Technical Analysis
The converter directory defaults to the current working directory (
"."), while the default converter definitions are relative executable names._get_converter()first trusts any matching file in that directory based only on its existence. It does not verify that the file is a regular executable from a trusted installation directory, nor does it validate its owner, publisher signature, or cryptographic hash.If no matching file exists there, the method returns another relative path containing only the executable name. Passing that value to
subprocess.run()causes operating-system executable search behavior to apply, potentially selecting a malicious binary from an attacker-controlled directory in `PA ...[truncated 1742 chars]- Remediation
View remediation
Remediation Suggestions
- Require every converter to be configured using an explicit absolute path. Reject relative paths and bare executable names.
- Remove the default current-directory lookup and do not fall back implicitly to
PATH. - Canonicalize configured paths with
Path.resolve(strict=True)before execution. - Enforce an allowlist of trusted installation directories and verify that the resolved executable remains within one of those directories.
- Confirm that the resolved path is a regular file and is not an unexpected symbolic link or reparse-point redirection.
- Where supported, validate the executable's publisher signature or compare its cryptographic hash against an administrator-managed allowlist.
- Ensure converter installation directories and configuration files are not writable by untrusted users.
- Continue invoking the process with an argument list and without
shell=True. - Document native process execution as a required capability instead of declaring only filesystem access.
- Fail closed when a validated converter cannot be found, and report a configuration error rather than searching untrusted locations.
