T09 · Insecure Skill Coding Practices
Warning
- Location
- check_ipo.py:48
- Finding
- Untrusted Remote Content Is Emitted as Agent-Facing Markdown Without Sanitization<![CDATA[ ## Vulnerability Details **File Location**: `check_ipo.py:48-55`, `check_ipo.py:84-91`, and `check_ipo.py:166-177` **Vulnerability Type**: Untrusted content injection into Markdown-formatted notifications **Risk Level**: Medium ### Complete Code Snippet ```python # Subscription data obtained from the remote website item_id = match.group(1).strip() name = match.group(2).strip() date_range = match.group(3).strip() confirmed_price = match.group(4).strip().replace(" ", "").strip() expected_price = match.group(5).strip().replace(" ", "").strip() competition = match.group(6).strip().replace(" ", "").strip() underwriter = match.group(7).strip().replace(" ", "").strip() # Listing data obtained from the remote website item_id = match.group(1).strip() name = match.group(2).strip() name = re.sub(r'<font[^>]*>[^<]*</font>', '', name).strip() listing_date_str = match.group(3).strip() current_price = match.group(4).strip().replace(" ", "").strip() ipo_price = match.group(5).strip().replace(" ", "").strip() def format_subscription(item: dict) -> str: """Format subscription item for notification.""" price = item.get("confirmed_price") or item.get("expected_price") or "-" date_str = format_date_with_weekday(item['date_range'], item['start_date']) url = item.get('url', '') name_with_link = f"[{item['name']}]({url})" if url else item['name'] return f"📋 {name_with_link}\n 청약: {date_str}\n 공모가: {price}\n 주간사: {item['underwriter']}" def format_listing(item: dict) -> str: """Format listing item for notification.""" price = item.get("ipo_price") or "-" try: listing_date = datetime.fromisoformat(item['listing_date']).date() wd = get_weekday_kr(listing_date) date_str = f"{listing_date.month:02d}/{listing_date.day:02d}({wd})" except: date_str = item['listing_date'] url = item.get('url', '') name_with_link = f"[{item['name']}]({url})" if url else item['name'] ...[truncated 2845 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Escape Markdown metacharacters before formatting remote values.** At minimum, escape characters such as `\`, `[`, `]`, `(`, `)`, `*`, `_`, `` ` ``, `~`, `>`, and `#`. 2. **Apply strict field validation.** - Limit company and underwriter names to expected Unicode letters, digits, spaces, and a small allowlist of punctuation. - Validate prices against an expected numeric and separator format. - Reject unexpected line breaks and control characters. - Enforce reasonable maximum lengths for every extracted field. 3. **Separate untrusted data from agent instructions.** Mark fetched values explicitly as external data and ensure downstream prompts state that notification content must not be interpreted as commands or policy instructions. 4. **Prefer plain-text output where rich Markdown is unnecessary.** If Markdown links are retained, construct all link destinations exclusively from locally validated identifiers and escape the visible label. 5. **Use a dedicated sanitization helper**, for example: ```python def sanitize_text(value: str, max_length: int = 120) -> str: value = re.sub(r"[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]", "", value) value = value.replace("\r", " ").replace("\n", " ") value = re.sub(r"\s+", " ", value).strip() value = value[:max_length] for char in ("\\", "[", "]", "(", ")", "*", "_", "`", "~", ">", "#"): value = value.replace(char, "\\" + char) return value ``` 6. **Apply sanitization immediately after parsing** so every later formatter receives normalized data rather than raw external content. 7. **Add security tests** containing Markdown links, multiline instruction text, control characters, oversized fields, and malformed Unicode to verify that generated alerts remain inert. ]]>
