Back to skill

Security audit

为知笔记skills

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its WizNote note-sync purpose, but it handles passwords, tokens, and note content without enough transport and endpoint safeguards.

Review before installing. Use only with a trusted WizNote server over HTTPS, avoid plaintext HTTP, and do not run it against sensitive notes until kbServer validation and same-origin or allowlist checks are added. Treat create/save operations as real remote writes and require explicit confirmation before using them.

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

Error
Location
wiznote_cli.py:43
Finding

WizNote credentials, session tokens, and note content can be transmitted over plaintext HTTP

Content
View full analysis
Credentials: resolved_base_url = base_url if base_url is not None else os.getenv("WIZNOTE_BASE_URL") resolved_user = user if user is not None else os.getenv("WIZNOTE_USER") resolved_password = password if password is not None else os.getenv("WIZNOTE_PASSWORD") missing = [] if not resolved_base_url: missing.append("WIZNOTE_BASE_URL") if not resolved_user: missing.append("WIZNOTE_USER") if not resolved_password: missing.append("WIZNOTE_PASSWORD") if missing: raise ValueError(f"Missing WizNote credentials: {', '.join(missing)}") assert resolved_base_url is not None assert resolved_user is not None assert resolved_password is not None return Credentials( base_url=resolved_base_url.rstrip("/"), user=resolved_user, password=resolved_password, ) ``` ```python def login(credentials: Credentials) -> LoginResult: payload = login_request_payload(credentials) request = Request( url=( f"{credentials.base_url.rstrip('/')}" "/as/user/login?clientType=web&clientVersion=4.0&lang=zh-cn" ), data=json.dumps(payload).encode("utf-8"), headers={"Content-type": "application/json"}, method="POST", ) try: with urlopen(request, timeout=DEFAULT_TIMEOUT_SECONDS) as response: response_payload = json.loads(response.read().decode("utf-8")) ``` Token-bearing operations use the same unchecked URL pattern: ```python request = Request( f"{base_url.rstrip('/')}{note ...[truncated 2500 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
wiznote_helper.py:16
Finding

Untrusted login response controls the destination of authenticated WizNote requests

Content
View full analysis
LoginResult: code = payload.get("returnCode") if code != 200: raise ValueError(f"WizNote login failed with returnCode={code}: {payload.get('returnMessage', '')}") result = payload.get("result") if not isinstance(result, dict): raise ValueError("WizNote login payload missing result object") token = result.get("token") kb_server = result.get("kbServer") kb_guid = result.get("kbGuid") if not isinstance(token, str) or not token: raise ValueError("WizNote login payload missing token") if not isinstance(kb_server, str) or not kb_server: raise ValueError("WizNote login payload missing kbServer") if not isinstance(kb_guid, str) or not kb_guid: raise ValueError("WizNote login payload missing kbGuid") return LoginResult( token=token, kb_server=kb_server.rstrip("/"), kb_guid=kb_guid, ) ``` The documented operating pattern forwards the token to the returned endpoint: ```python payload = cli.fetch_note_list( base_url=login.kb_server, kb_guid=login.kb_guid, token=login.token, category=category, ) ``` Authenticated request construction then uses that endpoint directly: ```python return RequestSpec( url=f"{base_url.rstrip('/')}{note_list_path(kb_guid, category, start=start, count=count)}", headers={"X-Wiz-Token": token}, ) ``` Write operations additionally send note content to the selected server: ```python return RequestSpec( url=f"{base_url.rstrip('/')}/ks/note/create/{kb_guid}", headers={"X-Wiz-Token": token, "Conten ...[truncated 2813 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
SKILL.md:151
Finding

Documentation installs mutable, unpinned third-party dependencies

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This code chunk does not implement the declared note-management functionality. It only adjusts Python's import path for tests by adding the repository root to sys.path. That behavior is unrelated to interacting with a WizNote server, maintaining documents, mirroring notes locally, or organizing note categories. Because the actual behavior shown is materially different from the declared purpose, this is a mismatch.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 15)May include surrounding context.

md
- **Private by default** — connect to your own WizNote deployment instead of moving docs into a public SaaS workspace
- **Claude-friendly workflow** — pair the same doc system with Claude Code and adjacent desktop, web, or IDE-centered repo workflows
- **Cross-end continuity** — write or sync on one surface, continue from another, and keep the same documentation source of truth
- **Built for personal or small-team vibe coding** — keep docs, plans, and implementation notes tightly coupled to the codebase
- **Repo mirrors included** — keep WizNote as canonical while preserving code-adjacent Markdown copies in `docs/wiznote-mirror/...`

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
85% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt · README.md (reported line 54)May include surrounding context.

将当前目录复制到 Claude 的 skills 目录:

bash
mkdir -p ~/.claude/skills
cp -R ./wiznote ~/.claude/skills/wiznote

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
85% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt · README.zh-CN.md (reported line 54)May include surrounding context.

将当前目录复制到 Claude 的 skills 目录:

bash
mkdir -p ~/.claude/skills
cp -R ./wiznote ~/.claude/skills/wiznote

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.zh-CN.md (reported line 54)May include surrounding context.

将当前目录复制到 Claude 的 skills 目录:

bash
mkdir -p ~/.claude/skills
cp -R ./wiznote ~/.claude/skills/wiznote

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill instructs use of environment variables for credentials and network access to a WizNote server, but it does not declare an explicit tool scope or permission boundary. In an agent setting, undeclared access to env and network increases the chance the skill is invoked with broader capabilities than the user expects, enabling credential use and remote actions without clear consent boundaries.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill explicitly supports creating and updating remote notes and writing mirrored copies to a local repository, but it does not prominently warn that these are state-changing operations requiring user confirmation. In agent workflows, omission of such warnings can lead to unintended remote edits or local file writes when a user expected a read-only documentation task.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code file contains natural-language locale configuration asserting lang: "zh-cn", which enforces a specific language/locale choice in the tested behavior. The policy for SQP-3 applies to all file types and flags forced language or locale choices when there is no user choice or documented region-specific justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The test asserts that the login request must include lang=zh-cn, which encodes a fixed locale requirement into expected behavior. Because no opt-in or justification is present, this is a natural-language policy concern under SQP-3 rather than a security scanner issue.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The login payload explicitly sets "lang" to "zh-cn", and the login URL repeats the same locale setting. This forces a specific language setting without any visible opt-in, configurability, or documented region-specific justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code logs in by sending the user ID and password to a remote service, and other functions in the file send and retrieve note content over HTTP. The file contains no confirmation prompt, print/log disclosure, or inline warning to inform users that credentials and note data will be transmitted off-host.

Content

No source excerpt is available for this finding.