Back to skill

Security audit

TingDong

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its podcast-generation purpose, but it sends article data and bearer tokens over unencrypted HTTP to a hard-coded service and includes an extra monitoring script outside the main user flow.

Review before installing. Only use this skill for links or text you are comfortable sending to the TingDong backend, avoid sensitive or private content, and do not send bearer tokens over the default HTTP endpoint unless the provider moves to HTTPS or you configure a trusted HTTPS backend. Treat the included monitor script as an operator utility, not part of normal podcast generation.

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

Error
Location
scripts/generate_podcast.py:16
Finding

Bearer Token and User Content Transmitted over Plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_podcast.py:16-42
Vulnerability Type: Cleartext transmission of sensitive information
Risk Level: High

Complete Code Snippet

python
BASE_URL = os.environ.get(
    "TINGDONG_API_URL",
    "http://111.229.22.145:8092/api/v1"
).rstrip("/")
API_TOKEN = os.environ.get("TINGDONG_API_TOKEN", "")


def api_post(endpoint: str, payload: dict, timeout: int = 30) -> dict:
    """POST request"""
    url = f"{BASE_URL}{endpoint}"
    data = json.dumps(payload).encode("utf-8")
    headers = {"Content-Type": "application/json"}
    if API_TOKEN:
        headers["Authorization"] = f"Bearer {API_TOKEN}"
    req = urllib.request.Request(url, data=data, headers=headers, method="POST")
    with urllib.request.urlopen(req, timeout=timeout) as resp:
        return json.loads(resp.read().decode("utf-8"))


def api_get(endpoint: str, timeout: int = 30) -> dict:
    """GET request"""
    url = f"{BASE_URL}{endpoint}"
    headers = {}
    if API_TOKEN:
        headers["Authorization"] = f"Bearer {API_TOKEN}"
    req = urllib.request.Request(url, method="GET", headers=headers)
    with urllib.request.urlopen(req, timeout=timeout) as resp:
        return json.loads(resp.read().decode("utf-8"))

The same insecure default is used by the monitoring client:

python
API_BASE = os.environ.get(
    "TINGDONG_API_URL",
    "http://111.229.22.145:8092/api/v1"
).rstrip("/")
API_TOKEN = os.environ.get("TINGDONG_API_TOKEN", "")

def api_get(endpoint: str, timeout: int = 10):
    url = f"{API_BASE}{endpoint}"
    headers = {}
    if API_TOKEN:
        headers["Authorization"] = f"Bearer {API_TOKEN}"
    return requests.get(url, headers=headers, timeout=timeout)

The plaintext endpoint is also explicitly prescribed in SKILL.md:48-72 and documented in references/api_docs.md:5-8.

Technical Analysis

The default API endpoint uses HTTP rather than HTTPS. When TINGDONG_API_TOKEN is configured, both clients at ...[truncated 2270 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace the default endpoint with an HTTPS URL backed by a valid, trusted certificate.
  2. Reject non-HTTPS API URLs whenever TINGDONG_API_TOKEN is present.
  3. Apply the transport check in both generate_podcast.py and monitor.py, before constructing or sending an authenticated request.
  4. Update SKILL.md and references/api_docs.md so all authenticated examples and returned audio links use HTTPS.
  5. If plaintext access is required for isolated development environments, require an explicit insecure-development option, display a prominent warning, and refuse to attach bearer credentials over HTTP.
  6. Rotate tokens previously used with the plaintext public endpoint because they may have been exposed in transit.
  7. Use short-lived, narrowly scoped tokens and implement server-side revocation and quota controls to reduce the impact of credential interception.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (18)

Tainted flow: 'req' from os.environ.get (line 40, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/generate_podcast.py (reported line 30)May include surrounding context.

python
if API_TOKEN:
        headers["Authorization"] = f"Bearer {API_TOKEN}"
    req = urllib.request.Request(url, data=data, headers=headers, method="POST")
    with urllib.request.urlopen(req, timeout=timeout) as resp:
        return json.loads(resp.read().decode("utf-8"))

Tainted flow: 'req' from os.environ.get (line 40, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/generate_podcast.py (reported line 41)May include surrounding context.

python
if API_TOKEN:
        headers["Authorization"] = f"Bearer {API_TOKEN}"
    req = urllib.request.Request(url, data=data, headers=headers, method="POST")
    with urllib.request.urlopen(req, timeout=timeout) as resp:
        return json.loads(resp.read().decode("utf-8"))

Tainted flow: 'url' from os.environ.get (line 18, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/monitor.py (reported line 22)May include surrounding context.

python
headers = {}
    if API_TOKEN:
        headers["Authorization"] = f"Bearer {API_TOKEN}"
    return requests.get(url, headers=headers, timeout=timeout)


class Monitor:

Tainted flow: 'FEISHU_WEBHOOK' from os.environ.get (line 12, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/monitor.py (reported line 70)May include surrounding context.

python
# 如果有飞书webhook,发送消息
        if FEISHU_WEBHOOK:
            try:
                requests.post(FEISHU_WEBHOOK, json={
                    "msg_type": "text",
                    "content": {"text": message}
                }, timeout=10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description says the skill converts articles/web links into AI-generated podcast audio with TTS. The actual code chunk instead implements infrastructure monitoring for a '听懂了' service: it polls a health endpoint, inspects disk space, and sends operational alerts. These are materially different primary purposes and undeclared capabilities unrelated to article reading or podcast generation. Therefore this is a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill invokes environment variables and outbound network access but does not declare any explicit tool scope such as permissions or allowed-tools. This creates a least-privilege gap: the agent may be granted broader capabilities than users or reviewers expect, making review and containment harder if the skill is modified or misused.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The trigger list includes phrases such as “朗读文章” and “听这篇文章”, which can overlap with ordinary user requests and may cause the skill to activate in situations where the user did not specifically intend podcast generation. Although later text adds a narrowing condition, the manifest-level trigger list itself is broad enough to create ambiguity.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

The skill sends user-supplied article URLs and authentication headers to an external service over plain HTTP to a hard-coded IP address. This exposes request contents and bearer tokens to interception or tampering in transit, and it transfers potentially sensitive reading targets/content to a third party with limited trust signals.

Content

Scanner excerpt · SKILL.md (reported line 66)May include surrounding context.

Skill 处理:

bash
# 提交任务(异步)
curl -s -X POST http://111.229.22.145:8092/api/v1/podcast/submit \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TINGDONG_API_TOKEN" \
  -d '{"content":"https://mp.weixin.qq.com/s/xxxxx","content_type":"url","style":"conversational","user_id":"user_001"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

This is a second instance of the same unsafe pattern: outbound submission of user content and bearer authentication to a non-TLS external endpoint. Repeated examples indicate the insecure transport is part of the intended design rather than an isolated documentation mistake, increasing the likelihood of credential leakage and man-in-the-middle manipulation.

Content

Scanner excerpt · SKILL.md (reported line 100)May include surrounding context.

| 默认 / 未指定 | conversational | 8-12 分钟 |

bash
curl -s -X POST http://111.229.22.145:8092/api/v1/podcast/submit \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TINGDONG_API_TOKEN" \
  -d '{"content":"https://...","style":"deep_dive","user_id":"user_001"}'

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documentation explicitly specifies plain HTTP for the API base URL and audio URLs, meaning article links, submitted text, user identifiers, task IDs, and returned media links can be intercepted or modified by any attacker on the network path. In this skill’s context, users submit potentially sensitive article content and then retrieve generated audio, so lack of transport encryption creates real confidentiality and integrity risk rather than a merely theoretical issue.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file forces a specific language/locale for all readers and does not indicate that Chinese is optional or required for a region-specific use case. The policy requires either user opt-in for language choice or clear documentation justifying the locale constraint.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script sends user-provided article URLs or full text to a third-party backend without any explicit notice, consent prompt, or privacy warning at the point of use. In this skill context, users may provide private article text or internal links, so silent transmission to a remote server meaningfully increases data exposure risk.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/monitor.py (reported line 70)May include surrounding context.

python
# 如果有飞书webhook,发送消息
        if FEISHU_WEBHOOK:
            try:
                requests.post(FEISHU_WEBHOOK, json={
                    "msg_type": "text",
                    "content": {"text": message}
                }, timeout=10)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The natural-language instructions and usage examples are entirely Chinese, which can effectively force a specific language context without stating that users may interact in other languages. The file does not offer a language choice or clarify that the locale is intentionally limited to a Chinese-language audience.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
73% confidence
Finding

The file presents all user-facing instructions and API descriptions in Chinese only, with no note that the skill is Chinese-language only or that other language options exist. Per the policy, forcing a specific language without user opt-in or documented locale justification is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The human-facing module description and operational text are presented in Chinese with no indication that language is configurable or intentionally region-specific. Under the stated policy, forcing a specific language without user opt-in can be a locale-policy issue.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The code reads TINGDONG_API_TOKEN from the environment and includes it as a Bearer token in outbound requests. This credential use is not surfaced to the user through CLI help, prompts, or other visible disclosure.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The top-level natural-language description is written entirely in Chinese and presents the script's behavior in that locale without any indication of user language choice or documented regional constraint. Under the stated policy, forcing a specific language without opt-in is a natural-language locale violation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.