T09 · Insecure Skill Coding Practices
Warning
- Location
- academic_citation_skill.py:510
- Finding
- Unvalidated Crossref API Base URL Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `academic_citation_skill.py:510-586` **Vulnerability Type**: Server-Side Request Forgery through an unvalidated configurable API endpoint **Risk Level**: Medium ### Vulnerable Code ```python def _load_config(self, config_file: str) -> Dict: """加载配置文件""" config_path = Path(__file__).parent / config_file try: with open(config_path, 'r', encoding='utf-8') as f: return json.load(f) except FileNotFoundError: return { "api_base": "https://api.crossref.org", "rate_limit": 10, "cache_ttl": 86400 } def fetch_by_doi(self, doi: str) -> Optional[Dict]: """通过DOI获取文献信息""" cache_key = f"doi_{doi}" if cache_key in self.cache: logger.info(f"Using cached result for DOI: {doi}") return self.cache[cache_key] self._rate_limit_wait() try: url = f"{self.config['api_base']}/works/{doi}" logger.info(f"Fetching DOI from: {url}") response = self.session.get(url, timeout=15) if response.status_code == 200: data = response.json() result = self._parse_crossref_response(data) self.cache[cache_key] = result logger.info(f"Successfully fetched reference: {result.get('title', 'Unknown')}") return result elif response.status_code == 404: logger.warning(f"DOI not found: {doi}") else: logger.error(f"Failed to fetch DOI {doi}: HTTP {response.status_code}") except requests.exceptions.Timeout: logger.error(f"Timeout fetching DOI: {doi}") except Exception as e: logger.error(f"Error fetching DOI {doi}: {str(e)}") return None def search_by_title_author(self, title: str, author: str = None, year: int = None, max_results: int = 10) -> List[Dict]: """通过标题和作者搜索文献""" self._rate_limit_wait() try: para ...[truncated 3385 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Allowlist the official service** - Permit only `https://api.crossref.org` unless custom providers are an explicit product requirement. - Compare normalized hostnames rather than using substring or suffix checks. 2. **Require secure URL properties** - Require the `https` scheme. - Reject embedded usernames or passwords. - Reject fragments and unexpected ports. - Normalize the URL before validation and use a URL-joining function rather than direct string concatenation. 3. **Block internal destinations** - Resolve all destination addresses before making a request. - Reject loopback, private, link-local, multicast, reserved, and unspecified IPv4 and IPv6 addresses. - Account for hosts that resolve to multiple addresses and DNS rebinding. 4. **Control redirects** - Prefer `allow_redirects=False`. - If redirects are necessary, validate the scheme, hostname, port, and resolved address of every redirect target before following it. 5. **Restrict custom configuration** - Require explicit user approval before enabling a nondefault API provider. - Treat configuration files from imported archives or untrusted project directories as untrusted input. - Fail closed when configuration parsing or endpoint validation fails. 6. **Reduce query disclosure** - Clearly notify users when search metadata will be sent to a nondefault provider. - Avoid logging full sensitive query strings where they are not operationally necessary. 7. **Add security tests** - Test rejection of `localhost`, `127.0.0.1`, `[::1]`, RFC1918 addresses, link-local addresses, cloud metadata addresses, embedded credentials, non-HTTPS schemes, unusual ports, and redirects to blocked networks. ]]>
