T09 · Insecure Skill Coding Practices
- Location
scripts/hnews.py:243- Finding
Unvalidated URL Schemes in Generated HTML Links
- Content
View full analysis
str: """生成单条新闻的 HTML 卡片。""" e = html_mod.escape title = e(item['title']) url = e(item['url']) rank = item['rank'] source_html = '' if item['source']: source_html = f'{e(item["source"])}' meta_parts = [] if item['points']: meta_parts.append(f'{item["points"]} points') if item['author']: meta_parts.append(f'@{item["author"]}') if item['comments']: meta_parts.append(f'{item["comments"]} 评论') meta_html = '\n '.join(meta_parts) return f'''\ ``` The URL originates from Markdown input at line 43: ```python url = m.group(3) ``` ### Technical Analysis The converter copies a URL from an input Markdown document into an HTML `href` attribute. Although `html.escape()` prevents the URL from breaking out of the quoted attribute, it does not validate or restrict the URL scheme. Consequently, input containing a scheme such as `javascript:` can remain an executable or otherwise unsafe browser URL in the generated document. Other unwanted schemes, including crafted `data:` URLs, may facilitate deceptive navigation or delivery of attacker-controlled content, depending on browser restrictions. For example, an attacker-controlled entry could contain: ```markdown 1. [Malicious News](javascript:alert(document.domain)) (example.com) 10 points | attacker | 1 comment ``` The generated card would preserve the unsafe scheme: ```html ``` `rel=" ...[truncated 1441 chars]- Remediation
View remediation
str: url = raw_url.strip() parsed = urlsplit(url) if parsed.scheme.lower() not in {'https', 'http'}: raise ValueError(f'Unsupported URL scheme: {parsed.scheme or "missing"}') if not parsed.netloc: raise ValueError('The URL must contain a valid host') return url ``` Apply validation when parsing each item: ```python try: url = validate_news_url(m.group(3)) except ValueError as exc: print(f'Warning: skipping unsafe URL: {exc}', file=sys.stderr) i += 1 continue ``` At the rendering boundary, retain contextual escaping: ```python url = html_mod.escape(item['url'], quote=True) ``` A defense-in-depth policy can also be emitted in the document head: ```html ``` The exact policy should be tested against supported browsers and the intended standalone-file workflow. ]]>
