Back to skill

Security audit

flomo-sync

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real flomo backup tool, but it handles session tokens, remote attachment URLs, and generated file paths with more authority than is safely scoped.

Install only if you are comfortable giving this script access to your flomo account and writing all notes and attachments to local disk. Use a dedicated private output folder, exclude exports and .flomo.config from git/cloud sharing, prefer --no-download unless you need attachments, and treat the copied token like a password. The publisher should sanitize slugs, enforce output-directory containment, restrict attachment hosts and sizes, and provide a safer authentication story before broad use.

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

Warning
Location
scripts/flomo-sync.py:267
Finding

Unrestricted Attachment Retrieval Enables SSRF and Unbounded Disk Consumption

Content
View full analysis
str | None: """ Download an attachment into images_dir/YYYY/MM/DD/{slug}_{name}. """ ext = _ext_from_url(url) or Path(name).suffix.lower() if ext not in IMAGE_EXTS and ext not in AUDIO_EXTS: return None try: dt = datetime.strptime(created_at[:10], "%Y-%m-%d") date_path = Path(f"{dt.year:04d}") / f"{dt.month:02d}" / f"{dt.day:02d}" except (ValueError, TypeError): date_path = Path("unknown") dest_dir = images_dir / date_path dest_dir.mkdir(parents=True, exist_ok=True) safe_name = name.replace("/", "_").replace("\\", "_") if not Path(safe_name).suffix and ext: safe_name = safe_name + ext filename = f"{slug}_{safe_name}" dest_path = dest_dir / filename if dest_path.exists(): return str(Path("images") / date_path / filename) try: resp = requests.get(url, timeout=30, stream=True) resp.raise_for_status() with open(dest_path, "wb") as f: for chunk in resp.iter_content(chunk_size=65536): f.write(chunk) return str(Path("images") / date_path / filename) except Exception as e: print(f" ⚠ Download failed {name}: {e}", flush=True) return None ``` The function is invoked for attachment URLs supplied by the remote API: ```python if images_dir is not None: local_path = download_attachment(url, name, slug, created_at, images_dir) ``` ### Technical Analysis Attachment URLs are taken from the flomo API response and passed directly to `requests.get()`. The implementation does not validate: - The URL scheme - The desti ...[truncated 2516 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/flomo-sync.py:390
Finding

Unsanitized Memo Slugs Can Escape the Intended Output Directory

Content
View full analysis
str: slug = memo.get("slug") or f"memo_{id(memo)}" parts: list[str] = [] created_at = str(memo.get("created_at") or "") if len(created_at) >= 10: parts.append(created_at[:10]) tags = memo.get("tags") or [] if tags: leaf = tags[0].split("/")[-1] leaf = re.sub(r'[\\/:*?"<>|]', "", leaf).strip() if leaf: parts.append(leaf) content_md = html_to_md(memo.get("content") or "") content_clean = re.sub(r"#\S+", "", content_md) chars = re.findall(r"[\u4e00-\u9fff\w]", content_clean) preview = "".join(chars[:6]) if preview: parts.append(preview) parts.append(slug) return "_".join(parts) + ".md" def write_memo(memo: dict, output_dir: Path, images_dir: Path | None) -> str: new_filename = _memo_filename(memo) new_path = output_dir / new_filename slug = memo.get("slug") or "" new_content = memo_to_md_text(memo, images_dir) status = "created" if slug: for old in output_dir.glob(f"*_{slug}.md"): if old.name != new_filename: old.unlink() ...[truncated 2817 chars]
Remediation
View remediation
str: slug = re.sub(r"[^A-Za-z0-9_-]", "_", str(value or "")) slug = slug.strip("_") if not slug: raise ValueError("Invalid memo slug") return slug[:128] ``` 2. Apply the same validation before using a slug in Markdown filenames, attachment filenames, and glob patterns. 3. Resolve every destination path and verify containment before writing: ```python root = output_dir.resolve() destination = (root / filename).resolve() if destination != root and root not in destination.parents: raise ValueError("Destination escapes output directory") ``` 4. Perform an equivalent containment check against `images_dir.resolve()` for attachments. 5. Reject absolute paths and any filename containing path separators before joining paths. 6. Avoid using untrusted values directly in glob expressions. Locate existing files through validated identifiers or a local index instead. 7. Use exclusive creation or atomic temporary-file replacement where overwriting is not explicitly required. 8. Add tests for `../`, nested traversal, absolute POSIX paths, Windows drive paths, UNC paths, encoded separators, and mixed slash styles. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:20
Finding

Runtime Dependencies Are Installed Without Version or Integrity Pinning

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (17)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
description: 将 flomo 所有记录 memo 同步/备份到本地 Markdown 文件的工具。使用 scripts/flomo-sync.py 脚本通过 flomo API 拉取 memo,支持增量同步、附件下载、多文件输出。当用户需要备份 flomo、同步 flomo memo 到本地、导出 flom

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
description: 将 flomo 所有记录 memo 同步/备份到本地 Markdown 文件的工具。使用 scripts/flomo-sync.py 脚本通过 flomo API 拉取 memo,支持增量同步、附件下载、多文件输出。当用户需要备份 flomo、同步 flomo memo 到本地、导出 flom

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
description: 将 flomo 所有记录 memo 同步/备份到本地 Markdown 文件的工具。使用 scripts/flomo-sync.py 脚本通过 flomo API 拉取 memo,支持增量同步、附件下载、多文件输出。当用户需要备份 flomo、同步 flomo memo 到本地、导出 flom

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
description: 将 flomo 所有记录 memo 同步/备份到本地 Markdown 文件的工具。使用 scripts/flomo-sync.py 脚本通过 flomo API 拉取 memo,支持增量同步、附件下载、多文件输出。当用户需要备份 flomo、同步 flomo memo 到本地、导出 flom

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
description: 将 flomo 所有记录 memo 同步/备份到本地 Markdown 文件的工具。使用 scripts/flomo-sync.py 脚本通过 flomo API 拉取 memo,支持增量同步、附件下载、多文件输出。当用户需要备份 flomo、同步 flomo memo 到本地、导出 flom

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
description: 将 flomo 所有记录 memo 同步/备份到本地 Markdown 文件的工具。使用 scripts/flomo-sync.py 脚本通过 flomo API 拉取 memo,支持增量同步、附件下载、多文件输出。当用户需要备份 flomo、同步 flomo memo 到本地、导出 flom

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
description: 将 flomo 所有记录 memo 同步/备份到本地 Markdown 文件的工具。使用 scripts/flomo-sync.py 脚本通过 flomo API 拉取 memo,支持增量同步、附件下载、多文件输出。当用户需要备份 flomo、同步 flomo memo 到本地、导出 flom

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
description: 将 flomo 所有记录 memo 同步/备份到本地 Markdown 文件的工具。使用 scripts/flomo-sync.py 脚本通过 flomo API 拉取 memo,支持增量同步、附件下载、多文件输出。当用户需要备份 flomo、同步 flomo memo 到本地、导出 flom

Ssd 3

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

Instructing users to recover and reuse the live Authorization header from browser network traffic effectively asks them to repurpose an active session credential outside its intended context. If exposed via terminal history, screenshots, logs, shell scripts, or plaintext config files, an attacker could use that bearer token to access the user's flomo data until it expires or is revoked.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The CLI help repeats unsafe operational guidance, increasing the chance users will place a sensitive bearer token directly on the command line, where it may be captured by shell history, process listings, CI logs, or support transcripts. Repetition in built-in help makes the insecure workflow part of normal operation rather than an exceptional workaround.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill advertises behavior that reads a local config file, writes Markdown and attachments to disk, and calls the flomo API, but it declares no explicit tool scope or permission boundary. Without a declared scope, an agent may invoke file and network capabilities more broadly than users expect, increasing the chance of unintended data exposure or filesystem writes.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The description is written as a direct operational instruction in Chinese and the file provides no indication that users may choose another language or that the skill is limited to a Chinese-only compliance or regional context. Under the policy criteria, forcing a specific language without opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The instructions tell users to extract a live Authorization bearer token from browser developer tools and reuse it in the script, but do not treat it as a sensitive credential or warn about scope, storage, and leakage risks. This encourages insecure credential handling and normalizes copying session-equivalent secrets into local files and command histories.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script hardcodes a reverse-engineered signing secret and reproduces a private API signature flow to impersonate the official web client. That exceeds a normal backup tool's required trust boundary and creates a durable capability to access undocumented endpoints in ways the platform did not intend, increasing legal, security, and account-risk exposure if reused or adapted.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script writes markdown files, downloads attachments, and deletes prior memo files with matching slugs when filenames change. While the tool's purpose is synchronization, the deletion behavior is not clearly disclosed to the user in nearby comments, prompts, or CLI messaging, so users may not realize existing files in the target directory can be removed or replaced.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill describes syncing all memos and downloading attachments locally, but it does not prominently warn that this will persist potentially sensitive personal notes and media onto disk in bulk. In this context, the data being synced is likely private, so insufficient disclosure can lead to accidental local retention, backup propagation, or storage in unsafe locations.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The file output section says the tool may generate flomo_export.md in a --single mode, but the parameter table above lists only --token, --dir, --after, and --no-download. Within this provided file, that documented mode is not otherwise defined, creating an intent/documentation mismatch that could mislead users about supported behavior.

Content

No source excerpt is available for this finding.