T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/jmap_client.py:95
- Finding
- JMAP bearer token can be transmitted to an untrusted network endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/jmap_client.py:95-141` **Vulnerability Type**: Unrestricted credential-bearing network destination **Risk Level**: High ### Vulnerable Code ```python class FastmailJMAP: def __init__(self, token: str, *, base_url: Optional[str] = None, account_id: Optional[str] = None): self.token = token self.base_url = (base_url or os.environ.get("FASTMAIL_BASE_URL") or DEFAULT_BASE_URL).rstrip("/") self._account_id_override = account_id or os.environ.get("FASTMAIL_ACCOUNT_ID") self._session: Optional[JmapSession] = None def _headers(self) -> Dict[str, str]: return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"} def session(self) -> JmapSession: if self._session: return self._session url = self.base_url + JMAP_SESSION_PATH req = urllib.request.Request(url, headers=self._headers()) try: with urllib.request.urlopen(req, timeout=30) as r: data = json.loads(r.read()) except Exception as e: raise FastmailError(f"Failed to fetch JMAP session: {e}") api_url = data.get("apiUrl") if not api_url: raise FastmailError("JMAP session response missing apiUrl") if self._account_id_override: account_id = self._account_id_override else: accounts = data.get("accounts") or {} if not accounts: raise FastmailError("JMAP session response has no accounts") account_id = list(accounts.keys())[0] self._session = JmapSession(api_url=api_url, account_id=account_id) return self._session def call(self, method_calls: List[list], *, using: Optional[List[str]] = None) -> Dict[str, Any]: sess = self.session() for mc in method_calls: if isinstance(mc, list) and len(mc) >= 2 and isinstance(mc[1], dict): ...[truncated 2442 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require `https` for the base URL and every session-provided API URL. 2. Allowlist the expected Fastmail hostname, such as `api.fastmail.com`, unless support for another deployment is an explicit requirement. 3. Parse and canonicalize URLs with `urllib.parse.urlsplit`; reject embedded credentials, unexpected ports, fragments, and non-HTTPS schemes. 4. Verify that `apiUrl` remains on an approved origin before attaching the bearer token. 5. Apply equivalent validation to redirect destinations, or disable automatic redirects for authenticated requests and validate redirects manually. 6. Avoid permitting `FASTMAIL_BASE_URL` in normal production operation. If retained for testing, require a separate explicit development mode and never reuse production credentials. 7. Continue recommending narrowly scoped, read-only tokens and require `FASTMAIL_TOKEN_SEND` rather than falling back to a general read token for sending. ]]>
