T09 · Insecure Skill Coding Practices
- Location
install_cron.py:74- Finding
Predictable Shared Temporary File Permits Symlink-Based File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
install_cron.py:74-79andinstall_cron.py:127-131
Vulnerability Type: Predictable temporary file / symlink following
Risk Level: MediumVulnerable Code
The cron installation path uses a fixed filename:
python temp_file = "/tmp/cron_temp.txt" with open(temp_file, "w") as f: f.write(new_cron) result = subprocess.run( ["crontab", temp_file], capture_output=True, text=True )The uninstallation path repeats the same unsafe pattern:
python temp_file = "/tmp/cron_temp.txt" with open(temp_file, "w") as f: f.write("\n".join(new_lines)) result = subprocess.run( ["crontab", temp_file], capture_output=True, text=True )Technical Analysis
/tmpis normally a shared, world-writable directory. The constant path/tmp/cron_temp.txtcan be predicted and created before the installer runs. Python's standardopen(..., "w")follows symbolic links and does not require exclusive creation.A local attacker can therefore place a symbolic link at that path pointing to another file writable by the user who runs the installer. Opening the path truncates and replaces the linked target with generated crontab content.
The implementation also does not explicitly set mode
0600. Consequently, crontab contents may be exposed to other local users depending on the process umask. Cleanup occurs only after successfulcrontabexecution, so exceptions and failed subprocess calls can leave the temporary file behind.This issue affects both installation and uninstallation. It does not independently grant root privileges: the overwrite is constrained by the filesystem permissions of the account running
install_cron.py. If the script is unnecessarily run under a privileged account, however, the potential scope increases to files writable by that account.Attack Path
- The attacker has access to the same multi-user host and can write to
/tmp. - The attacker predicts ...[truncated 1612 chars]
- The attacker has access to the same multi-user host and can write to
- Remediation
View remediation
Remediation Suggestions
Avoid filesystem-based transfer entirely by sending the new crontab through standard input:
python result = subprocess.run( ["crontab", "-"], input=new_cron, capture_output=True, text=True, timeout=30, check=False, )Apply the same approach to uninstallation.
If a temporary file is unavoidable:
- Create it with Python's
tempfilemodule using a unique, unpredictable name. - Restrict its permissions to
0600. - Keep it on a trusted local filesystem.
- Remove it in a
finallyblock, regardless of subprocess success. - Do not follow attacker-controlled symbolic links.
- Do not run the installer as root because it only needs to modify the current user's crontab.
Example:
python import os import tempfile temp_path = None try: with tempfile.NamedTemporaryFile( mode="w", encoding="utf-8", prefix="market-open-cron-", delete=False ) as temp_file: temp_path = temp_file.name os.chmod(temp_path, 0o600) temp_file.write(new_cron) result = subprocess.run( ["crontab", temp_path], capture_output=True, text=True, timeout=30, check=False, ) finally: if temp_path: try: os.unlink(temp_path) except FileNotFoundError: passAdditionally, make cron installation explicitly opt-in, display the exact entries before installation, and document that it must be run as the intended unprivileged user.
- Create it with Python's
