Back to skill

Security audit

Mowenskill Publish

Security checks for vulnerabilities and agentic risk

Overview

The skill coherently implements a Mowen note publisher, with expected but important risks around public posting, full-content edits, image uploads, and API key handling.

Install this only if you want an agent to create, edit, and change visibility for your Mowen notes. Prefer MOWEN_API_KEY or a secret manager over --api-key, review content before using autoPublish or public privacy, remember edits replace the entire note, and only include local image paths or remote image URLs you are willing to upload.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/publish_note.py:124
Finding

Unvalidated Dynamic Upload Destination Can Expose Local Files

Content
View full analysis

Vulnerability Details

File Location: scripts/publish_note.py:168-177 and scripts/publish_note.py:124-132
Vulnerability Type: Unvalidated outbound upload destination
Risk Level: Medium

Vulnerable Code

python
endpoint = form.pop("endpoint", "")
if not endpoint:
    _die("Failed to obtain upload authorization: endpoint was not returned")

file_id = form.get("x:file_id", "")

time.sleep(RATE_LIMIT_DELAY)

_info(f"[Upload] Sending file: {filename} -> {endpoint}")
_multipart_upload(endpoint, form, file_path)

The receiving function uses the endpoint without validating its scheme, hostname, port, or redirect behavior:

python
upload_url = endpoint.rstrip("/") + "/"
req = Request(
    upload_url,
    data=body,
    headers={"Content-Type": f"multipart/form-data; boundary={boundary}"},
    method="POST",
)
try:
    with urlopen(req, timeout=120) as resp:
        return resp.read()

Technical Analysis

The local-image workflow obtains a signed upload form from the fixed Mowen API and then trusts the returned endpoint as the destination for the selected local file. This dynamic endpoint is part of the documented object-storage workflow and is therefore functionally necessary. However, the implementation does not enforce HTTPS or verify that the destination belongs to an approved Mowen or Alibaba OSS domain.

Consequently, a compromised, malicious, or incorrectly configured API response can direct the script to transmit the complete local image and temporary signed upload fields to an arbitrary server. Python's default URL handling can also follow redirects, and redirected destinations are not revalidated.

The API Bearer key itself is not included in the multipart upload. The exposed data consists of the user-selected local file and temporary upload authorization fields such as the policy, callback, credential, signature, metadata, and file identifiers.

Attack Pa

...[truncated 1325 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse the endpoint with urllib.parse.urlparse.
  2. Require the https scheme and reject URLs containing user information, fragments, or unexpected ports.
  3. Enforce an explicit allowlist of object-storage hostnames or hostname suffixes documented by Mowen. Perform boundary-safe matching, such as exact equality or hostname.endswith("." + allowed_suffix), rather than substring matching.
  4. Disable automatic redirects for multipart uploads, or validate the scheme and hostname of every redirect target before transmitting the request body.
  5. Reject IP literals, localhost, link-local addresses, and private network destinations unless the API explicitly documents and requires them.
  6. Avoid logging the full upload URL if it may ever contain query credentials.
  7. Add tests covering HTTP endpoints, unrelated domains, deceptive suffixes, embedded credentials, unexpected ports, IP literals, and redirects.
  8. Consider constraining accepted local files to caller-approved directories when the Skill runs in an agent environment.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/publish_note.py:505
Finding

API Key Accepted Through Process Command-Line Arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/publish_note.py:505-508
Vulnerability Type: Sensitive credential exposure through command-line arguments
Risk Level: Low

Vulnerable Code

python
parser.add_argument(
    "--api-key",
    default=os.environ.get("MOWEN_API_KEY", ""),
    help="Mowen API Key (reads MOWEN_API_KEY by default)",
)

The documentation also explicitly presents command-line key submission as a supported option in SKILL.md:15-16.

Technical Analysis

Accepting a secret through --api-key places the credential in the process argument vector. Depending on operating-system policy and execution environment, command-line arguments may be visible to other local users, process-monitoring software, audit systems, CI logs, agent execution logs, or diagnostic tooling. Interactive shell invocations may additionally persist the complete command in shell history.

The environment-variable option is safer than a command-line argument but is still inherited by child processes unless the environment is sanitized. The command-line option creates an avoidable exposure channel and is not required for the declared publishing functionality.

Attack Path

  1. A user or automation system invokes the script as publish_note.py --api-key SECRET ....
  2. The complete command is retained in shell history, execution logs, or process telemetry, or is observed through process inspection while the script is running.
  3. A local user or log reader retrieves the API key.
  4. The attacker authenticates to the Mowen API with the stolen key.
  5. The attacker exercises whatever create, edit, upload, or settings permissions and quotas are assigned to that key.

Impact Assessment

Exposure of the API key can grant access to the victim's Mowen Open API privileges. Based on this Skill's supported operations, those privileges may include creating notes, replacing the content of API-created notes, uploa ...[truncated 289 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove or deprecate --api-key and use a protected credential source.
  2. Prefer MOWEN_API_KEY for unattended operation, while ensuring child-process environments and logs are sanitized.
  3. For interactive use, accept the key through getpass.getpass() so it is not echoed or added to command history.
  4. Where available, integrate with an operating-system keychain or dedicated secret manager.
  5. If backward compatibility requires retaining --api-key, display a prominent warning and ensure examples never place real secrets on command lines.
  6. Update SKILL.md to recommend protected environment injection or secret-manager usage exclusively.
  7. Rotate any API key known to have appeared in shell history, CI output, process telemetry, or execution logs.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (9)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose is centered on Mowen note publishing and configuration functionality, but the supplied code chunk contains only generic test-execution logic. It does not show any API calls, note creation/editing behavior, rich text or image handling, or Mowen-specific integration. Its primary purpose is materially different: running a Python test suite. This is a clear description-to-behavior mismatch.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill instructs the agent to read environment variables, process local files, and make network requests, but it does not declare any corresponding tool scope or permission boundaries. This creates a least-privilege and transparency failure: a caller or runtime may permit broader access than users realize, increasing the chance of unintended data exposure such as API keys or local image contents being sent to the external Mowen service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

Editing replaces the entire note content, but if that destructive behavior is not surfaced prominently enough before use, an agent or user may unintentionally overwrite existing content. In a content-management skill, this can cause irreversible data loss or integrity issues, especially when automating edits from partial user instructions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill automatically uploads images from local paths or remote URLs to a third-party API, but it does not provide a clear privacy and data-transfer warning near that behavior. This is dangerous because local files may contain sensitive personal or corporate data, and remote URL ingestion can disclose access patterns or move data across trust boundaries without informed consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation exposes an autoPublish option that can cause content to be published immediately, but it does not prominently warn that enabling it changes a draft workflow into a public-posting action. In a skill whose purpose is to publish notes on a social platform, this increases the risk that an agent or integrator posts sensitive, unreviewed, or unintended content without explicit user confirmation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The privacy-setting API documents switching a note to public or applying sharing rules, but it does not clearly warn that this can broaden visibility and expose previously private content. Because this skill is specifically designed to create and manage public-facing notes, insufficient warning around visibility changes raises the chance of accidental disclosure by users or automated agents.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This code file contains user-facing natural-language instructions, help text, and status messages exclusively in Chinese, beginning in the module docstring and continuing throughout the CLI. Under the policy, forcing a specific language without offering the user a language/locale choice is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The module docstring and inline comments are written in Chinese, which imposes a specific language for user-facing developer guidance without indicating any language choice or opt-in. The policy explicitly flags language or locale constraints when they are forced rather than optional or justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code file contains natural-language documentation entirely in Chinese, including the module docstring and comments, with no indication that language selection is optional or region-specific. Under the policy rule, forcing a specific language without user opt-in is a locale/language policy concern.

Content

No source excerpt is available for this finding.