T09 · Insecure Skill Coding Practices
- Location
scripts/analyze_matrix.py:73- Finding
Unescaped CSV Fields Enable Markdown Report Injection
- Content
View full analysis
= config.get("viral_threshold", 3.0) else \ "⚠️ 异常" if r["alerts"] else "✅ 正常" lines.append( f"| {r['name']} | {r['platform']} | {r['plays']:,} | " f"{r['new_fans']:,} | {r['engagement_rate']}% | " f"{r['viral_score']:.1f}x | {status} |" ) ``` ### Technical Analysis The `account_name`, `platform`, and `risk_signal` values originate from a user-supplied CSV file. These values are inserted directly into Markdown headings, list entries, bold text, and table cells without escaping Markdown metacharacters or removing line breaks. An attacker able to influence the input dataset can supply values containing table delimiters, newlines, links, images, headings, or HTML. For example, a malicious `account_name` could contain: ```text Legitimate Account ## Urgent Security Notice [Reauthenticate](https://attacker.example/login) ``` A malicious table value could contain pipe characters and newlines to terminate the intended row and inject additional rows or arbitrary Markdown. Depending on the destination renderer, an image payload such as the following could also cause a request to an attacker-controlled server when the report is viewed: ```markdown  ``` The generated report i ...[truncated 2031 chars]- Remediation
View remediation
`. - Replace carriage returns and newlines with spaces in table cells and inline labels. - Prevent raw HTML from reaching renderers that support HTML in Markdown. 3. Apply reasonable maximum lengths and, where appropriate, allowlists to fields such as `platform` and `account_name`. 4. Prefer document or messaging APIs that accept structured plain-text nodes rather than submitting concatenated Markdown. 5. Disable external image loading or sanitize image and link syntax before publishing reports when supported by the destination platform. 6. Add tests using hostile values containing pipes, newlines, headings, links, images, HTML tags, and backslashes. A context-specific helper can be introduced as follows: ```python def escape_markdown_text(value: object, *, table_cell: bool = False) -> str: text = str(value or "") text = text.replace("\r", " ").replace("\n", " ") text = text.replace("\\", "\\\\") for char in ("*", "_", "[", "]", "(", ")", "!", "<", ">"): text = text.replace(char, "\\" + char) if table_cell: text = text.replace("|", "\\|") return text ``` Apply it before constructing alerts and report rows: ```python risk_signal = escape_markdown_text(row.get("risk_signal", "")) account_name = escape_markdown_text(row.get("account_name", "Unknown")) platform = escape_markdown_text(row.get("platform", "-"), table_cell=True) if risk_signal.strip(): alerts.append(f"⚠️ Account risk: {risk_signal}") ``` When the same value is used in multiple contexts, escape it separately for each context rather than reusing a value escap ...[truncated 57 chars]
