T09 · Insecure Skill Coding Practices
- Location
scripts/runner.py:65- Finding
Predictable Shared Temporary File Used for Pytest Reports
- Content
View full analysis
Vulnerability Details
File Location:
scripts/runner.py:65-85
Vulnerability Type: Predictable temporary file, symlink race, and stale report consumption
Risk Level: MediumVulnerable Code
python # Try to get JSON output cmd.append('--json-report') cmd.append('--json-report-file=/tmp/pytest_report.json') start_time = time.time() result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.root) elapsed = time.time() - start_time # Parse results passed = result.returncode == 0 # Parse output output = result.stdout + result.stderr # Extract test counts from output passed_count = output.count(' PASSED') failed_count = output.count(' FAILED') error_count = output.count(' ERROR') skipped_count = output.count(' SKIPPED') # Try to read JSON report try: json_report = Path('/tmp/pytest_report.json') if json_report.exists(): report_data = json.loads(json_report.read_text()) passed_count = report_data.get('summary', {}).get('passed', passed_count) failed_count = report_data.get('summary', {}).get('failed', failed_count) except: passTechnical Analysis
The test runner always instructs pytest to write its JSON report to the globally predictable path
/tmp/pytest_report.json. Shared temporary directories can be modified by other local users. An attacker can therefore create this pathname before the victim invokes the runner, including as a symbolic link to another file.When the pytest JSON-report plugin opens the supplied path, it may follow a pre-existing symbolic link and truncate or overwrite the linked file with the privileges of the user running the Skill. The target must still be writable by that user, but the attacker can influence which writable file is affected.
The runner also does not remove an existing report before starting pytest or verify that a fresh report was generated. If pytest or the reporting plugin f ...[truncated 1692 chars]
- Remediation
View remediation
Remediation Suggestions
- Create a private, unpredictable report path with
tempfile.TemporaryDirectory()ortempfile.NamedTemporaryFile(). - Place the report inside a process-specific temporary directory with permissions restricted to the invoking user.
- Pass the generated pathname to
--json-report-filerather than using a fixed/tmpfilename. - Delete or invalidate any old report before invoking pytest.
- Read the report only if the subprocess completed and a fresh regular file was produced.
- Where supported, verify that the report is not a symbolic link and is owned by the current user.
- Clean up the temporary directory in a
finallyblock. - Avoid a bare
except; catch specific exceptions and report parsing or integrity failures.
Example hardening pattern:
python import tempfile with tempfile.TemporaryDirectory(prefix='tdd-pytest-') as temp_dir: report_path = Path(temp_dir) / 'pytest-report.json' cmd.extend([ '--json-report', f'--json-report-file={report_path}', ]) result = subprocess.run( cmd, capture_output=True, text=True, cwd=self.root, ) if report_path.is_file(): report_data = json.loads(report_path.read_text(encoding='utf-8'))- Create a private, unpredictable report path with
