T09 · Insecure Skill Coding Practices
- Location
scripts/db_query.py:178- Finding
Database Password May Be Reused and Transmitted as the SSH Password
- Content
View full analysis
str: """Get password from environment variable or fall back to config file.""" db_name = db_config.get('name', '').replace(' ', '_').upper() env_var = f"{env_var_prefix}_{db_name}" env_password = os.environ.get(env_var) if env_password: return env_password return db_config.get('password', '') def query_database(description: str, query: str, config_path: str = None): """Query a database by description.""" config = load_config(config_path or CONFIG_PATH) db = find_database(config, description) if not db: print(f"Error: Database '{description}' not found") list_databases(config) sys.exit(1) print(f"\nQuerying database: {db.get('name')}") ssh_process = None tunnel_config = db.get('ssh_tunnel', {}) # Start SSH tunnel if needed if tunnel_config.get('enabled'): # Get SSH password from environment or config ssh_password = get_password(db, 'SSH_PASSWORD') if ssh_password: tunnel_config['ssh_password'] = ssh_password ``` ### Technical Analysis The shared `get_password()` function always falls back to the database-level `password` property when the requested environment variable is absent. This fallback is appropriate for a database password lookup but unsafe for an SSH password lookup. When `get_password(db, 'SSH_PASSWORD')` is called and the corresponding `SSH_PASSWORD_` variable is unset, the function returns `db['password']`. That value is then assigned to `tunnel_config['ssh_password']`. The tunnel launcher subsequently places it in the `SSHPASS` environment variable and invokes `sshpass -e`, causing the database password to be submitted t ...[truncated 1436 chars]- Remediation
View remediation
str: db_name = db_config.get('name', '').replace(' ', '_').upper() return os.environ.get( f"DB_PASSWORD_{db_name}", db_config.get('password', '') ) def get_ssh_password(db_config: Dict, tunnel_config: Dict) -> str: db_name = db_config.get('name', '').replace(' ', '_').upper() return os.environ.get( f"SSH_PASSWORD_{db_name}", tunnel_config.get('ssh_password', '') ) ``` Call the SSH-specific accessor as follows: ```python ssh_password = get_ssh_password(db, tunnel_config) ``` Additional hardening measures: - Prefer SSH public-key authentication over password authentication. - Keep database and SSH credentials in separate configuration properties. - Do not silently reuse one credential when another credential is missing. - Fail with a clear error when password-based SSH authentication is required but no SSH-specific password is configured. - Consider using a secret manager or operating-system credential store rather than plaintext configuration values. ]]>
