T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/wifi_setup.py:60
- Finding
- Persistent WebREPL Provisioning Exposes Plaintext Credentials and Bypasses Dangerous-Operation Confirmation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/wifi_setup.py:60-110, 127-128` **Vulnerability Type**: Plaintext credential storage, credential disclosure, predictable default password, and unsafe persistent configuration **Risk Level**: High ### Vulnerable Code ```python # Configure WebREPL password try: with open("webrepl_cfg.py", "w") as f: f.write("PASS = " + repr(webrepl_password) + "\n") print("LOG:WebREPL password configured") except Exception as e: print("ERROR:Failed to write webrepl_cfg.py: " + str(e)) raise SystemExit # Enable WebREPL try: import webrepl webrepl.start() print("LOG:WebREPL started on port 8266") except Exception as e: print("ERROR:Failed to start WebREPL: " + str(e)) raise SystemExit # Write boot.py for auto-connect on power-up boot_code = ''' import network, time sta = network.WLAN(network.STA_IF) sta.active(True) sta.connect({ssid!r}, {password!r}) for _ in range(30): if sta.isconnected(): break time.sleep(0.5) import webrepl webrepl.start() ''' try: # Backup existing boot.py try: with open("boot.py", "r") as f: backup = f.read() with open("boot.py.bak", "w") as f: f.write(backup) print("LOG:Existing boot.py backed up to boot.py.bak") except OSError: pass with open("boot.py", "w") as f: f.write(boot_code) print("LOG:boot.py updated for auto-connect") except Exception as e: print("ERROR:Failed to write boot.py: " + str(e)) raise SystemExit print("RESULT:" + json.dumps({ "ip": ip, "webrepl_port": 8266, "webrepl_password": webrepl_password })) ``` ```python parser.add_argument( "--webrepl-password", default="micropython", help="WebREPL access password (default: micropython)" ) ``` ### Technical Analysis The provisioning script writes the WiFi password into `boot.py` and the WebREPL password into `webrepl_cfg.py` as plaintext. It then configure ...[truncated 2502 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Do not accept WiFi or WebREPL passwords directly through command-line arguments. Read them from an interactive no-echo prompt, a protected file descriptor, or another secret-handling mechanism. - Never include passwords in `RESULT:`, `LOG:`, exception text, or other captured output. - Remove the predictable default WebREPL password. Require a unique, sufficiently long password or generate one using a cryptographically secure random source. - Require explicit, informed confirmation immediately before modifying `boot.py`. - Clearly disclose that the native MicroPython configuration stores credentials in plaintext on the device. - Make persistent auto-start optional rather than an implicit part of WiFi setup. - Abort if the existing `boot.py` cannot be backed up, unless the user separately confirms replacement without a backup. - Preserve existing startup logic through a dedicated configuration module or carefully reviewed merge rather than replacing `boot.py` wholesale. - Apply restrictive permissions or platform-appropriate protections where the device filesystem supports them. - Provide a supported deprovisioning command that disables WebREPL and securely removes stored credentials. ]]>
