T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/feynman_api.py:539
- Finding
- Unauthenticated Wildcard-CORS API Exposes Private Workspace Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/feynman_api.py`, lines 539-606 **Vulnerability Type**: Unauthenticated local API and overly permissive CORS **Risk Level**: High ### Vulnerable Code ```python def _send_json(self, payload: dict, code: int = 200) -> None: data = json.dumps(payload, ensure_ascii=False).encode("utf-8") self.send_response(code) self.send_header("Content-Type", "application/json; charset=utf-8") self.send_header("Content-Length", str(len(data))) self.send_header("Cache-Control", "no-store") self.send_header("Access-Control-Allow-Origin", "*") self.send_header("Access-Control-Allow-Methods", "GET,OPTIONS") self.send_header("Access-Control-Allow-Headers", "Content-Type,Authorization") self.end_headers() self.wfile.write(data) def do_OPTIONS(self) -> None: self.send_response(204) self.send_header("Access-Control-Allow-Origin", "*") self.send_header("Access-Control-Allow-Methods", "GET,OPTIONS") self.send_header("Access-Control-Allow-Headers", "Content-Type,Authorization") self.end_headers() ``` The following unauthenticated routes return workspace data: ```python if path == "/api/feynman/contracts": contracts = self.store.contracts() self._send_json({"contracts": contracts, "total": len(contracts)}) return if path == "/api/feynman/profile": self._send_json({"profile": {"markdown": self.store.user_profile()}}) return if len(parts) == 2 and parts[1] == "conversations": q = parse_qs(parsed.query) try: limit = int((q.get("limit") or ["5"])[0]) except ValueError: limit = 5 clause_id = (q.get("clause_id") or [""])[0].strip() or None limit = max(1, min(limit, 50)) convs = self.store.conversations(parts[0], limit, clause_id=clause_id) self._send_json({"conversations": convs, "total": len(convs)}) return if len(parts) == 2 and parts[1] == "memory": memory_text = self.store.contract_memory(parts[0 ...[truncated 2160 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Generate a cryptographically random API token for each launch and require it on every API request. 2. Reject requests without a valid `Authorization: Bearer ...` header. 3. Replace wildcard CORS with an exact allowlist containing only the intended panel origin, such as `http://127.0.0.1:19380`. 4. Validate both the `Origin` and `Host` headers. Reject unexpected origins instead of reflecting them. 5. Avoid exposing the token in URLs because URLs can leak through logs and browser history. 6. Return only the minimum fields required by the selected dashboard view. 7. Consider separating profile and conversation access behind an explicit user opt-in. 8. Add automated tests proving that unauthenticated and foreign-origin requests are rejected. 9. Keep loopback binding as defense in depth, but do not treat it as a replacement for authorization. ]]>
