T09 · Insecure Skill Coding Practices
- Location
govb_email/fetcher.py:300- Finding
Predictable Shared Lock File Allows Symlink-Based File Truncation
- Content
View full analysis
Vulnerability Details
File Location:
govb_email/fetcher.py, lines 300-304
Vulnerability Type: Unsafe temporary file handling
Risk Level: MediumVulnerable Code:
python LOCK_FILE = '/tmp/govb_bidding_email.lock' try: lock_fd = open(LOCK_FILE, 'w') fcntl.flock(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)Technical Analysis
The application uses a predictable lock-file path in the globally writable
/tmpdirectory. Opening this path with modewfollows symbolic links and truncates the resolved target before the advisory lock is acquired.A local attacker who can create files in
/tmpcan place a symbolic link at/tmp/govb_bidding_email.lockpointing to another file writable by the account runninggovb-email. When the victim invokes the command,open(..., 'w')follows that link and truncates the target.The subsequent
flockdoes not prevent this attack because pathname resolution and truncation occur before the lock is applied.Attack Path
- A local attacker determines which user is expected to run
govb-email. - The attacker identifies a valuable file writable by that user, such as an application configuration or user data file.
- The attacker creates
/tmp/govb_bidding_email.lockas a symbolic link to that target. - The victim runs
govb-email. - The application follows the symbolic link while opening the lock file in write mode.
- The target file is truncated before
fcntl.flockis executed. - The affected application or user loses data or operates with a corrupted configuration.
Impact Assessment
Exploitation does not grant arbitrary code execution or access beyond the victim's existing filesystem privileges. It can, however, truncate any file writable by the account running the Skill. This may cause data loss, configuration corruption, denial of service, or secondary security consequences if a security-relevant writable file is targeted.
- A local attacker determines which user is expected to run
- Remediation
View remediation
Remediation Suggestions
- Store the lock in a user-private runtime directory, such as
$XDG_RUNTIME_DIR, after verifying that the directory is owned by the current user and is not accessible to other users. - Create the lock securely with
os.openand restrictive flags and permissions:python flags = os.O_WRONLY | os.O_CREAT flags |= getattr(os, "O_NOFOLLOW", 0) fd = os.open(lock_path, flags, 0o600) lock_fd = os.fdopen(fd, "w") fcntl.flock(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) - Validate the opened file with
os.fstatand reject non-regular files or files not owned by the current user. - Avoid deleting a shared-path lock without verifying its inode and ownership.
- Consider using a maintained lock-file library that protects against symlink and ownership attacks.
- Store the lock in a user-private runtime directory, such as
