T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/crm_postgrid_mailer.py:217
- Finding
- Arbitrary CRM Base URLs Receive GHL or FUB Credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/crm_postgrid_mailer.py:217-253`, with the unrestricted CLI option at `scripts/crm_postgrid_mailer.py:620-621` **Vulnerability Type**: Credential disclosure through an unvalidated network destination **Risk Level**: High ### Vulnerable Code ```python def fetch_contacts_from_ghl(args: argparse.Namespace) -> List[Dict[str, Any]]: api_key = args.api_key or os.getenv("GHL_API_KEY") if not api_key: raise MailerError("Missing GHL API key. Set GHL_API_KEY or pass --api-key.") base_url = (args.base_url or os.getenv("GHL_BASE_URL") or DEFAULT_GHL_BASE_URL).rstrip("/") query: Dict[str, Any] = {"limit": args.limit} if args.location_id: query["locationId"] = args.location_id url = f"{base_url}/contacts/?{urllib.parse.urlencode(query)}" headers = { "Accept": "application/json", "Authorization": f"Bearer {api_key}", "Version": args.ghl_version, } payload = _http_json("GET", url, headers=headers, timeout=args.timeout) contacts = _extract_ghl_contacts(payload) return [_normalize_contact(item, "ghl") for item in contacts] def fetch_contacts_from_fub(args: argparse.Namespace) -> List[Dict[str, Any]]: api_key = args.api_key or os.getenv("FUB_API_KEY") if not api_key: raise MailerError("Missing FUB API key. Set FUB_API_KEY or pass --api-key.") base_url = (args.base_url or os.getenv("FUB_BASE_URL") or DEFAULT_FUB_BASE_URL).rstrip("/") auth_header = base64.b64encode(f"{api_key}:".encode("utf-8")).decode("ascii") query = {"limit": args.limit} url = f"{base_url}/people?{urllib.parse.urlencode(query)}" headers = { "Accept": "application/json", "Authorization": f"Basic {auth_header}", } payload = _http_json("GET", url, headers=headers, timeout=args.timeout) people = _extract_fub_people(payload) return [_normalize_contact(item, "fub") for item in people] ``` The desti ...[truncated 1915 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse endpoint overrides with `urllib.parse.urlparse`. 2. Require HTTPS for every authenticated CRM request. 3. Allowlist the exact official CRM hostnames by default: - `services.leadconnectorhq.com` - `api.followupboss.com` 4. Reject URLs containing user information, unexpected ports, fragments, or non-HTTPS schemes. 5. If custom endpoints are operationally necessary, require an explicit development-only flag and a separately supplied test credential. 6. Do not automatically reuse `GHL_API_KEY` or `FUB_API_KEY` for an unapproved origin. 7. Log the validated destination before a request without logging the Authorization header. 8. Configure CRM tokens with read-only, least-privilege scopes wherever the provider supports them. ]]>
