T09 · Insecure Skill Coding Practices
Warning
- Location
- src/ioc_scan.py:153
- Finding
- Unsanitized URLs and API credentials are transmitted to VirusTotal<![CDATA[ ## Vulnerability Details **File Location**: `src/ioc_scan.py:153-195` **Vulnerability Type**: Sensitive information disclosure through third-party API requests **Risk Level**: Medium ### Vulnerable Code ```python def check_url_virustotal(url: str) -> Optional[Dict]: """Consulta URL no VirusTotal (relatório existente).""" if not VIRUSTOTAL_API_KEY: return None url_encoded = urllib.parse.quote(url, safe='') url_api = f"{VT_API_URL_V2}/url/report" params = { 'apikey': VIRUSTOTAL_API_KEY, 'resource': url } try: response = requests.get(url_api, params=params, timeout=30) if response.status_code == 200: data = response.json() if data.get('response_code') == 1: return data return None except Exception as e: print(f"[VirusTotal] Erro: {e}") return None def scan_url_virustotal(url: str) -> Optional[Dict]: """Submete URL para scan no VirusTotal.""" if not VIRUSTOTAL_API_KEY: return None url_api = f"{VT_API_URL_V2}/url/scan" data = { 'apikey': VIRUSTOTAL_API_KEY, 'url': url } try: response = requests.post(url_api, data=data, timeout=30) if response.status_code == 200: result = response.json() # Aguarda e consulta novamente time.sleep(3) return check_url_virustotal(url) return None except Exception as e: print(f"[VirusTotal Scan] Erro: {e}") return None ``` The automatic submission behavior is invoked by the following logic in `scan_ioc`: ```python elif ioc_type == 'url': print(f"[*] Consultando URL: {ioc}") vt_data = check_url_virustotal(ioc) if not vt_data: print(f"[*] Nenhum resultado, submetendo para scan...") vt_data = scan_url_virustotal(ioc) ``` ### Technical Analysis The scanner sends the complete user-supplied URL to VirusTotal w ...[truncated 3575 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Require explicit consent before submission** - Separate passive report lookup from active URL submission. - Do not automatically call the scan endpoint when no report exists. - Prompt the user before submitting an unknown URL and clearly identify VirusTotal as the recipient. 2. **Sanitize URLs before transmission** - Reject URLs containing embedded user information. - Remove fragments before lookup or submission. - Remove or redact sensitive query parameters such as `token`, `key`, `apikey`, `access_token`, `session`, `auth`, `signature`, `sig`, and password-reset parameters. - Prefer extracting and checking only the hostname when full-path analysis is not necessary. - Warn users that sanitization may reduce URL-specific reputation accuracy. 3. **Protect the VirusTotal API key** - Migrate to a supported VirusTotal API version that accepts the API key in an authorization header, where available. - Avoid placing credentials in query strings. - Ensure HTTP client, proxy, and application logging does not record authorization headers, request bodies, or sensitive query strings. - Rotate the existing key if it may already have appeared in retained logs. 4. **Provide privacy-preserving operating modes** - Add a lookup-only mode that never submits unknown URLs. - Make lookup-only behavior the default. - Add a hostname-only mode for sensitive or internal URLs. - Clearly document what data is sent, to which provider, and under what conditions. 5. **Validate destination and input** - Parse URLs with `urllib.parse.urlsplit`. - Permit only expected schemes such as HTTP and HTTPS. - Reject malformed URLs and URLs containing credentials. - Consider blocking internal hostnames and private or loopback addresses unless the user explicitly overrides the restriction. 6. **Minimize retained sensitive data** - Avoid printing complete sensitive URLs in console output. - Redact ...[truncated 154 chars]
