T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/elba.py:1376
- Finding
- PIN Entry Is Echoed and Persisted as Plaintext## Vulnerability Details **File Location**: `scripts/elba.py`, lines 1376–1385 **Vulnerability Type**: Plaintext sensitive-data handling **Risk Level**: Medium ```python elba_id = input("Enter ELBA-Verfügernummer (e.g., ELVIE32V...): ").strip() pin = input("Enter PIN (5 digits): ").strip() if not elba_id or not pin: print("Error: ID and PIN are required.", file=sys.stderr) return # Write to config.json cfg = {"elba_id": elba_id, "pin": pin} CONFIG_FILE.write_text(json.dumps(cfg, indent=2) + "\n", encoding="utf-8") _harden_path(CONFIG_FILE) ``` ### Technical Analysis The setup routine obtains the banking PIN through Python's ordinary `input()` function. Unlike `getpass.getpass()`, `input()` echoes entered characters to the terminal. The PIN may consequently be exposed to shoulder surfing, terminal session recording, screen sharing, or other console-capture mechanisms. The PIN is then permanently stored as plaintext JSON. The implementation applies file mode `0600`, which reduces exposure to other local users but does not protect the PIN from processes running under the same account, workspace backup systems, malware with user-level access, or accidental copying of the workspace. This also conflicts with the setup documentation's statement that no passwords are stored. Although pushTAN approval remains necessary, the PIN is still an authentication factor and must be treated as a secret. ### Attack Path 1. A user runs the Skill's interactive `setup` command. 2. The user types the PIN into the ordinary terminal prompt. 3. The PIN is displayed or retained by a terminal recorder, remote session log, screen-sharing system, or nearby observer. 4. Alternatively, a process running as the same OS user reads the plaintext `raiffeisen-elba/config.json`. 5. The attacker obtains the ELBA ID and PIN and can initiate authentication attempts. 6. Account access would still require compromise or unauthorized approva ...[truncated 371 chars]
- Remediation
- ## Remediation Suggestions - Replace the PIN prompt with a non-echoing prompt: ```python from getpass import getpass elba_id = input("Enter ELBA-Verfügernummer: ").strip() pin = getpass("Enter PIN: ").strip() ``` - Prefer an operating-system credential store, keychain, or dedicated secret provider instead of permanent plaintext storage. - If file storage remains supported, clearly disclose that the PIN is stored locally and preserve the existing `0600` permissions and strict `0077` umask. - Reject symlinked credential files and verify ownership before reading or overwriting the configuration. - Exclude the configuration and state directories from source control, cloud synchronization, diagnostics, and workspace backups. - Update `SETUP.md` so its data-handling claims accurately describe permanent PIN storage.
