T09 · Insecure Skill Coding Practices
- Location
plexctl.py:44- Finding
Plex Authentication Token Stored Without Restrictive File Permissions
- Content
View full analysis
Vulnerability Details
File Location:
plexctl.py:44-49
Vulnerability Type: Plaintext credential storage with insufficient access controls
Risk Level: HighVulnerable Code
python def save_config(cfg): """Save config to ~/.plexctl/config.json""" os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True) with open(CONFIG_PATH, "w") as f: json.dump(cfg, f, indent=2) print(f"✓ Config saved to {CONFIG_PATH}")The configuration written by this function contains the Plex authentication token:
python cfg = { "plex_url": url, "plex_token": token, "default_client": default_client } save_config(cfg)Technical Analysis
The application stores a privileged Plex authentication token in plaintext at
~/.plexctl/config.json. Neither the containing directory nor the file is assigned an explicit restrictive permission mode.When the file is created through
open(CONFIG_PATH, "w"), its effective permissions depend on the process umask. A common umask can produce a file with mode0644, allowing other local users to read it. If the file already exists with permissive permissions, opening it for writing does not repair those permissions.The directory is similarly created without explicitly enforcing mode
0700. This violates least-privilege credential-storage practices and makes the security of the token dependent on external environment configuration.Attack Path
- A user runs
plexctl setupand supplies a valid Plex authentication token. save_configwrites the token to~/.plexctl/config.json.- The file is created under a permissive umask or was previously created with overly broad permissions.
- Another local user or process reads the configuration file.
- The attacker extracts the Plex server URL and authentication token.
- The attacker submits authenticated Plex API requests using the stolen token.
Impact As
...[truncated 587 chars]
- A user runs
- Remediation
View remediation
Remediation Suggestions
- Create the configuration directory with mode
0700. - Create the configuration file with mode
0600, independently of the process umask. - Check existing permissions during loading and either reject or repair an overly permissive file.
- Write configuration changes to a securely created temporary file in the same directory, set mode
0600, flush and synchronize it, and atomically replace the destination. - Avoid following attacker-controlled symbolic links when opening the credential file.
- Prefer an operating-system credential store or keyring for the Plex token where supported.
- Do not print, log, or include the token in exception messages.
Example hardening pattern:
python def save_config(cfg): config_dir = os.path.dirname(CONFIG_PATH) os.makedirs(config_dir, mode=0o700, exist_ok=True) os.chmod(config_dir, 0o700) flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC fd = os.open(CONFIG_PATH, flags, 0o600) try: os.fchmod(fd, 0o600) with os.fdopen(fd, "w") as f: json.dump(cfg, f, indent=2) except Exception: os.close(fd) raise- Create the configuration directory with mode
