T09 · Insecure Skill Coding Practices
- Location
- scripts/moltbook-post.py:151
- Finding
- Redis Password Transmitted in Plaintext to a Hard-Coded Network Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/moltbook-post.py`, lines 151–153 and 196–241 **Vulnerability Type**: Plaintext credential transmission to a hard-coded endpoint **Risk Level**: High ### Vulnerable Code ```python # --- Redis Rate Limiting --- REDIS_HOST = "10.0.0.120" REDIS_PORT = 6379 def REDIS_PASSWORD(): return _get("REDIS_PASSWORD", required=False) or "" ``` The password is subsequently transmitted through a raw, unencrypted TCP socket: ```python sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(3) sock.connect((REDIS_HOST, REDIS_PORT)) def send_cmd(parts): data = f"*{len(parts)}\r\n".encode('utf-8') for p in parts: encoded = str(p).encode('utf-8') data += f"${len(encoded)}\r\n".encode('utf-8') + encoded + b"\r\n" sock.sendall(data) def read_line(): line = b"" while True: byte = sock.recv(1) if not byte: break if byte == b'\r': next_byte = sock.recv(1) if next_byte == b'\n': break line += byte + next_byte else: line += byte return line def read_resp(): first = sock.recv(1) if first == b'+': return read_line().decode('utf-8') elif first == b':': return int(read_line()) elif first == b'$': length = int(read_line()) if length == -1: return None data = sock.recv(length) sock.recv(2) return data.decode('utf-8') elif first == b'-': error = read_line().decode('utf-8') raise Exception(f"Redis error: {error}") return None # Authenticate send_cmd(["AUTH", REDIS_PASSWORD()]) auth_resp = read_resp() ``` Equivalent plaintext authentication behavior is repeated in `redis_mark_posted` and `redis_check_ratelimit`. ### Technical Analysis The script retrieves `REDIS_PASSWORD` from the process environment or the workspace-level `.secrets-cache.json` file. It then ...[truncated 2596 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Remove the hard-coded endpoint** - Do not ship a fixed Redis host in the Skill. - Require an explicit `REDIS_URL` or equivalent configuration supplied by the user. - Keep Redis integration disabled unless the user affirmatively configures it. 2. **Require encrypted transport** - Support only TLS-protected Redis connections, such as `rediss://`. - Validate the server certificate and hostname. - Do not permit silent downgrade to plaintext TCP when credentials are configured. 3. **Use a maintained Redis client** - Replace the custom socket-level RESP implementation with a reputable Redis library that supports TLS, authentication, connection cleanup, and robust protocol parsing. - Pin and audit the dependency if one is introduced. 4. **Constrain secret loading** - Read only the specific credential required for an explicitly configured Redis endpoint. - Avoid automatically sourcing unrelated workspace-wide secret caches. - Do not transmit any credential until the user-configured destination has been validated. 5. **Fail safely** - If Redis is unavailable or not configured, use local deduplication without making an outbound connection. - Do not fail open for security-sensitive rate-limit or deduplication decisions without clearly informing the user. 6. **Protect credentials operationally** - Use a dedicated, unique Redis account or ACL user with access only to the required key namespace. - Rotate any Redis password that may already have been transmitted by this implementation. - Prohibit credential reuse across Redis instances or unrelated services. 7. **Improve disclosure and consent** - Document the exact destination, data transmitted, TLS requirements, and circumstances under which Redis is contacted. - Provide a dry-run or diagnostic command that displays the destination without exposing the credential. ]]>
