T09 · Insecure Skill Coding Practices
- Location
scripts/spec_manager.py:350- Finding
Arbitrary File Read and Write Through Unsanitized Brand Names
- Content
View full analysis
dict: """Load brand design-language configuration.""" brand_file = _brand_dir() / f"{brand_name}.json" if brand_file.exists(): return json.loads(brand_file.read_text(encoding="utf-8")) return { "name": brand_name, "colors": [], "fonts": [], "style_notes": "", "design_patterns": [], "avoid_patterns": [], "sample_count": 0, "generations": [], } def save_brand(brand_data: dict) -> None: """Save brand design-language configuration.""" brand_dir = _brand_dir() brand_dir.mkdir(parents=True, exist_ok=True) brand_file = brand_dir / f"{brand_data['name']}.json" brand_file.write_text( json.dumps(brand_data, ensure_ascii=False, indent=2), encoding="utf-8", ) ``` ### Technical Analysis The user-controlled `--brand` argument is passed to `load_brand()` and ultimately used directly as part of a filesystem path. The code does not reject absolute paths, parent-directory components, or path separators. With `pathlib`, joining a base directory to an absolute path discards the base directory. Relative components such as `../` can also escape the intended `~/.content-marketing/brands` directory after path resolution. The same unsafe value is retained in the brand data's `name` field and later passed to `save_brand()`. Consequently, the vulnerable flow supports both reading an existing JSON file and writing generation records to a location outside the intended state directory. ### Attack Path 1. An attacker invokes the Skill with a crafted brand value, such as: ```text --brand ../../../../tmp/attacker-controlled ``` 2. `record_generation()` calls `load_brand(brand_name)`. 3. `load_brand()` constructs ...[truncated 947 chars]- Remediation
View remediation
