T09 · Insecure Skill Coding Practices
- Location
scripts/qc_chart_generator.py:451- Finding
Template Name Path Traversal Enables Unauthorized Local JSON File Access
- Content
View full analysis
Vulnerability Details
File Location:
scripts/qc_chart_generator.py:451-459
Vulnerability Type: Path traversal in template loading
Risk Level: MediumVulnerable Code
python def load_template(template_name): """Load a predefined template.""" template_dir = os.path.join(os.path.dirname(__file__), '..', 'assets', 'templates') template_path = os.path.join(template_dir, f'{template_name}.json') if not os.path.exists(template_path): return None with open(template_path, 'r', encoding='utf-8') as f: template = json.load(f)Technical Analysis
The
template_namevalue originates from the command-line--dataargument when--templateis enabled. It is appended with.jsonand joined to the intended template directory without validation, canonicalization, or a containment check.os.path.join()does not prevent traversal sequences such as../. An attacker able to control the command arguments can therefore construct a path that escapesassets/templatesand points to another readable JSON file. The existence check does not provide protection because it is performed on the attacker-influenced path.The appended
.jsonsuffix limits the issue to paths that resolve to filenames ending in.json, but it does not guarantee that the selected file resides in the authorized template directory.Attack Path
- The attacker identifies a JSON file readable by the account running the Skill.
- The attacker calculates a relative path from
assets/templatesto that file, omitting the final.jsonsuffix. - The attacker invokes the program with template mode enabled, for example:
bash python scripts/qc_chart_generator.py \ --chart-type fishbone \ --template \ --data '../../../path/to/sensitive_file' \ --output /tmp/result.png - The application appends
.json, resolves the traversal path t ...[truncated 793 chars]
- Remediation
View remediation
Remediation Suggestions
- Restrict template names to a conservative allowlist pattern such as
^[A-Za-z0-9_-]+$. - Resolve the template directory and candidate path to canonical absolute paths before opening the file.
- Verify that the resolved candidate remains a descendant of the template directory.
- Reject absolute paths, path separators,
.components, and..components. - Consider selecting templates only from an enumerated list of known files.
Example hardening approach:
python import re from pathlib import Path def load_template(template_name): if not re.fullmatch(r'[A-Za-z0-9_-]+', template_name): raise ValueError('Invalid template name') template_dir = ( Path(__file__).resolve().parent.parent / 'assets' / 'templates' ).resolve() template_path = (template_dir / f'{template_name}.json').resolve() if template_dir not in template_path.parents: raise ValueError('Template path escapes the template directory') if not template_path.is_file(): return None with template_path.open('r', encoding='utf-8') as file: template = json.load(file) return template.get('data', template)- Restrict template names to a conservative allowlist pattern such as
