T09 · Insecure Skill Coding Practices
Warning
- Location
- server.py:36
- Finding
- Runtime Directory Exposure Can Disclose Configuration and API Credentials<![CDATA[ ## Vulnerability Details **File Location**: `server.py:36-39`; related credential-loading behavior at `update.py:9-13` **Vulnerability Type**: Unrestricted static file exposure and insecure secret storage fallback **Risk Level**: Medium ### Vulnerable Code `server.py:36-39`: ```python class Handler(SimpleHTTPRequestHandler): def __init__(self, *args, **kwargs): super().__init__(*args, directory=str(ROOT), **kwargs) ``` `update.py:9-13`: ```python CONFIG = json.loads((ROOT / "config.json").read_text()) def _load_key(): k = os.environ.get("WEREAD_API_KEY") or CONFIG.get("api_key") if k: return k ``` ### Technical Analysis `SimpleHTTPRequestHandler` is configured to serve the entire runtime directory rather than an explicit allowlist of public files. Consequently, any file beneath `ROOT` may be requested through the loopback HTTP service, including `config.json`, Python and shell source files, generated HTML fragments, and any other files later placed in that directory. This becomes a credential-disclosure vulnerability because `update.py` explicitly supports loading `WEREAD_API_KEY` from the `api_key` field in `config.json`. Although the supplied default configuration does not contain a key and the documentation recommends protected settings files, the implemented fallback permits a sensitive bearer credential to be stored in a file exposed by the HTTP server. Binding to `127.0.0.1` reduces exposure to remote network clients, but it does not enforce filesystem-equivalent access control. Other local processes or users capable of connecting to the loopback port may retrieve files regardless of their filesystem permissions. Browser-based access may also be possible in some scenarios, even if cross-origin response reading is constrained by browser policy. ### Attack Path 1. The user starts `server.py`, directly or through `open-widget.sh`. 2. The helper binds to `127.0.0.1:47900` and serves all files under the runtime directo ...[truncated 972 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace unrestricted `SimpleHTTPRequestHandler` behavior with explicit route handling that serves only `widget.html` and any strictly required public assets. 2. Reject requests for configuration files, source files, logs, hidden files, and generated internal fragments. 3. Remove `CONFIG.get("api_key")` as a credential source. Load the key only from the process environment or a dedicated protected credential store. 4. If file-backed credential storage is unavoidable, place the credential outside the HTTP document root and enforce restrictive filesystem permissions such as mode `0600`. 5. Run the server from a dedicated public subdirectory containing only files intended for browser access. 6. Add automated tests verifying that requests such as `/config.json`, `/update.py`, `/server.py`, and `/helper.log` return `404` or `403`. ]]>
