Back to skill

Security audit

Flomo Via App

Security checks for vulnerabilities and agentic risk

Overview

This skill is meant to send notes to flomo, but its instructions and scripts have important inconsistencies and unsafe configuration handling that users should review before installing.

Install only if you are comfortable running local shell scripts and sending note content through a flomo webhook. Treat the webhook token as a secret, prefer a local permission-restricted config over shell-profile persistence, and inspect any token or URL before saving it. The package should be fixed to align the URL Scheme documentation with actual behavior and to validate or safely serialize configuration values.

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

Error
Location
scripts/configure.sh:30
Finding

Arbitrary Command Execution Through Unsafe Configuration Serialization

Content
View full analysis

Vulnerability Details

File Location: scripts/configure.sh:30-100; configuration is subsequently executed by scripts/flomo_send.sh:14-19
Vulnerability Type: Shell command injection through sourced configuration
Risk Level: High

Vulnerable Code

scripts/configure.sh accepts a webhook value without validating or escaping shell metacharacters:

bash
read -rp "Webhook token (or full URL): " WEBHOOK_INPUT

if [ -z "$WEBHOOK_INPUT" ]; then
    echo "⚠️  No webhook provided. You can configure it later by running this script again."
    exit 0
fi

# Detect if user pasted full URL or just token
if echo "$WEBHOOK_INPUT" | grep -q "^https://flomoapp.com/iwh/"; then
    # Full URL provided
    WEBHOOK_URL="$WEBHOOK_INPUT"
    WEBHOOK_TOKEN=$(echo "$WEBHOOK_URL" | sed 's|https://flomoapp.com/iwh/||')
else
    # Just token provided
    WEBHOOK_TOKEN="$WEBHOOK_INPUT"
    WEBHOOK_URL="https://flomoapp.com/iwh/$WEBHOOK_TOKEN"
fi

The unescaped value is written as executable shell syntax to either a shell startup file:

bash
echo "" >> "$SHELL_CONFIG"
echo "# Flomo Skill Configuration" >> "$SHELL_CONFIG"
echo "export FLOMO_WEBHOOK_TOKEN=$WEBHOOK_TOKEN" >> "$SHELL_CONFIG"

Or to the local .env file:

bash
ENV_FILE="$(dirname "$0")/../.env"
echo "# Flomo Skill Configuration" > "$ENV_FILE"
echo "FLOMO_WEBHOOK_TOKEN=$WEBHOOK_TOKEN" >> "$ENV_FILE"
echo "# FLOMO_WEBHOOK_URL=$WEBHOOK_URL" >> "$ENV_FILE"
chmod 600 "$ENV_FILE"

scripts/flomo_send.sh later executes the generated .env file as shell code:

bash
ENV_FILE="$(dirname "$0")/../.env"
if [ -f "$ENV_FILE" ]; then
    set -o allexport
    # shellcheck disable=SC1090
    source "$ENV_FILE"
    set +o allexport
fi

Technical Analysis

The webhook token crosses a trust boundary from interactive user input into a shell program. It is serialized by concatenating it directly into an ...[truncated 2187 chars]

Remediation
View remediation

Remediation Suggestions

  1. Validate token-only input against the exact character set and length allowed by flomo. Reject whitespace, control characters, shell metacharacters, and unexpected URL syntax.

  2. Prefer accepting only a token and constructing the fixed webhook URL internally. Do not accept arbitrary shell expressions or unrestricted URLs.

  3. Do not load data files with source. Store configuration in a non-executable format, such as JSON, and parse the required field with a data parser.

  4. If shell-compatible output is unavoidable, serialize values safely with printf '%q' rather than string concatenation:

    bash
    {
        printf '%s\n' '# Flomo Skill Configuration'
        printf 'FLOMO_WEBHOOK_TOKEN=%q\n' "$WEBHOOK_TOKEN"
    } > "$ENV_FILE"
    chmod 600 "$ENV_FILE"
    
  5. Avoid writing credentials to shell startup files. Use the permission-restricted, non-executable application configuration file instead.

  6. Write configuration atomically using a securely created temporary file, set restrictive permissions before adding the secret, and then rename it into place.

  7. Add regression tests using values containing semicolons, command substitutions, quotes, backticks, spaces, and redirection operators. All malformed values should be rejected without executing any command.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/flomo_send.sh:69
Finding

Unrestricted Webhook URL Allows Note Exfiltration and Arbitrary HTTP POST Requests

Content
View full analysis

Vulnerability Details

File Location: scripts/flomo_send.sh:69-88
Vulnerability Type: Unvalidated outbound request destination
Risk Level: Medium

Vulnerable Code

bash
send_webhook() {
    if [ -n "$FLOMO_WEBHOOK_URL" ]; then
        WEBHOOK_URL="$FLOMO_WEBHOOK_URL"
    elif [ -n "$FLOMO_WEBHOOK_TOKEN" ]; then
        WEBHOOK_URL="https://flomoapp.com/iwh/$FLOMO_WEBHOOK_TOKEN"
    else
        return 2
    fi

    # Build JSON payload safely (handles quotes/newlines in content).
    if command -v python3 >/dev/null 2>&1; then
        PAYLOAD=$(printf '%s' "$FULL_CONTENT" | python3 -c 'import sys,json;print(json.dumps({"content": sys.stdin.read()}))')
    else
        # Fallback: escape simple cases (less safe for arbitrary input)
        ESCAPED=$(printf '%s' "$FULL_CONTENT" | sed -e 's/\\/\\\\/g' -e 's/"/\\\"/g' -e ':a;N;$!ba;s/\n/\\n/g')
        PAYLOAD="{\"content\": \"$ESCAPED\"}"
    fi

    RESP=$(curl -sS -w "\n%{http_code}" -X POST "$WEBHOOK_URL" -H "Content-Type: application/json" -d "$PAYLOAD" || true)

Technical Analysis

When FLOMO_WEBHOOK_URL is defined, the script passes its value directly to curl without verifying the URL scheme, hostname, port, or path. Although project documentation presents https://flomoapp.com/iwh/... as the expected format, executable code does not enforce that restriction.

Consequently, anyone able to influence the process environment or local configuration can redirect the complete note payload to an attacker-controlled server. The same behavior may also be used to issue a JSON HTTP POST from the victim's network context to an internal or local HTTP service.

Quoting "$WEBHOOK_URL" prevents shell argument injection, but it does not make the network destination trustworthy.

Attack Path

  1. An attacker causes FLOMO_WEBHOOK_URL to be set to an attacker-controlled URL, or modifies the Skill's local configuration to define s ...[truncated 1063 chars]
Remediation
View remediation

Remediation Suggestions

  1. Prefer removing FLOMO_WEBHOOK_URL support and accept only a strictly validated webhook token.

  2. Construct the destination internally from a constant origin:

    bash
    WEBHOOK_URL="https://flomoapp.com/iwh/$FLOMO_WEBHOOK_TOKEN"
    
  3. Validate the token against flomo's documented character set and length before constructing the URL.

  4. If full URL support is required, parse the URL with a proper URL parser and require:

    • The https scheme.
    • The exact flomoapp.com hostname.
    • The expected port or no explicit port.
    • A path beginning with /iwh/.
    • No user-information component.
    • No control characters or malformed encoding.
  5. Configure curl to fail explicitly on HTTP errors and apply conservative connection and request timeouts.

  6. Reject non-Flomo destinations before handling or transmitting note content, and return an actionable error without including the secret webhook value.

  7. Add tests confirming that alternate domains, subdomain lookalikes, HTTP URLs, localhost addresses, private-network addresses, user-information tricks, and alternate ports are rejected.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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 (34)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The README claims URL-scheme delivery, automatic app detection, and webhook fallback behavior that the static analysis indicates are not actually implemented. This mismatch can mislead users about where their note content goes and under what conditions network transmission occurs, which is a security-relevant deception even if not overtly malicious.

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/flomo_send.sh "Your note content" "#tag1 #tag2"

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

This script writes the flomo webhook token to a plaintext .env file in the skill directory. Although intended for convenience, storing long-lived credentials in a local file can expose them to other local processes, accidental inclusion in backups, sync tools, or source control if the directory is mishandled.

Content

Scanner excerpt · scripts/configure.sh (reported line 93)May include surrounding context.

sh
fi
                ;;
            *)
                # Save to .env file (default)
                ENV_FILE="$(dirname "$0")/../.env"
                echo "# Flomo Skill Configuration" > "$ENV_FILE"
                echo "FLOMO_WEBHOOK_TOKEN=$WEBHOOK_TOKEN" >> "$ENV_FILE"

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

Writing FLOMO_WEBHOOK_TOKEN directly into a plaintext .env file persists a usable authentication secret on disk. If that file is read by unauthorized local users, malware, or accidentally committed/shared, an attacker could send notes to the user's flomo inbox via the webhook.

Content

Scanner excerpt · scripts/configure.sh (reported line 94)May include surrounding context.

sh
;;
            *)
                # Save to .env file (default)
                ENV_FILE="$(dirname "$0")/../.env"
                echo "# Flomo Skill Configuration" > "$ENV_FILE"
                echo "FLOMO_WEBHOOK_TOKEN=$WEBHOOK_TOKEN" >> "$ENV_FILE"
                echo "# FLOMO_WEBHOOK_URL=$WEBHOOK_URL" >> "$ENV_FILE"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/configure.sh (reported line 69)May include surrounding context.

sh
set -e

# Load local .env if present (export variables so they're available to curl/python)
ENV_FILE="$(dirname "$0")/../.env"
if [ -f "$ENV_FILE" ]; then
    set -o allexport

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/configure.sh (reported line 101)May include surrounding context.

sh
set -e

# Load local .env if present (export variables so they're available to curl/python)
ENV_FILE="$(dirname "$0")/../.env"
if [ -f "$ENV_FILE" ]; then
    set -o allexport

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/flomo_send.sh (reported line 13)May include surrounding context.

sh
set -e

# Load local .env if present (export variables so they're available to curl/python)
ENV_FILE="$(dirname "$0")/../.env"
if [ -f "$ENV_FILE" ]; then
    set -o allexport

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/flomo_send.sh (reported line 14)May include surrounding context.

sh
set -e

# Load local .env if present (export variables so they're available to curl/python)
ENV_FILE="$(dirname "$0")/../.env"
if [ -f "$ENV_FILE" ]; then
    set -o allexport
    # shellcheck disable=SC1090

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest says the skill sends notes via URL Scheme with automatic webhook fallback and supports quick capture workflows on macOS. In contrast, the README explicitly states that URL Scheme mode has been cancelled/removed and that the skill now uniformly uses the Webhook API, which is a direct contradiction in documented intent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README instructs users to store a sensitive webhook token in shell profiles or a local .env file without any warning about file permissions, accidental source control commits, shell history exposure, or broader environment leakage. In this skill's context, the token grants the ability to submit content into the user's flomo inbox, so disclosure could enable unauthorized note injection or abuse of the webhook endpoint.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest presents URL Scheme delivery with webhook fallback as a core feature. This README section explicitly says direct URL Scheme invocation has been removed and users should use only the Webhook API, which is an active contradiction rather than a mere omission.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill documentation directs users to run shell scripts (./scripts/configure.sh, ./scripts/flomo_send.sh) but does not declare any corresponding tool scope or permissions. This weakens the trust boundary for users and reviewers because shell execution capability is implied but not transparently declared, increasing the chance that users execute local code without adequate scrutiny.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.