T09 · Insecure Skill Coding Practices
Error
- Location
- src/fb_client.py:61
- Finding
- Long-Lived Facebook Access Token Transmitted in URL Query Parameters<![CDATA[ ## Vulnerability Details **File Location**: `src/fb_client.py`, lines 61–78 **Vulnerability Type**: Sensitive credential exposure through URL query parameters **Risk Level**: High ### Vulnerable Code ```python def _auth_params(self) -> dict[str, str]: return {"access_token": self.access_token} async def _request( self, method: str, endpoint: str, *, params: dict[str, Any] | None = None, data: dict[str, Any] | None = None, ) -> dict[str, Any]: merged_params = {**self._auth_params(), **(params or {})} response = await self._client.request( method, endpoint, params=merged_params, data=data, ) ``` ### Technical Analysis Every Facebook Graph API request adds the long-lived Page access token to the URL query string through the `params` argument. Sending a credential to Facebook is necessary for the declared functionality, but placing it in the query string is not the minimum-risk authentication mechanism. Although HTTPS protects the URL while it is in transit, query strings are frequently captured by HTTP client diagnostics, reverse proxies, network monitoring products, exception reports, tracing platforms, and access logs. Anyone with access to such records may recover the complete token. The destination is the official Facebook Graph API, and no covert exfiltration destination was identified. The vulnerability is the avoidable exposure surface created by the authentication mechanism. ### Attack Path 1. An operator configures the Skill with a long-lived `FB_ACCESS_TOKEN`. 2. The Skill invokes any exposed Facebook tool. 3. `_auth_params()` returns the token and `_request()` includes it in `merged_params`. 4. `httpx` constructs a request URL containing `access_token=<secret>`. 5. A proxy, diagnostic hook, tracing system, exception collector, or URL logger records the complete request URL. 6. An attacker or unauthorized log reader extracts the token. 7. The attacker submits dir ...[truncated 910 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove `_auth_params()` and do not place access tokens in query parameters. 2. Send the credential through an authorization header: ```python self._client = httpx.AsyncClient( base_url=BASE_URL, timeout=httpx.Timeout(30.0, connect=10.0), headers={ "User-Agent": "fb-page-publisher/1.0.0", "Authorization": f"Bearer {self.access_token}", }, ) ``` 3. Ensure HTTP debug logging, exception telemetry, and tracing systems redact `Authorization`, `access_token`, and other credential fields. 4. Store the token in a dedicated secret manager where possible, rather than a plaintext `.env` file. 5. Use a Page-scoped token with only the permissions required by enabled tools. 6. Separate read-only and write/destructive credentials if the deployment model supports doing so. 7. Rotate the current token if request URLs may already have been logged. 8. Establish periodic token rotation and immediate revocation procedures for suspected disclosure. ]]>
