Back to skill

Security audit

Youdao Note Web

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-built for Youdao notes, but it asks for a full browser login cookie and can bulk-read or create notes without built-in confirmation controls.

Review before installing. Treat YOUDAO_COOKIE like a password for the Youdao account, avoid storing it longer than needed, rotate it after use, and only run bulk reads or note creation when you have clearly chosen the target folder or note. Use an isolated environment and consider pinning dependencies before installation.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
youdao_api.py:11
Finding

Full Browser Cookie Is Collected and Forwarded Beyond the Required Cookie Set

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
youdao_api.py:78
Finding

Authentication Token Is Repeatedly Embedded in Request URLs

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Third-Party Dependencies Are Installed Without Version or Integrity Pinning

Content
View full analysis
Remediation
View remediation
brotli== ``` 2. Generate and verify cryptographic hashes, and install with: ```bash pip install --require-hashes -r requirements.txt ``` 3. Use a lockfile or a compiled requirements file that also pins transitive dependencies. 4. Configure installation to use an approved package index over HTTPS and disable unexpected extra indexes. 5. Use automated dependency vulnerability scanning and review updates before changing pinned versions. 6. Install dependencies in an isolated virtual environment under a non-privileged account. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (28)

Tainted flow: 'url' from os.getenv (line 352, 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 · youdao_api.py (reported line 81)May include surrounding context.

python
url = f"{BASE_URL}/yws/api/personal/file?method=getByPath&keyfrom=web&cstk={cstk}"
    headers = build_headers()
    data = {"file": "/", "method": "getByPath", "keyfrom": "web", "cstk": cstk}
    response = requests.post(url, headers=headers, data=data)
    
    if response.status_code == 400:
        url_get = f"{BASE_URL}/yws/api/personal/file?method=getByPath&keyfrom=web&file=%2F&cstk={cstk}"

Tainted flow: 'url' from os.getenv (line 352, 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 · youdao_api.py (reported line 368)May include surrounding context.

python
url = f"{BASE_URL}/yws/api/personal/file?method=getByPath&keyfrom=web&cstk={cstk}"
    headers = build_headers()
    data = {"file": "/", "method": "getByPath", "keyfrom": "web", "cstk": cstk}
    response = requests.post(url, headers=headers, data=data)
    
    if response.status_code == 400:
        url_get = f"{BASE_URL}/yws/api/personal/file?method=getByPath&keyfrom=web&file=%2F&cstk={cstk}"

Tainted flow: 'url_get' from os.getenv (line 84, 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 · youdao_api.py (reported line 85)May include surrounding context.

python
if response.status_code == 400:
        url_get = f"{BASE_URL}/yws/api/personal/file?method=getByPath&keyfrom=web&file=%2F&cstk={cstk}"
        response = requests.get(url_get, headers=headers)
        
    if response.status_code != 200:
        print("Warning: Failed to get root directory via API. You may need to specify --dir explicitly.", file=sys.stderr)

Tainted flow: 'url' from os.getenv (line 352, 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 · youdao_api.py (reported line 102)May include surrounding context.

python
cstk = get_cstk()
    url = f"{BASE_URL}/yws/api/personal/file/{dir_id}?all=true&f=true&len=100&sort=1&isReverse=false&method=listPageByParentId&keyfrom=web&cstk={cstk}"
    headers = build_headers()
    response = requests.get(url, headers=headers)
    if response.status_code != 200:
        print(f"Error in list_files: {response.text}", file=sys.stderr)
    response.raise_for_status()

Tainted flow: 'url' from os.getenv (line 352, 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 · youdao_api.py (reported line 144)May include surrounding context.

python
if root_dir:
        params["parentId"] = root_dir

    response = requests.post(url, headers=headers, params=params, data={"cstk": cstk})
    if response.status_code != 200:
        print(f"Error in search_notes: status={response.status_code} body={response.text}", file=sys.stderr)
    response.raise_for_status()

Tainted flow: 'url' from os.getenv (line 352, 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 · youdao_api.py (reported line 382)May include surrounding context.

python
"convert": "true",
        "cstk": cstk
    }
    response2 = requests.post(url, headers=headers, data=data_no_editor)
    if response2.status_code == 200:
        content = process_response_content(response2)
        if content and "当前客户端版本过低" not in content and "当前笔记内容暂时无法查看" not in content:

Tainted flow: 'url_new_format' from os.getenv (line 389, 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 · youdao_api.py (reported line 390)May include surrounding context.

python
# Third attempt: try fallback endpoint for new doc formats
    url_new_format = f"{BASE_URL}/yws/api/personal/file/{file_id}?method=download&all=true&f=true&len=30&sort=1&isReverse=false&keyfrom=web&cstk={cstk}"
    response3 = requests.get(url_new_format, headers=headers)
    if response3.status_code == 200:
        content = process_response_content(response3)
        if content and "当前客户端版本过低" not in content and "当前笔记内容暂时无法查看" not in content:

Tainted flow: 'url_get2' from os.getenv (line 397, 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 · youdao_api.py (reported line 398)May include surrounding context.

python
# Fourth attempt: try basic sync download
    url_get2 = f"{BASE_URL}/yws/api/personal/sync?method=download&keyfrom=web&id={file_id}&cstk={cstk}"
    response4 = requests.get(url_get2, headers=headers)
    if response4.status_code == 200:
        content = process_response_content(response4)
        if content:

Tainted flow: 'push_params' from os.getenv (line 443, 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 · youdao_api.py (reported line 500)May include surrounding context.

python
"transactionTime": now,
        "transactionId": file_id
    }
    push_resp = requests.post(push_url, headers=headers, params=push_params, data=push_payload)
    last_push_resp = push_resp
    if push_resp.status_code == 200:
        push_result = parse_push_result(push_resp, note_name)

Tainted flow: 'url' from os.getenv (line 352, 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 · youdao_api.py (reported line 516)May include surrounding context.

python
]
    last_response = last_push_resp
    for payload in payload_candidates:
        response = requests.post(url, headers=headers, params=params, data=payload)
        last_response = response
        if response.status_code == 200 and note_exists_in_parent(note_name):
            result = response.json()

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill claims to operate 'safely' and highlights read/search/create, but the content also enables undeclared directory listing and bulk reading of all notes in a folder, while relying on a full browser cookie that may grant broad account access. This mismatch can mislead users and orchestration systems about the real data access breadth, increasing the risk of unexpected mass disclosure of private notes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README instructs users to extract and store a full authenticated browser cookie, including session-bearing values, in an environment variable so the skill can access their account. This exposes reusable credentials that may be leaked through process inspection, shell history, logs, crash reports, or other tooling, and it normalizes unsafe credential handling without warning users about account takeover risk.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill declares no explicit tool scope or permission boundary even though it requires environment-variable secrets and network access. Without declared limits, an agent may invoke a capability that can access authenticated note data using a high-privilege browser cookie, reducing transparency and making overreach harder to detect or control.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The activation text says to call the skill whenever the user asks to operate on Youdao notes, which is broad and may trigger the skill for loosely related prompts without sufficient narrowing or confirmation. In a skill that can access authenticated personal notes, broad invocation conditions increase the chance of unnecessary data access or unintended actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The markdown explicitly instructs the agent to read all notes in a directory in one operation, but it does not warn about the privacy implications or require explicit user acknowledgment for mass content access. Bulk extraction materially raises the blast radius versus single-note reads, especially for personal or work logs that may contain sensitive information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill depends on a full browser session cookie stored in YOUDAO_COOKIE, which is highly sensitive and effectively grants account access. Without strong disclosure and safer secret-handling patterns, users or operators may expose long-lived session credentials to logs, process listings, or broader runtime access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The code automatically transmits the full authenticated cookie header on every request, but the skill metadata does not disclose this sensitive authentication mechanism. In agent environments, hidden credential use is risky because it can surprise users and widen the blast radius if the runtime or logs are compromised.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill performs remote write operations that create notes in the user's account, but there is no built-in confirmation or user-warning mechanism in the implementation. In an autonomous agent context, silent writes are more dangerous because they can alter user data unexpectedly or be abused for spam, persistence, or misleading records.

Content

No source excerpt is available for this finding.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · youdao_api.py (reported line 427)May include surrounding context.

python
parent_dir = get_root_dir()
    headers = build_headers()
    headers["Content-Type"] = "application/x-www-form-urlencoded"
    time_mod = __import__("time")
    now = int(time_mod.time())
    file_id = "WEB" + os.urandom(16).hex().upper()
    note_name = title.strip()

Tainted flow: 'payload' from requests.post (line 459, network input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · youdao_api.py (reported line 516)May include surrounding context.

python
]
    last_response = last_push_resp
    for payload in payload_candidates:
        response = requests.post(url, headers=headers, params=params, data=payload)
        last_response = response
        if response.status_code == 200 and note_exists_in_parent(note_name):
            result = response.json()

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill implements read_all_in_dir, which performs bulk extraction of every note in a directory, exceeding the metadata description of read/search/create at the single-note level. In an agent setting, this materially increases data-exposure risk because a broad request can retrieve far more user content than necessary for the task.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The README content and usage examples are entirely in Chinese and instruct the user to interact with the agent in Chinese-style prompts, but do not indicate that language is optional or limited for a justified regional reason. Under the language/locale policy, skills should not implicitly force a specific language without opt-in or documentation.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency 'requests' is specified without a version pin, which makes builds non-reproducible and can cause the skill to install a vulnerable or incompatible release depending on when and where it is deployed. In a note-taking integration that likely handles authentication and user data, pulling an unbounded version of an HTTP client library increases supply-chain and patch-management risk.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
requests
brotli

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The manifest includes 'requests' without a pinned version, and the package has multiple known advisories across releases. Because the version is unspecified, there is no way to verify from this file alone whether deployment will use a patched version, leaving open the possibility of shipping a vulnerable HTTP stack in a skill that may transmit credentials or access note content.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency 'brotli' is also unpinned, so the installed package version is not deterministic and may vary across environments. That creates avoidable supply-chain risk and makes it difficult to verify whether known security fixes are present.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
requests
brotli

Static analysis

No suspicious patterns detected.