T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/applecal.py:481
- Finding
- Basic Authentication Credentials Can Be Forwarded to Unvalidated CalDAV Discovery URLs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/applecal.py:481-550` **Vulnerability Type**: Insufficient validation of authentication destinations **Risk Level**: High ### Vulnerable Code ```python self.session = requests.Session() self.session.auth = HTTPBasicAuth(self.apple_id, self.password) self.session.headers.update({"User-Agent": user_agent, "Content-Type": "application/xml"}) # Retry on transient network errors (prefer idempotent methods to avoid duplicate writes) retry = Retry( total=MAX_RETRIES, backoff_factor=0.5, status_forcelist=[500, 502, 503, 504], allowed_methods=["GET", "HEAD", "OPTIONS", "PROPFIND", "REPORT"], ) adapter = HTTPAdapter(max_retries=retry) self.session.mount("https://", adapter) self.session.mount("http://", adapter) self.principal_url = None self.home_url = None self.outbox_url = None self.user_addresses = [] self._discover() def _request(self, method: str, url: str, **kwargs) -> requests.Response: """Wrapper around session.request with default timeout.""" kwargs.setdefault("timeout", DEFAULT_TIMEOUT) logger.debug("%s %s", method, url) resp = self.session.request(method, url, **kwargs) logger.debug("→ %s", resp.status_code) return resp ``` ```python parsed = urlparse(resp.url) server_root = f"{parsed.scheme}://{parsed.netloc}" self.principal_url = href if href.startswith("http") else urljoin(server_root, href) # 2. Calendar Home, Outbox, and User Addresses body = '''<?xml version="1.0"?> <d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav"> <d:prop> <c:calendar-home-set/> <c:schedule-outbox-URL/> <c:calendar-user-address-set/> </d:prop> </d:propfind>''' resp = self._request("PROPFIND", self.principal_url, headers={"Depth": "0"}, data=body) resp.raise_for_status() root = parse_xml(resp.text) # Home home_el = root.find(".//{urn:ietf:params:xml:ns:caldav}calendar-home-set") home_href = get_href(home_el) if not home_href: ...[truncated 2974 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Create a centralized URL-validation function and apply it before every authenticated request. 2. Require `https` and reject plain HTTP: ```python parsed = urlparse(candidate_url) if parsed.scheme != "https": raise RuntimeError("CalDAV URL must use HTTPS") ``` 3. Maintain a strict allowlist of expected Apple CalDAV hostnames or validated hostname suffixes. Avoid substring checks; compare normalized hostnames exactly or against a carefully bounded suffix. 4. Reject URLs containing unexpected user-information, nonstandard ports, fragments, or malformed hostnames. 5. Resolve relative URLs against an already validated origin, then validate the final absolute URL again. 6. Disable automatic redirects for authenticated requests or manually follow redirects only after validating each destination: ```python resp = self.session.request( method, url, allow_redirects=False, **kwargs, ) ``` 7. Avoid session-wide authentication. Attach credentials only after the final request destination has passed origin and TLS validation. 8. Remove the HTTP adapter unless cleartext HTTP is explicitly required; it is inappropriate for requests carrying calendar credentials. 9. Add tests covering absolute cross-origin URLs, HTTP downgrade URLs, hostname-suffix bypasses, user-information URLs, and cross-origin redirects. ]]>
