T09 · Insecure Skill Coding Practices
- Location
- scripts/pixiv.py:446
- Finding
- OAuth Bearer Token May Be Disclosed to an Unvalidated Download Host<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pixiv.py:446-472` **Vulnerability Type**: Authenticated request to an unvalidated URL **Risk Level**: High ### Vulnerable Code ```python pages = illust.get("meta_pages") or [] urls = [] if pages: for p in pages: original = p.get("image_urls", {}).get("original") if original: urls.append(original) else: original = illust.get("meta_single_page", {}).get("original_image_url") if original: urls.append(original) if not urls: print(f"作品{illust_id}无可下载原图") return False success_count = 0 for idx, url in enumerate(urls): ext = os.path.splitext(urlparse(url).path)[1] or ".jpg" save_path = save_dir / f"{illust_id}_p{idx}{ext}" if save_path.exists(): print(f"作品{illust_id}_p{idx}已存在,跳过") success_count += 1 continue headers = self._app_headers() headers["Referer"] = "https://app-api.pixiv.net/" try: resp = self.session.get(url, headers=headers, stream=True, timeout=40) ``` ### Technical Analysis The image URLs are obtained from the Pixiv API response and used without validating their scheme or destination hostname. The request headers are generated by `_app_headers()`, which includes the user's Pixiv OAuth access token in an `Authorization: Bearer ...` header. This creates a credential-forwarding vulnerability. If an image URL is unexpectedly changed to an attacker-controlled URL—such as through a compromised upstream response, malicious proxy, or service-side data integrity failure—the script sends the bearer token to that destination. Redirect behavior can create the same concern unless every redirect target is validated. Image downloads generally should not receive an account-level OAut ...[truncated 1373 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not include the Pixiv OAuth bearer token in image CDN requests unless the destination explicitly requires it. 2. Validate every download URL before issuing a request: - Require the `https` scheme. - Maintain an explicit allowlist of expected Pixiv image domains. - Reject URLs containing embedded credentials. - Reject unexpected ports. 3. Disable automatic redirects for the initial request or validate every redirect destination before following it. 4. Use a dedicated download session with no default authentication headers. 5. Construct only the minimum headers needed for image retrieval, such as an approved `Referer` and user agent. 6. Fail closed when a URL does not match the expected domain policy. 7. Revalidate the final response URL before writing response content. A safer pattern is: ```python parsed = urlparse(url) allowed_hosts = {"i.pximg.net"} if parsed.scheme != "https" or parsed.hostname not in allowed_hosts: raise ValueError("Untrusted image URL") download_headers = { "User-Agent": APP_USER_AGENT, "Referer": "https://www.pixiv.net/", } resp = self.session.get( url, headers=download_headers, stream=True, timeout=40, allow_redirects=False, ) ``` ]]>
