- Location
- scripts/fetch_explosive_articles.py:756
- Finding
- Untrusted API data is inserted into generated HTML and JavaScript without context-aware escaping<![CDATA[
## Vulnerability Details
**File Locations**:
- `scripts/fetch_explosive_articles.py:756-823,904-907`
- `scripts/gen_xhs_html.py:297,600-677`
- `scripts/xiaohongshu-similar-account.py:840-847,887-953`
- `scripts/generate_xhs_report.py:69-76`
- `assets/report_template.html:109,137-145`
**Vulnerability Type**: Stored HTML and JavaScript injection in generated reports
**Risk Level**: High
### Vulnerable Code
`scripts/fetch_explosive_articles.py:756-823` directly inserts remote fields into HTML text and attribute contexts:
```python
def get_article_html(article: dict, rank: int) -> str:
try:
title = article.get("title", "无笔记标题") or "无笔记标题"
photo_url = article.get("photoJumpUrl", "#")
user_name = article.get("userName", "未知作者")
user_url = article.get("userJumpUrl", "#")
fans = article.get("fans", "0")
desc = article.get("desc", "")
like_count = article.get("useLikeCount", "0")
collect_count = article.get("collectedCount", "0")
comment_count = article.get("useCommentCount", "0")
share_count = article.get("useShareCount", "0")
interactive_count = article.get("interactiveCount", "0")
analysis = generate_content_analysis(desc, title)
user_head_url = article.get("userHeadUrl", "")
if user_head_url:
author_html = (
f'<img src="{user_head_url}" class="author-avatar" '
f'alt="{user_name}">{user_name}({fans} 粉丝)'
)
else:
author_html = (
f'<span class="author-avatar-placeholder"></span>'
f'{user_name}({fans} 粉丝)'
)
return f'''
<div class="article-item">
<div class="article-body">
<div class="article-rank {top_class}">{rank}</div>
<div class="article-content">
<a href="{photo_url}" target="_blank"
class="
...[truncated 5745 chars]
- Remediation
- <![CDATA[
## Remediation Suggestions
1. Apply context-aware output encoding:
- Use `html.escape(value, quote=True)` for HTML text and quoted attributes.
- Do not reuse HTML escaping for JavaScript contexts.
2. Validate every remote URL before placing it in `href` or `src`:
- Permit only `https`.
- Restrict hosts to expected Xiaohongshu/CDN domains where practical.
- Reject control characters, `javascript:`, `data:`, and unexpected schemes.
3. Replace HTML string concatenation and `innerHTML` with DOM-safe operations:
```javascript
const titleLink = document.createElement('a');
titleLink.textContent = String(d.title || '--');
titleLink.href = validateUrl(d.photoJumpUrl) || '#';
titleLink.target = '_blank';
titleLink.rel = 'noopener noreferrer';
```
4. When embedding JSON in HTML:
- Prefer a non-executable `application/json` element.
- Escape `<`, `>`, `&`, U+2028, and U+2029.
- Read and parse its `textContent`.
Example:
```html
<script id="report-data" type="application/json">{{SAFE_JSON}}</script>
<script>
const RAW = JSON.parse(
document.getElementById('report-data').textContent
);
</script>
```
5. Escape the JSON server-side before insertion:
```python
works_json = json.dumps(works, ensure_ascii=False)
works_json = (
works_json
.replace("&", "\\u0026")
.replace("<", "\\u003c")
.replace(">", "\\u003e")
.replace("\u2028", "\\u2028")
.replace("\u2029", "\\u2029")
)
```
6. Add `rel="noopener noreferrer"` to links opened with `target="_blank"`.
7. Add a restrictive Content Security Policy that disallows inline and unexpected remote scripts.
8. Add regression tests using payloads containing quotes, angle brackets, event handlers, `javascript:` URLs, and closing script tags.
]]>