T09 · Insecure Skill Coding Practices
- Location
hn-extract.py:145- Finding
Unrestricted Server-Side URL Fetching Through Attacker-Controlled Article Metadata
- Content
View full analysis
'HackerNewsExtractor': assert path.is_file(), f"json file not found: {path}" assert path.suffix == ".json", f"input file must be json: {path}" json_str = path.read_text() data = json.loads(json_str) return cls(data) ``` ```python def get_html_form_url(self, url: str): return fetch_url(url) ``` ```python def extract(self) -> str: """Extract text from the origin.""" assert self.data, "data must be populated before extract" id = self.data.get("id", "") self.id = id self.hn_id = id hn_url = f"https://news.ycombinator.com/item?id={id}" title = self.data.get("title", "") author = self.data.get("author", "") created_at = self.data.get("created_at", "") points = self.data.get("points", "") # story_id = int(self.data.get("story_id", 0)) article_url = self.data.get("url", "") children = self.data.get("children", []) self.add_line('---') self.add_line(f"title: {title}") self.add_line(f"author: {author}") self.add_line(f"created_at: {created_at}") self.add_line(f"url: {article_url}") self.add_line(f"points: {points}") self.add_line(f"hn_url: {hn_url}", width=0) self.add_line(f"comments: {len(children)}") self.add_line('---', sep="\n") self.add_paragraph(f"# {title}") self.article_html = self.get_html_form_url(article_url) ``` ### Technical Analysis The extractor accepts a local JSON file and uses its `url` property as the destination of an outbound request. The destination is passed directly to `trafilatura.fetch_url()` without validating: - The URL scheme - The destination hostname - The resolved IP address - Whether the destination belongs to a loopback, private ...[truncated 2276 chars]- Remediation
View remediation
