T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/paper_radar.py:327
- Finding
- Unescaped User Input and Remote Metadata in Exported HTML Reports<![CDATA[ ## Vulnerability Details **File Location**: `scripts/paper_radar.py`, lines 327-354 **Vulnerability Type**: HTML injection and unsafe link generation **Risk Level**: Medium ### Vulnerable Code ```python def md_to_simple_html(md_text, title="Semantic Paper Radar Report"): lines = md_text.splitlines() out = [] out.append("<!doctype html><html><head><meta charset='utf-8'>") out.append(f"<title>{title}</title>") out.append("<style>body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Arial,sans-serif;max-width:980px;margin:24px auto;padding:0 16px;line-height:1.6}h1,h2{line-height:1.3}code{background:#f2f2f2;padding:2px 4px;border-radius:4px}a{color:#0969da;text-decoration:none}a:hover{text-decoration:underline}ul{padding-left:22px}.muted{color:#666}</style></head><body>") link_pat = re.compile(r"\[([^\]]+)\]\(([^\)]+)\)") def conv_links(t): return link_pat.sub(lambda m: f'<a href="{m.group(2)}" target="_blank" rel="noopener noreferrer">{m.group(1)}</a>', t) in_list = False for ln in lines: ln = ln.rstrip() if not ln: if in_list: out.append("</ul>") in_list = False continue if ln.startswith("# "): if in_list: out.append("</ul>"); in_list=False out.append(f"<h1>{conv_links(ln[2:])}</h1>") elif ln.startswith("## "): if in_list: out.append("</ul>"); in_list=False out.append(f"<h2>{conv_links(ln[3:])}</h2>") elif ln.startswith("- "): if not in_list: out.append("<ul>"); in_list=True out.append(f"<li>{conv_links(ln[2:])}</li>") else: if in_list: out.append("</ul>"); in_list=False out.append(f"<p>{conv_links(ln)}</p>") if in_list: out.append("</ul>") out.append("<p class='muted'>Generated by semantic-paper-radar</p>") out.a ...[truncated 2656 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Escape every text node before inserting it into HTML: ```python import html safe_text = html.escape(value, quote=False) ``` 2. Escape HTML attribute values with quote escaping enabled: ```python safe_href = html.escape(url, quote=True) ``` 3. Parse link destinations with `urllib.parse.urlsplit()` and allow only explicitly approved schemes, preferably `https` and optionally `http`: ```python parsed = urllib.parse.urlsplit(url) if parsed.scheme not in {"https", "http"}: url = "" ``` 4. Escape the document title, user query, paper titles, venue names, and all other API-derived fields independently of Markdown link conversion. 5. Prefer a maintained Markdown renderer configured to: - Disable raw HTML. - Sanitize generated markup. - Reject unsafe URL schemes. - Add `rel="noopener noreferrer"` to external links. 6. Add regression tests using payloads in the query, title, venue, and URL fields, including: - HTML tags. - Quotes in link destinations. - Event-handler attributes. - `javascript:` and `data:` URLs. - Encoded or mixed-case unsafe schemes. ]]>
