T09 · Insecure Skill Coding Practices
- Location
scripts/make_charts.py:21- Finding
Hard-Coded Output Directory Enables Predictable File Overwrites Outside the Project
- Content
View full analysis
Vulnerability Details
File Location:
scripts/make_charts.py:21, 129, 193, 254, 300, 355, 417, 461, 521, 574, 638, 687, 741
Vulnerability Type: Unvalidated absolute output path and predictable file overwrite
Risk Level: MediumVulnerable Code
python OUT = '/home/ubuntu/weekly_report_v3/charts' plt.savefig(f'{OUT}/fig01_overview.png', dpi=150, bbox_inches='tight') plt.savefig(f'{OUT}/fig02_refund.png', dpi=150, bbox_inches='tight') plt.savefig(f'{OUT}/fig03_traffic.png', dpi=150, bbox_inches='tight') plt.savefig(f'{OUT}/fig04_customers.png', dpi=150, bbox_inches='tight') plt.savefig(f'{OUT}/fig05_live.png', dpi=150, bbox_inches='tight') plt.savefig(f'{OUT}/fig06_cs.png', dpi=150, bbox_inches='tight') plt.savefig(f'{OUT}/fig07_products.png', dpi=150, bbox_inches='tight') plt.savefig(f'{OUT}/fig08_ads_scene.png', dpi=150, bbox_inches='tight') plt.savefig(f'{OUT}/fig09_ads_plan.png', dpi=150, bbox_inches='tight') plt.savefig(f'{OUT}/fig10_ads_daily.png', dpi=150, bbox_inches='tight') plt.savefig(f'{OUT}/fig11_content.png', dpi=150, bbox_inches='tight') plt.savefig(f'{OUT}/fig12_priority.png', dpi=150, bbox_inches='tight')Technical Analysis
The chart generator writes all generated images to a fixed absolute directory outside the project. The destination cannot be selected by the user, is not constrained to an authorized workspace, and is not validated before writing.
All output filenames are static and predictable. Matplotlib's
savefigoperation normally replaces an existing destination without requesting confirmation. The script does not check whether the destination already exists, whether it is a symbolic link, or whether the resolved destination remains inside an approved output directory.Consequently, running the script can overwrite prior reports or other files at those paths. If a local attacker can modify the hard-coded output directory, the attacker may pre-create symboli ...[truncated 1971 chars]
- Remediation
View remediation
Remediation Suggestions
- Replace the absolute path with a project-relative default or a caller-supplied command-line argument.
- Create the output directory explicitly with
pathlib.Path.mkdir(parents=True, exist_ok=True). - Resolve the requested output directory and verify that it remains beneath an approved workspace.
- Before writing each chart, reject symbolic-link destinations and unexpected non-regular files.
- Do not overwrite existing files by default. Require an explicit
--overwriteoption, generate versioned names, or use an atomic safe-write strategy. - Run the chart generator under a minimally privileged account.
- Report the final output path clearly so users can verify where artifacts were written.
Example hardened approach:
python import argparse from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[1] DEFAULT_OUTPUT = PROJECT_ROOT / "charts" parser = argparse.ArgumentParser() parser.add_argument("--output-dir", type=Path, default=DEFAULT_OUTPUT) parser.add_argument("--overwrite", action="store_true") args = parser.parse_args() output_dir = args.output_dir.expanduser().resolve() approved_root = PROJECT_ROOT.resolve() if output_dir != approved_root and approved_root not in output_dir.parents: raise ValueError("Output directory must remain inside the project workspace") output_dir.mkdir(parents=True, exist_ok=True, mode=0o700) target = output_dir / "fig01_overview.png" if target.is_symlink(): raise ValueError("Symbolic-link output targets are not allowed") if target.exists() and not args.overwrite: raise FileExistsError(f"Refusing to overwrite existing file: {target}") plt.savefig(target, dpi=150, bbox_inches="tight")
