Back to skill

Security audit

Daum Trends

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent Daum trend briefing skill, with a real but limited formatting risk when remote trend text is rendered as Markdown.

Install this only if you want a Korean Daum trends notifier that makes outbound requests to Daum. If you pipe the default Markdown output into Telegram, Discord, or another renderer, consider using plain/html output or adding Markdown escaping first, because trend titles come from remote pages. Configure the cron example only if scheduled public or channel announcements are intended.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/trends.py:75
Finding

Unescaped Remote Content in Default Markdown Output

Content
View full analysis

Vulnerability Details

File Location: scripts/trends.py, lines 75–79
Vulnerability Type: Markdown injection through untrusted remote content
Risk Level: Medium

Vulnerable Code

python
def fmt_line_markdown(rank, kw, title, url):
    short = (title[:45] + "…") if len(title) > 48 else title
    if short:
        return f"{rank}. [{kw}]({url}) — {short}"
    return f"{rank}. [{kw}]({url})"

The affected values originate from remote Daum pages through the following code:

python
word = kw.get("keyword", kw.get("text", f"#{i+1}"))
url = search_url(word)
title = ""
try:
    search_html = fetch(url)
    title = extract_title(search_html)
except Exception:
    pass

Technical Analysis

The default Markdown formatter inserts the remotely sourced kw and title values directly into Markdown without escaping Markdown metacharacters or removing control characters.

A crafted keyword containing characters such as ], (, or ) can terminate or restructure the generated link. A crafted title can introduce links, mentions, formatting, or instruction-like text. The title extractor increases exposure because it heuristically accepts the first anchor text of a qualifying length from up to 200,000 characters of the remote search page rather than restricting extraction to a trusted news-result selector.

Although the HTML formatter escapes visible keyword and title text, Markdown is the default output format. The generated output is explicitly intended for automated Telegram or Discord delivery, where Markdown syntax may be rendered and become deceptive or interactive.

Attack Path

  1. An attacker causes crafted text to appear as a trend keyword or qualifying anchor title on content returned by the fetched Daum pages.
  2. extract_trends() accepts the keyword, or extract_title() selects the crafted anchor text as a representative title.
  3. main() passes the remotely controlled value to fmt_line_markdown().
  4. The formatter inte ...[truncated 917 chars]
Remediation
View remediation

Remediation Suggestions

  1. Escape all Markdown metacharacters in remotely sourced keywords and titles using the exact escaping rules required by the destination platform, such as Telegram MarkdownV2 or Discord Markdown.
  2. Remove carriage returns, line feeds, bidirectional-control characters, zero-width characters, and other control characters before formatting.
  3. Prefer plain-text output as the default when the downstream renderer is unknown.
  4. Replace the broad anchor-matching heuristic with a structured parser and selectors limited to the intended news-result elements.
  5. Enforce conservative character and length policies after HTML decoding.
  6. Keep destination URLs generated exclusively from the fixed HTTPS search base and URL-encoded keyword.
  7. Add tests covering payloads such as ]([malicious URL]), embedded mentions, nested formatting, newlines, and Unicode direction-control characters.

A platform-specific escaping helper should be applied before interpolation, for example:

python
def escape_markdown(text: str) -> str:
    text = re.sub(r"[\r\n\x00-\x1f\x7f]", " ", text)
    return re.sub(r"([\\`*_{}\[\]()#+\-.!|>])", r"\\\1", text)

def fmt_line_markdown(rank, kw, title, url):
    kw_safe = escape_markdown(str(kw))
    short = (title[:45] + "…") if len(title) > 48 else title
    short_safe = escape_markdown(short)
    if short_safe:
        return f"{rank}. [{kw_safe}]({url}) — {short_safe}"
    return f"{rank}. [{kw_safe}]({url})"

The final implementation must be adjusted to the Markdown dialect used by the delivery API.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill documents and encourages network access to external sites (daum.net and search.daum.net) but does not declare any explicit tool scope or permissions. This creates a governance and containment gap: an agent may be allowed to make outbound requests without a clearly declared boundary, making review, policy enforcement, and least-privilege controls harder.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The description is written as a Korean-only briefing skill and explicitly says to use it when the user asks for Korean real-time search trends, but it does not state whether output language is optional or user-selectable. This can violate language/locale policy when a skill implicitly constrains interaction to a specific language without opt-in or justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This file presents its purpose in Korean and later emits Korean user-facing strings, which imposes a specific language/locale without any user selection mechanism. Under the policy, forcing a language without opt-in is a natural-language policy violation unless the locale constraint is clearly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The error/output strings such as "트렌드 데이터 없음" and the trend header are fixed in Korean, with no indication that the user can choose another language. This creates a language policy issue because the skill forces a locale in normal operation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.