Back to skill

Security audit

OpenClaw Flomo Skill

Security checks for vulnerabilities and agentic risk

Overview

This flomo skill mostly does what it says, but it handles authenticated account access and memo writes in ways that need careful review before installation.

Install only if you are comfortable giving this skill access to your logged-in flomo account and private memos. Avoid setting FLOMO_API_BASE, review any command before running write or verify, and assume webhook writes and verification can create real memos in your account.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/flomo_tool.py:173
Finding

Bearer Token Can Be Transmitted to an Arbitrary API Host

Content
View full analysis
dict: base = os.getenv("FLOMO_API_BASE", "https://flomoapp.com/api/v1").rstrip("/") params = { "api_key": "flomo_web", "app_version": _get_app_version(), "platform": os.getenv("FLOMO_PLATFORM", "mac"), "timestamp": int(time.time()), "webp": "1", } if extra_params: params.update(extra_params) params["sign"] = _sign_params(params.copy()) url = f"{base}{path}?{urllib.parse.urlencode(params, doseq=True)}" return _curl_json( "GET", url, headers={ "Accept": "application/json, text/plain, */*", "Authorization": f"Bearer {_get_access_token()}", "platform": "Mac", "device-model": "Mac", }, ) ``` ### Technical Analysis The `FLOMO_API_BASE` environment variable can replace the default API origin with an unrestricted URL. Regardless of the selected origin, `_api_get()` attaches the bearer token obtained from `FLOMO_ACCESS_TOKEN` or the local flomo desktop configuration. Consequently, configuration or launch-environment manipulation can redirect an authenticated request to an attacker-controlled HTTP or HTTPS server. Customizing the credential-bearing API host is not required for the Skill's ordinary flomo read/write functionality and exceeds the minimum privilege needed for the declared behavior. The English and Chinese README files explicitly document the unrestricted `FLOMO_API_BASE` override, making this behavior part of the supported configuration rather than an unreachable implementation detail. ### Attack Path 1. An attacker or compromised orchestration component influences the Skill's launch environment. 2. `FLOMO_API_BASE` is set to an ...[truncated 893 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/flomo_tool.py:52
Finding

Bearer Token, Webhook Secret, and Memo Content Are Exposed Through Process Arguments

Content
View full analysis
dict: cmd = ["curl", "-sS", "-X", method.upper(), url] if headers: for k, v in headers.items(): cmd.extend(["-H", f"{k}: {v}"]) if data_json is not None: cmd.extend(["-H", "Content-Type: application/json", "-d", json.dumps(data_json, ensure_ascii=False)]) raw = _run_curl(cmd) return json.loads(raw) ``` Authenticated requests supply the bearer token through this function: ```python return _curl_json( "GET", url, headers={ "Accept": "application/json, text/plain, */*", "Authorization": f"Bearer {_get_access_token()}", "platform": "Mac", "device-model": "Mac", }, ) ``` Webhook writes supply both the secret webhook URL and private memo content: ```python resp = _curl_json("POST", webhook_url, data_json={"content": content}) ``` ### Technical Analysis The function builds a `curl` argument vector containing: - The bearer token in a `-H "Authorization: Bearer ..."` argument. - The full incoming webhook URL in the URL argument. - User memo content in the `-d` argument. Although the returned JSON masks the webhook URL, that masking occurs only after `curl` has already been launched with the complete secret in its process arguments. Process inspection, diagnostic tools, crash collection, command instrumentation, or local monitoring software may therefore capture these values while the subprocess exists. Using a subprocess is not inherently unsafe, and `subprocess.run()` with a list avoids shell injection. The vulnerability is specifically the placement of ...[truncated 1299 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/flomo_tool.py:402
Finding

Documented Dry Health Check Performs a Persistent Remote Write

Content
View full analysis
0 else 3600 check = read_remote(limit=40, query=verify_q, tz=args.tz, since_seconds=verify_window) result["checks"].append({"name": "write_webhook", "ok": True, "status": out.get("status"), "readback_hits": check.get("count")}) ``` ### Technical Analysis The authoritative Skill instructions describe the health check as a URL-scheme “dry flow,” but the documented command uses `--try-webhook`. The implementation resolves the user's incoming webhook and calls `write_webhook()`, which creates a real memo in the user's remote flomo account. The generated verification memo is not deleted after readback. Therefore, the operation is neither a dry run nor a URL-scheme-only check. Although `README.md` more accurately identifies verification as an end-to-end webhook write, the inconsistency in `SKILL.md` may cause an Agent or user to perform a persistent state-changing operation without informed consent. ### Attack Path 1. An Agent loads `SKILL.md` and follows the documented one-shot health-check command. 2. The Ag ...[truncated 888 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (24)

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 · README.md (reported line 103)May include surrounding context.

md
你可以通过环境变量覆盖默认行为:

- `FLOMO_CONFIG_PATH`:覆盖本机 flomo 配置文件路径
- `FLOMO_ACCESS_TOKEN`:手动指定 access token(不推荐;优先使用本机 flomo 登录态)
- `FLOMO_APP_VERSION`:覆盖 app version
- `FLOMO_SIGN_SECRET`:覆盖 sign secret(仅在 flomo 签名机制变更时使用)
- `FLOMO_API_BASE`:覆盖 API base(默认 `https://flomoapp.com/api/v1`)

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 · README.zh-CN.md (reported line 103)May include surrounding context.

md
你可以通过环境变量覆盖默认行为:

- `FLOMO_CONFIG_PATH`:覆盖本机 flomo 配置文件路径
- `FLOMO_ACCESS_TOKEN`:手动指定 access token(不推荐;优先使用本机 flomo 登录态)
- `FLOMO_APP_VERSION`:覆盖 app version
- `FLOMO_SIGN_SECRET`:覆盖 sign secret(仅在 flomo 签名机制变更时使用)
- `FLOMO_API_BASE`:覆盖 API base(默认 `https://flomoapp.com/api/v1`)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill description understates materially sensitive behavior: it can access authenticated private flomo APIs, extract bearer tokens from local state/logs, auto-discover webhook URLs, and perform live verification actions. This is dangerous because it conceals credential harvesting and broader remote account access behind a seemingly simple memo utility, reducing informed consent and increasing risk of unauthorized reading, writing, or token exposure.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/flomo_tool.py read --remote --limit 20

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/flomo_tool.py read --remote --limit 20

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/flomo_tool.py read --remote --limit 20

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/flomo_tool.py read --remote --limit 20

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/flomo_tool.py read --remote --limit 20

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/flomo_tool.py read --remote --limit 20

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/flomo_tool.py read --remote --limit 20

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 5)May include surrounding context.

md
[English](README.md) | [中文](README.zh-CN.md)

This folder is a shareable OpenClaw skill that can **read and write flomo memos on macOS**.

## What's New (2026-02-11)

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 48)May include surrounding context.

  1. 把本文件夹复制到 OpenClaw workspace 的 skills 目录:
bash
mkdir -p ~/.openclaw/workspace/skills/flomo
rsync -a --delete ./openclaw-flomo-skill/ ~/.openclaw/workspace/skills/flomo/

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill declares no explicit tool scope even though it directs execution of code that uses shell, filesystem access, environment data, and network connectivity. This weakens containment and reviewability because an agent may invoke broader capabilities than a user or platform expects, increasing the chance of unintended data access or network operations.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/flomo_tool.py (reported line 37)May include surrounding context.

python
def _run_strings(path: Path) -> str:
    proc = subprocess.run(["strings", "-n", "6", str(path)], capture_output=True, text=True)
    if proc.returncode != 0:
        raise RuntimeError(proc.stderr.strip() or f"strings failed for {path}")
    return proc.stdout

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/flomo_tool.py (reported line 45)May include surrounding context.

python
def _run_curl(args: list[str]) -> str:
    # Use curl for network calls to avoid Python SSL cert issues on some machines.
    proc = subprocess.run(args, capture_output=True, text=True)
    if proc.returncode != 0:
        err = (proc.stderr or "").strip()
        out = (proc.stdout or "").strip()

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill reads bearer tokens from local flomo config and includes logic to extract authorization tokens from renderer logs, then uses them against undocumented authenticated APIs. This expands the skill from local memo assistance into credential harvesting and privileged remote account access without clear necessity or user disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code accesses local flomo config to retrieve access tokens and reads local application data without any user-facing disclosure or consent mechanism. In a note-taking context, that can expose sensitive personal information and account credentials, making the behavior more dangerous than generic local file access.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The stated skill purpose emphasizes local cache search and memo creation, but the implementation also performs authenticated remote reads and metadata enumeration through private APIs. That capability mismatch is dangerous because users may not expect the skill to enumerate or exfiltrate cloud-hosted note content beyond the narrow documented workflow.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill sends memo content to a remote webhook/API without any built-in disclosure or confirmation at the point of transmission. Because memos often contain sensitive personal notes, silent network transmission can surprise users and leak private data if the webhook or destination is not explicitly user-controlled.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/flomo_tool.py (reported line 387)May include surrounding context.

python
def write_url_scheme(content: str):
    qs = urllib.parse.urlencode({"content": content})
    url = f"flomo://create?{qs}"
    proc = subprocess.run(["open", url], capture_output=True, text=True)
    if proc.returncode != 0:
        raise RuntimeError(proc.stderr.strip() or "open flomo:// failed")
    return {"ok": True, "mode": "url_scheme", "opened": True}

Tainted flow: 'url' from os.getenv (line 187, credential/environment) → subprocess.run (code execution)

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 · scripts/flomo_tool.py (reported line 387)May include surrounding context.

python
def write_url_scheme(content: str):
    qs = urllib.parse.urlencode({"content": content})
    url = f"flomo://create?{qs}"
    proc = subprocess.run(["open", url], capture_output=True, text=True)
    if proc.returncode != 0:
        raise RuntimeError(proc.stderr.strip() or "open flomo:// failed")
    return {"ok": True, "mode": "url_scheme", "opened": True}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

Extracting a bearer token from renderer logs is effectively credential scraping from application telemetry, and it is done silently. If abused, this grants authenticated access to the user's flomo account and bypasses normal expectations about how credentials should be handled.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This file is a Chinese-language README and presents the Chinese version by default, with only a link to English. The policy category calls out language or locale constraints; here the skill documentation is localized to Chinese without an explicit user language choice in the content itself.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

Opening the flomo URL scheme causes an external app action that writes content, yet there is no confirmation step or warning. While lower impact than credential access, it still permits unintended data creation or leakage to another application context.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.