T09 · Insecure Skill Coding Practices
- Location
juejin_skill/api.py:18- Finding
Authenticated HTTP Client Can Exfiltrate Session Cookies to Arbitrary Hosts
- Content
View full analysis
None: self._cookie = cookie self._timeout = timeout def _build_headers(self, extra: dict[str, str] | None = None) -> dict[str, str]: headers = {**DEFAULT_HEADERS} if self._cookie: headers["Cookie"] = self._cookie if extra: headers.update(extra) return headers def _request( self, method: str, url: str, *, json_body: dict[str, Any] | None = None, params: dict[str, Any] | None = None, extra_headers: dict[str, str] | None = None, ) -> dict[str, Any]: with httpx.Client(timeout=self._timeout) as client: resp = client.request( method, url, headers=self._build_headers(extra_headers), json=json_body, params=params, ) resp.raise_for_status() return resp.json() def get(self, url: str, **kwargs: Any) -> dict[str, Any]: """Send a GET request and return JSON.""" return self._request("GET", url, **kwargs) def post( self, url: str, json_body: dict[str, Any] | None = None, **kwargs: Any, ) -> dict[str, Any]: """Send a POST request and return JSON.""" return self._request("POST", url, json_body=json_body, **kwargs) ``` ### Technical Analysis `JuejinAPI` accepts an unrestricted URL through its public `get()` and `post()` methods. `_request()` sends the request without validating the URL scheme, hostname, port, or destination IP. At the same time, `_build_headers()` unconditionally attaches the Juejin session cookie whenever the client was initialized with one. Consequently, any caller with access to an authenticated `JuejinAPI` instance can cause the Juejin session credential to be sent to an arbitrary HT ...[truncated 1459 chars]- Remediation
View remediation
