T09 · Insecure Skill Coding Practices
- Location
deepaistudy_errors.py:43- Finding
Credentials Are Stored in a Plaintext Configuration File and Password Values Are Echoed
- Content
View full analysis
configparser.ConfigParser: config = configparser.ConfigParser() CONFIG_DIR.mkdir(parents=True, exist_ok=True) if CONFIG_FILE.exists(): config.read(CONFIG_FILE) if not config.has_section("default"): config.add_section("default") return config def save_config(config: configparser.ConfigParser) -> None: CONFIG_DIR.mkdir(parents=True, exist_ok=True) with open(CONFIG_FILE, "w") as f: config.write(f) ``` The configuration command also prints the supplied value without checking whether it is sensitive: ```python def cmd_config(args: argparse.Namespace) -> None: """Configuration command""" if args.subcommand == "set": if not args.key or not args.value: print("Usage: deepaistudy-errors config set ") sys.exit(1) set_config_value(args.key, args.value) print(f"✓ Set {args.key} = {args.value}") ``` ### Technical Analysis The password is stored directly in an INI file without encryption or integration with an operating-system credential manager. The file is created using the process's current `umask`, and the code does not explicitly enforce owner-only permissions such as `0600`. If the file already exists with permissive permissions, rewriting it does not correct those permissions. The `config list` implementation masks the password, but `config set password ` immediately prints the unmasked value. This may expose the password through terminal capture, CI logs, agent transcripts, shell wrappers, or monitoring systems. Supplying the password as a command ...[truncated 1331 chars]- Remediation
View remediation
