T09 · Insecure Skill Coding Practices
- Location
scripts/cat_therapy.py:70- Finding
Path Traversal in Language File Selection
- Content
View full analysis
Vulnerability Details
File Location:
scripts/cat_therapy.py, lines 70–77; attacker-controlled input originates at line 106
Vulnerability Type: Path traversal and arbitrary local JSON file read
Risk Level: MediumVulnerable Code:
python def get_quote(language="zh"): """Get a random healing quote in specified language.""" i18n_dir = os.path.join(os.path.dirname(__file__), "..", "i18n") lang_file = os.path.join(i18n_dir, f"{language}.json") if os.path.exists(lang_file): with open(lang_file, 'r', encoding='utf-8') as f: data = json.load(f) quotes = data.get("quotes", [])The untrusted value is obtained from a command-line argument:
python language = sys.argv[1] if len(sys.argv) > 1 else "zh" quote = get_quote(language)Technical Analysis
The
languagevalue is incorporated into a filesystem path without an allowlist, canonicalization, or containment check. An attacker who can control the command-line argument can supply traversal sequences such as../../directory/fileor an absolute path. Because.jsonis appended, the target must be a process-readable JSON file whose name ends in.json.If the selected file contains a
quotesarray, one of its entries is returned in the program output. If the file is malformed JSON or has an unexpected top-level type, the uncaught parsing or attribute error can terminate the process.Attack Path
- The attacker gains control over the language argument passed to
scripts/cat_therapy.py. - The attacker supplies a value such as
../../target, causing the constructed path to resolve to../../target.jsonoutside the intendedi18ndirectory. - The script confirms that the path exists and opens it with the privileges of the Skill process.
- If the file is valid JSON with a
quotesarray, a randomly selected entry is exposed in the generated response. - Alternat ...[truncated 577 chars]
- The attacker gains control over the language argument passed to
- Remediation
View remediation
Remediation Suggestions
- Restrict the language value to an explicit allowlist such as
{"zh", "en"}before constructing a path. - Reject absolute paths, path separators, traversal components, and unsupported locale identifiers.
- Resolve both the intended localization directory and candidate file with
pathlib.Path.resolve(), then verify that the candidate remains beneath the localization directory. - Avoid using raw command-line input as a filename; map accepted locale identifiers to fixed filenames.
- Catch
OSError,json.JSONDecodeError, and schema/type errors and safely fall back to the default localization file. - Validate that parsed content is an object and that
quotesis a list of strings.
Example hardening approach:
python LANGUAGE_FILES = { "zh": "zh.json", "en": "en.json", } def get_quote(language="zh"): filename = LANGUAGE_FILES.get(language, LANGUAGE_FILES["en"]) lang_file = os.path.join(i18n_dir, filename)- Restrict the language value to an explicit allowlist such as
