Back to skill

Security audit

Memos

Security checks for vulnerabilities and agentic risk

Overview

The skill is a straightforward Memos API helper, with expected token use and memo mutation features that users should handle carefully.

Install only if you trust the Memos instance configured in MEMOS_URL, preferably over HTTPS, and use a narrowly scoped MEMOS_TOKEN. Review visibility before creating memos because PUBLIC is the default, and invoke delete or force-delete only when you are certain the remote memo should be removed.

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

Warning
Location
memos.py:9
Finding

Bearer Token May Be Transmitted to an Untrusted or Plaintext Endpoint

Content
View full analysis

Vulnerability Details

File Location: memos.py, lines 9–20 and 43–52
Vulnerability Type: Unrestricted credential transmission
Risk Level: Medium

Vulnerable Code

python
BASE_URL = os.getenv("MEMOS_URL")
TOKEN = os.getenv("MEMOS_TOKEN")

if not BASE_URL:
    raise RuntimeError("MEMOS_URL environment variable is not set.")
if not TOKEN:
    raise RuntimeError("MEMOS_TOKEN environment variable is not set.")

HEADERS = {
    "Authorization": f"Bearer {TOKEN}",
    "Content-Type": "application/json",
}
python
url = f"{BASE_URL}{endpoint}"

try:
    resp = requests.request(
        method,
        url,
        headers=HEADERS,
        json=data,
        params=params,
        timeout=30  # 30 second timeout
    )

Technical Analysis

The user-controlled MEMOS_URL environment variable is used as the request destination without validating its scheme, host, embedded credentials, or trust boundary. Every API request includes the MEMOS_TOKEN in an Authorization: Bearer header.

If MEMOS_URL uses plain HTTP, the bearer token and memo data can traverse the network without transport encryption. If the variable is accidentally or maliciously set to an attacker-controlled server, invoking any supported command sends the token directly to that server.

This behavior is not concealed data exfiltration because the destination is explicitly configured by the environment. Nevertheless, failing to enforce secure transport and destination constraints creates an exploitable credential-handling weakness.

Redirect behavior should also be treated carefully. Even where the initial URL is trusted, authentication must not be forwarded to an unvalidated redirect destination.

Attack Path

  1. An attacker with influence over process configuration, deployment variables, a wrapper script, or setup instructions changes MEMOS_URL to an attacker-controlled URL or a plaintext ` ...[truncated 1060 chars]
Remediation
View remediation

Remediation Suggestions

  1. Parse MEMOS_URL with urllib.parse.urlparse rather than using unchecked string concatenation.
  2. Require the https scheme for non-loopback destinations.
  3. Reject malformed URLs, embedded username/password components, fragments, and unexpected schemes.
  4. If local plaintext deployments are required, permit HTTP only through an explicit opt-in and only for verified loopback hosts such as 127.0.0.1, ::1, or localhost.
  5. Normalize the base URL and construct API URLs with a safe URL-joining strategy.
  6. Disable redirects for authenticated requests unless required. If redirects are supported, validate every redirect target and do not forward the authorization header across origin boundaries.
  7. Use a narrowly scoped Memos token and provide rotation guidance in case configuration is compromised.
  8. Add tests confirming rejection of HTTP remote URLs, non-HTTP schemes, embedded credentials, malformed hosts, and cross-origin redirects.

Example validation approach:

python
from urllib.parse import urlparse

parsed = urlparse(BASE_URL)
if parsed.scheme != "https":
    raise RuntimeError("MEMOS_URL must use HTTPS.")
if not parsed.hostname or parsed.username or parsed.password:
    raise RuntimeError("MEMOS_URL is invalid.")
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (5)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
- The skill is implemented in Python and uses the `requests` library.
- It requires two environment variables:
  - `MEMOS_URL` – **REQUIRED**. Base URL of your Memos instance (e.g., `https://demo.usememos.com`).
  - `MEMOS_TOKEN` – **REQUIRED**. Personal access token for authentication.
- If either `MEMOS_URL` or `MEMOS_TOKEN` is not set, the skill will abort with a clear error.

## Commands

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

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

md
## Commands

| Command                         | Description                                                                                                                                | Usage example                                      | cd  |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------- | --- |
| `create <content> [visibility]` | Create a new memo. `visibility` defaults to `PUBLIC` (options: PRIVATE, PROTECTED, PUBLIC). The tag `#openclaw` is appended automatically. | `openclaw skill-run create "Hello world" "PUBLIC"` |
| `get <id>`                      | Retrieve a memo by its ID. ID can be in format `memos/123` or just `123`.                                                                  | `openclaw skill-run get 123`                       |

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill documents a delete operation, including a force option, but does not clearly warn that deletion may be irreversible or cause data loss. In an agent-executed context, destructive actions without prominent confirmation guidance increase the risk of accidental deletion, especially if the command is invoked from natural-language instructions or automation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The delete function performs an irreversible DELETE request against the remote Memos API, including an optional force mode, but the code provides no confirmation prompt and no user-facing warning about the destructive action. Although the docstring names the operation, it does not clearly disclose risk or caution the user before deletion is executed.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The docstring states the function will create a memo with the #openclaw tag, implying a specific intent for tagging behavior. In reality, the implementation simply appends a newline plus #openclaw to arbitrary user content, which is weaker and not a strict semantic guarantee of a uniquely tagged memo in all cases.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.