T09 · Insecure Skill Coding Practices
- Location
scripts/crawl_douban_self_history.py:300- Finding
Unrestricted Request Destinations Combined with Unvalidated Cookie Domains
- Content
View full analysis
str | None: soup = BeautifulSoup(html, "lxml") next_el = soup.select_one("span.next a") or soup.select_one("a.next") if not next_el: return None href = next_el.get("href", "").strip() return urljoin(current_url, href) if href else None ``` ```python def crawl_category(client: httpx.Client, uid: str, category: str, interval: float, page_limit: int | None) -> dict[str, Any]: items: list[Item] = [] page_count = 0 for status in STATUSES: next_url = build_start_url(uid, category, status) while next_url: page_count += 1 resp = client.get(next_url) resp.raise_for_status() html = resp.text if looks_like_login_or_auth_problem(html, str(resp.url)): raise RuntimeError(f"Authentication failed while fetching {resp.url}") source_name = f"{category}-{status}-page-{page_count}.html" items.extend(parse_page(category, html, status, str(resp.url), source_name)) if page_limit and page_count >= page_limit: next_url = None else: next_url = parse_next_page_url(html, str(resp.url)) if next_url: time.sleep(interval) ``` ```python def make_client(cookie_file: Path, timeout: float) -> httpx.Client: raw = load_cookies(cookie_file) client = httpx.Client(timeout=timeout, follow_redirects=True, headers={"User-Agent": "Mozilla/5.0 OpenClaw DoubanSelfTasteSkill"}) for item in raw: name = item.get("name") value = item.get("value") domain = item.get("domain") path = item.get("path", "/") if not name or value ...[truncated 2634 chars]- Remediation
View remediation
str: parsed = urlparse(url) if parsed.scheme != "https" or parsed.hostname not in ALLOWED_HOSTS: raise RuntimeError(f"Refusing unexpected outbound URL: {url}") return url ``` 6. Prefer a dedicated cookie jar containing only the minimum Douban cookies required for authentication. 7. Document that users must not provide an unrestricted whole-browser cookie export. ]]>
