T09 · Insecure Skill Coding Practices
- Location
bidding_report.py:304- Finding
Predictable Intermediate Chart Files Permit File Clobbering and Symlink Attacks
- Content
View full analysis
Vulnerability Details
File Location:
bidding_report.py:203-252,bidding_report.py:304-315,bidding_report.py:357-368, andbidding_report.py:445-459
Vulnerability Type: Insecure temporary-file handling
Risk Level: MediumThe report generator writes intermediate charts to predictable filenames in the current working directory. It does not create a private temporary directory, reject existing files, prevent symbolic-link traversal, or remove the files after embedding them in the report.
Relevant code:
python def _create_nested_pie(self, data, title, filename): # ... plt.tight_layout() plt.savefig(filename, dpi=150, bbox_inches='tight', facecolor='white') plt.close() return filename def _create_percent_bar(self, data, title, filename): # ... plt.tight_layout() plt.savefig(filename, dpi=150, bbox_inches='tight', facecolor='white') plt.close() return filenamePredictable global chart names are assigned as follows:
python # Insert overall nested donut chart chart_file = 'chart_overall.png' self.generate_chart( 'nested_pie', { 'ai_count': total['ai_count'], 'total_count': total['proj_count'], 'ai_amount': total['ai_amount'], 'total_amount': total['total_amount'] }, f"AI project count and amount ratio analysis\n" f"Total projects {total['proj_count']:,} | AI projects {total['ai_count']:,}", chart_file )python # Insert yearly percentage bar chart chart_file = 'chart_yearly.png' self.generate_chart( 'percent_bar', self.stats['yearly'], 'Annual AI bidding ratio trend', chart_file )Organization-derived filenames are also written into the current directory:
python safe_name = org_name.replace('/', '_').replace('\\', '_') chart_file = f'chart_{safe_name}_pie.png' self.generate_chart( 'nested_pie', ...[truncated 2755 chars]- Remediation
View remediation
Remediation Suggestions
-
Create a private temporary directory for each report-generation operation:
python import tempfile from pathlib import Path with tempfile.TemporaryDirectory(prefix="bidding-report-") as temp_dir: chart_file = Path(temp_dir) / "overall.png" self.generate_chart( "nested_pie", chart_data, chart_title, str(chart_file) ) doc.add_picture(str(chart_file), width=Inches(6)) doc.save(output_path) -
Keep all intermediate charts inside that private directory and allow
TemporaryDirectoryto remove them after the document has been saved. -
Use generated identifiers rather than organization names for filesystem paths. Organization names should appear only in chart content:
python import uuid chart_file = Path(temp_dir) / f"{uuid.uuid4().hex}.png" -
Do not run the application from shared or attacker-writable directories, especially when using a privileged account.
-
If charts must be retained, require an explicit chart-output directory, verify that it is trusted, and reject existing destination files or create them atomically with protections against symbolic links.
-
Validate and resolve the final output path against an approved output directory when the application is deployed as a service or invoked with untrusted arguments.
-
