Back to skill

Security audit

Yuque Doc Push

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches Yuque document management, but it needs Review because its token and file-sync handling can leak credentials or write pulled files outside the intended folder.

Review before installing. Use only trusted Yuque URLs, avoid running setup where command lines or agent transcripts are logged, protect the .env file, and do not pull or sync from repositories whose document slugs you do not trust until endpoint validation and path-containment checks are fixed.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/yuque_cli.py:214
Finding
Yuque API Token Can Be Transmitted to an Attacker-Controlled or Plaintext Endpoint## Vulnerability Details **File Location**: `scripts/yuque_cli.py:214-221`, `scripts/yuque_cli.py:232-236`, and `scripts/yuque_cli.py:77-96` **Vulnerability Type**: Insufficient endpoint validation leading to credential disclosure **Risk Level**: High ### Vulnerable Code ```python parsed = urlparse(url) if not parsed.scheme: parsed = urlparse("https://" + url) if not re.search(r'yuque\.com$', parsed.hostname or ""): return None, "URL must be a yuque.com domain (e.g. https://xxx.yuque.com/group/book)." base_url = f"{parsed.scheme}://{parsed.hostname}" ``` The resulting endpoint is then used to transmit the token: ```python def verify_connection(token, base_url, group_login, book_slug): """Test the token and repo by calling the list docs API. Returns (success, message).""" url = f"{base_url}/api/v2/repos/{group_login}/{book_slug}/docs?limit=1" try: resp = requests.get( url, headers={"X-Auth-Token": token, "User-Agent": "yuque-cli/1.0"}, timeout=15, ) ``` Normal API requests also attach the token to the configured base URL: ```python self.session.headers.update({ "X-Auth-Token": token, "Content-Type": "application/json", "User-Agent": "yuque-cli/1.0", }) def _request(self, method, path, **kwargs): url = self.base_url + path resp = self.session.request(method, url, **kwargs) ``` ### Technical Analysis The hostname check only tests whether the hostname text ends with `yuque.com`. It does not require a DNS label boundary. A domain such as `attackeryuque.com` therefore passes validation even though it is not controlled by Yuque. The parser also preserves the user-supplied scheme without requiring HTTPS. A URL beginning with `http://` can consequently cause the API token to be transmitted in plaintext. In addition, `requests` follows redirects by default. The implementation does not disabl ...[truncated 1619 chars]
Remediation
## Remediation Suggestions 1. Require HTTPS explicitly: ```python if parsed.scheme.lower() != "https": return None, "Yuque URLs must use HTTPS." ``` 2. Validate DNS label boundaries: ```python hostname = (parsed.hostname or "").lower().rstrip(".") if hostname != "yuque.com" and not hostname.endswith(".yuque.com"): return None, "URL must use yuque.com or a yuque.com subdomain." ``` 3. Reject embedded credentials, unexpected ports, fragments, and malformed hostnames. 4. Apply the same validation to `YUQUE_BASE_URL` loaded from environment variables. Validation only during setup is insufficient because `.env` can be edited independently. 5. Disable automatic redirects for token-bearing requests or manually follow redirects only after validating every destination: ```python resp = requests.get(url, headers=headers, timeout=15, allow_redirects=False) ``` 6. Ensure that the token is never forwarded when the scheme, hostname, or port changes. 7. Add regression tests covering `attackeryuque.com`, `yuque.com.attacker.example`, plaintext HTTP, embedded credentials, trailing-dot hostnames, unexpected ports, and cross-origin redirects.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/yuque_cli.py:747
Finding
Remote Document Slugs Permit Filesystem Path Traversal During Pull Operations## Vulnerability Details **File Location**: `scripts/yuque_cli.py:747-752`, `scripts/yuque_cli.py:990-1001`, and `scripts/yuque_cli.py:1180-1215` **Vulnerability Type**: Path traversal and arbitrary file write **Risk Level**: High ### Vulnerable Code ```python def file_path_for_slug(slug, root, layout, hint_subdir=None): """Where should a pulled doc be written locally?""" root = Path(root) if layout == "nested" and hint_subdir: return root / hint_subdir / f"{slug}.md" return root / f"{slug}.md" ``` Remote slugs are used as paths without validation: ```python if args.all: remote_docs = client.list_all_docs(optional_properties="latest_version_id") targets = [d.get("slug") for d in remote_docs if d.get("slug")] elif args.slug: targets = [args.slug] for slug in targets: detail = client.get_doc(slug).get("data", {}) or {} target = file_path_for_slug(slug, root, layout) if target.exists() and not args.overwrite: skipped.append({"slug": slug, "reason": "local file exists (pass --overwrite to replace)"}) continue target.parent.mkdir(parents=True, exist_ok=True) target.write_text(normalize_body(body), encoding="utf-8") ``` The missing-file restoration path uses the same unsafe function: ```python target = file_path_for_slug(slug, root, layout) target.parent.mkdir(parents=True, exist_ok=True) body = detail.get("body", "") or "" target.write_text(normalize_body(body), encoding="utf-8") ``` ### Technical Analysis `file_path_for_slug()` directly concatenates a remotely supplied document slug with the synchronization root. It does not reject: - `..` path components. - Forward or backward path separators. - Absolute paths. - Platform-specific drive or UNC path syntax. - Resolved targets located outside the synchronization root. `Path` normalizes traversal components when the path is used. A slug such as `../../ ...[truncated 1700 chars]
Remediation
## Remediation Suggestions 1. Enforce a conservative slug syntax before converting a slug to a path, for example: ```python if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_-]*", slug): raise ValueError(f"Unsafe document slug: {slug!r}") ``` 2. Explicitly reject `/`, `\`, `..`, absolute paths, drive prefixes, NUL characters, and control characters. 3. Resolve both the root and candidate target, then verify containment: ```python root = Path(root).resolve() target = (root / f"{slug}.md").resolve() try: target.relative_to(root) except ValueError: raise ValueError("Pull target escapes the synchronization root") ``` 4. Perform containment validation before calling `mkdir()` or `write_text()`. 5. Apply the same validation to `hint_subdir`, stored `local_path` values, command-line slugs, remote slugs, and slugs loaded from the synchronization state. 6. Consider mapping unsafe remote slugs to deterministic encoded local filenames rather than using the slug directly. 7. Add tests for traversal using forward slashes, Windows separators, absolute paths, drive paths, nested traversal, symlinked directories, and overwrite behavior.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/yuque_cli.py:1330
Finding
Yuque API Token Is Passed Through Process Command-Line Arguments## Vulnerability Details **File Location**: `scripts/yuque_cli.py:1330-1333` and `SKILL.md:42-57` **Vulnerability Type**: Sensitive information exposure through process arguments **Risk Level**: Medium ### Vulnerable Code The CLI requires the token as a command-line argument: ```python p_setup = subparsers.add_parser( "setup", help="Initialize .env from a Yuque knowledge base URL", ) p_setup.add_argument( "--url", required=True, help="Yuque knowledge base URL (e.g. https://xxx.yuque.com/group/book)", ) p_setup.add_argument("--token", required=True, help="Yuque API token") p_setup.add_argument( "--env-path", default=None, help="Path to write .env file (default: ./.env)", ) ``` The documented setup workflow instructs the agent to invoke it this way: ```bash python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>" ``` ### Technical Analysis Avoiding token output inside the Python program does not protect secrets placed in `argv`. Depending on the operating environment, command-line arguments may be exposed through: - Process inspection utilities and operating-system process metadata. - Shell history. - Agent tool-call transcripts and execution logs. - CI/CD logs and audit telemetry. - Monitoring or endpoint security products. - Other local users with sufficient process-inspection permissions. The Skill explicitly directs the agent to place the user-provided credential in a CLI argument. This is unnecessary because secure alternatives such as hidden prompting or standard input are available. ### Attack Path 1. The user provides a valid Yuque API token as required by the setup workflow. 2. The agent executes the documented command with `--token`. 3. The complete command line is captured in process metadata, shell history, an agent execution transcript, or infrastructure logs. 4. A local user, administrator, log read ...[truncated 439 chars]
Remediation
## Remediation Suggestions 1. Remove the required `--token` argument from the recommended setup flow. 2. Read the token using a hidden prompt: ```python from getpass import getpass token = getpass("Yuque API token: ") ``` 3. For non-interactive automation, accept the token through standard input or a dedicated inherited file descriptor. 4. If environment-based setup is supported, clearly warn that environment variables may also be exposed in some execution environments and avoid logging the environment. 5. Mark any deprecated `--token` option as unsafe and reject its use by default, or support it only behind an explicit compatibility flag. 6. Ensure agent tool calls, error handlers, debug logs, and telemetry redact token values. 7. Use restrictive permissions when writing `.env`, such as owner read/write only where supported.

T08 · Insecure Dependencies

Note
Location
README.md:51
Finding
Runtime Dependencies Are Installed Without Version or Integrity Pinning## Vulnerability Details **File Location**: `README.md:51` and `README.md:185` **Vulnerability Type**: Unpinned third-party dependencies **Risk Level**: Low ### Vulnerable Code ```bash pip install requests python-dotenv ``` The Skill documentation also lists `requests` and `python-dotenv` as prerequisites without specifying versions, hashes, or a lock file. ### Technical Analysis Installing packages by name alone resolves whatever versions are currently selected by the configured package index. This makes installation non-reproducible and does not provide integrity verification beyond the package-management defaults. No evidence of typosquatting, dependency confusion, or an intentionally malicious package was found. The packages named are established dependencies. The risk arises from mutable dependency resolution and the absence of constraints or hashes. ### Attack Path 1. A user follows the installation instructions at a later date or in a differently configured environment. 2. `pip` resolves versions that were not reviewed with the Skill. 3. A compromised, malicious, or incompatible release is downloaded from the active package index. 4. Package installation code executes with the privileges of the user performing the installation. 5. The compromised dependency can access the local environment and influence token-bearing network requests at runtime. ### Impact Assessment A compromised dependency executes in the same Python process as the Skill and could potentially: - Read the Yuque token and local `.env` files. - Read Markdown content being synchronized. - Alter API requests or responses. - Modify local files accessible to the process. - Execute arbitrary code with the installing or running user's privileges. The practical likelihood is lower than the direct implementation flaws because no currently malicious dependency was identified.
Remediation
## Remediation Suggestions 1. Add a reviewed dependency lock file with exact versions. 2. Use hash verification, for example through a requirements file containing pinned versions and `--hash` entries. 3. Install with: ```bash pip install --require-hashes -r requirements.txt ``` 4. Document the expected trusted package index and avoid untrusted extra indexes. 5. Use automated dependency scanning and controlled update reviews. 6. Test supported Python and dependency versions before updating the lock file.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (49)

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

Critical
Category
Data Flow
Content
"""Test the token and repo by calling the list docs API. Returns (success, message)."""
    url = f"{base_url}/api/v2/repos/{group_login}/{book_slug}/docs?limit=1"
    try:
        resp = requests.get(url, headers={"X-Auth-Token": token, "User-Agent": "yuque-cli/1.0"}, timeout=15)
    except requests.RequestException as e:
        return False, f"Connection failed: {e}"
Confidence
95% confidence
Finding
The setup flow allows a user-controlled `YUQUE_BASE_URL`/parsed base URL to be used for an authenticated HTTP request, and it sends the `X-Auth-Token` header to that destination. Although `parse_yuque_url` restricts `setup --url` to `*.yuque.com`, `load_config()` accepts `YUQUE_BASE_URL` from `.env` without host validation, so a malicious or tampered local config can redirect requests and exfiltrate the API token to an attacker-controlled endpoint.

Credential Access

High
Category
Privilege Escalation
Content
*.pot

# Environments
.env
.envrc
.venv
env/
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/yuque_cli.py setup --url "<user_url>" --token "<user_token>"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Credential Access

High
Category
Privilege Escalation
Content
--dry-run   Preview the action without executing it (create/update/delete)

Environment:
    Reads YUQUE_TOKEN, YUQUE_REPO, and optional YUQUE_BASE_URL from a .env
    file found by searching upward from the current working directory.

Sync state:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
--dry-run   Preview the action without executing it (create/update/delete)

Environment:
    Reads YUQUE_TOKEN, YUQUE_REPO, and optional YUQUE_BASE_URL from a .env
    file found by searching upward from the current working directory.

Sync state:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
--dry-run   Preview the action without executing it (create/update/delete)

Environment:
    Reads YUQUE_TOKEN, YUQUE_REPO, and optional YUQUE_BASE_URL from a .env
    file found by searching upward from the current working directory.

Sync state:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
--dry-run   Preview the action without executing it (create/update/delete)

Environment:
    Reads YUQUE_TOKEN, YUQUE_REPO, and optional YUQUE_BASE_URL from a .env
    file found by searching upward from the current working directory.

Sync state:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
--dry-run   Preview the action without executing it (create/update/delete)

Environment:
    Reads YUQUE_TOKEN, YUQUE_REPO, and optional YUQUE_BASE_URL from a .env
    file found by searching upward from the current working directory.

Sync state:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
--dry-run   Preview the action without executing it (create/update/delete)

Environment:
    Reads YUQUE_TOKEN, YUQUE_REPO, and optional YUQUE_BASE_URL from a .env
    file found by searching upward from the current working directory.

Sync state:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
--dry-run   Preview the action without executing it (create/update/delete)

Environment:
    Reads YUQUE_TOKEN, YUQUE_REPO, and optional YUQUE_BASE_URL from a .env
    file found by searching upward from the current working directory.

Sync state:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Static analysis

Detected: suspicious.secret_argv_exposure

Instructions pass high-value credentials through process argv.

Critical
Code
suspicious.secret_argv_exposure
Location
SKILL.md:44