Back to skill

Security audit

Article to Feishu

Security checks for vulnerabilities and agentic risk

Overview

This skill does the article-import workflow it advertises, but it fetches arbitrary URLs and downloads remote files with weak scoping and privacy controls.

Review before installing. Use this only for public, non-sensitive article URLs, avoid signed/private/internal links, and run it in an environment without access to internal networks or sensitive local files. Prefer a unique private temp directory, add URL allowlists and download limits, and confirm Feishu document creation before allowing the agent to write to your workspace.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/download_article_images.sh:29
Finding
Unrestricted Article URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/download_article_images.sh:29-57, 71` **Vulnerability Type**: Server-Side Request Forgery through unrestricted URL fetching **Risk Level**: High ### Vulnerable Code ```bash URL="$1" OUTPUT_DIR="$2" CUSTOM_REFERER="$3" # Auto-detect referer based on URL domain detect_referer() { local url="$1" if [[ "$url" == *"cnblogs.com"* ]]; then echo "https://www.cnblogs.com/" elif [[ "$url" == *"toutiao.com"* ]]; then echo "https://www.toutiao.com/" elif [[ "$url" == *"csdn.net"* ]]; then echo "https://blog.csdn.net/" elif [[ "$url" == *"weixin.qq.com"* ]]; then echo "https://mp.weixin.qq.com/" elif [[ "$url" == *"jianshu.com"* ]]; then echo "https://www.jianshu.com/" elif [[ "$url" == *"zhihu.com"* ]]; then echo "https://zhuanlan.zhihu.com/" else # Extract domain from URL echo "https://$(echo "$url" | sed -E 's|https?://([^/]+).*|\1|')/" fi } # Determine referer if [ -n "$CUSTOM_REFERER" ]; then REFERER="$CUSTOM_REFERER" else REFERER=$(detect_referer "$URL") fi # Fetch HTML content echo "Fetching page content..." HTML=$(curl -sL "$URL" 2>/dev/null) ``` The documented workflow also encourages passing a user-provided article URL directly into this script: ```bash bash {baseDir}/scripts/download_article_images.sh "$ARTICLE_URL" /tmp/article-img/ ``` ### Technical Analysis The script passes an arbitrary user-controlled URL directly to `curl`. It does not validate: - The URL scheme. - The destination hostname. - The resolved IP address. - Whether the address is loopback, private, link-local, reserved, or a cloud metadata address. - Redirect destinations followed by `curl -L`. - The presence of URL credentials. - Whether the URL belongs to a supported public article domain. Substring checks in `detect_referer` only select a Referer value and do not restrict the actual request destination. Conseq ...[truncated 1861 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Accept only well-formed `https://` URLs; reject all other schemes. 2. Reject embedded usernames, passwords, malformed hosts, and ambiguous URL encodings. 3. Resolve the hostname before connecting and reject every address in: - Loopback ranges. - Private IPv4 and IPv6 ranges. - Link-local ranges. - Multicast and reserved ranges. - Cloud metadata address ranges. 4. Pin the connection to an approved resolved public address to reduce DNS rebinding risk. 5. Disable automatic redirects or validate the scheme, hostname, and resolved destination after every redirect. 6. Prefer a strict allowlist of supported public article domains. 7. Run network-fetching scripts in a sandbox without access to internal networks or metadata services. 8. Add connection and total request timeouts. 9. Do not rely on substring hostname matching. Parse the URL and compare normalized hostnames exactly. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_article.sh:13
Finding
Complete User-Supplied URLs Are Disclosed to Jina AI Reader<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch_article.sh:13-20`; also present in `scripts/extract_images.sh:13-16` and `scripts/download_images.sh:20-27` **Vulnerability Type**: Sensitive URL disclosure to an external service **Risk Level**: Medium ### Vulnerable Code From `scripts/fetch_article.sh`: ```bash URL="$1" JINA_API="https://r.jina.ai/" # Build Jina Reader URL JINA_URL="${JINA_API}${URL}" # Fetch article content curl -sL "$JINA_URL" 2>/dev/null ``` The same behavior appears in `scripts/extract_images.sh`: ```bash URL="$1" JINA_API="https://r.jina.ai/" # Fetch article content CONTENT=$(curl -sL "${JINA_API}${URL}" 2>/dev/null) ``` It also appears in `scripts/download_images.sh`: ```bash URL="$1" OUTPUT_DIR="$2" JINA_API="https://r.jina.ai/" REFERER="https://www.toutiao.com/" # Create output directory mkdir -p "$OUTPUT_DIR" echo "Fetching article content..." CONTENT=$(curl -sL "${JINA_API}${URL}" 2>/dev/null) ``` ### Technical Analysis Each script concatenates the complete user-supplied URL to `https://r.jina.ai/` and sends the resulting request to an external service. No warning, consent check, or sensitive-parameter filtering is performed. URLs can contain security-sensitive information, including: - Signed query parameters. - Temporary access tokens. - Document identifiers. - Password-reset or invitation tokens. - Internal hostnames and paths. - User identifiers and tracking parameters. HTTPS protects the request while it is in transit, but it does not prevent the receiving external service from observing the complete URL. The issue is therefore an unannounced cross-boundary disclosure rather than plaintext transport. ### Attack Path 1. A user supplies a private, signed, token-bearing, or otherwise sensitive article URL. 2. The Agent invokes `fetch_article.sh`, `extract_images.sh`, or `download_images.sh`. 3. The script embeds the complete URL in a request sent to `r.jina.ai`. 4. Jina AI Reader receives and ca ...[truncated 806 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Clearly disclose that the complete URL will be sent to Jina AI Reader and require explicit user consent. 2. Use direct local fetching by default and make third-party proxying an opt-in fallback. 3. Reject URLs containing embedded credentials. 4. Detect potentially sensitive query parameters such as `token`, `key`, `signature`, `auth`, and `code`; refuse proxying or request confirmation. 5. Where possible, remove tracking and nonessential query parameters before proxying. 6. Do not send private, intranet, or signed URLs to external reader services. 7. Document the external service, the data transmitted, and any applicable retention or privacy implications. 8. Consider a self-hosted reader service when processing confidential content. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download_article_images.sh:29
Finding
Predictable Shared Temporary Directory Permits Symlink-Based File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `scripts/download_article_images.sh:29-30, 67, 113-120`; predictable path documented at `SKILL.md:26` **Vulnerability Type**: Unsafe temporary file handling and symlink overwrite **Risk Level**: Medium ### Vulnerable Code The output directory is accepted and reused without verifying its ownership, permissions, or existing contents: ```bash URL="$1" OUTPUT_DIR="$2" CUSTOM_REFERER="$3" ``` ```bash # Create output directory mkdir -p "$OUTPUT_DIR" ``` Downloaded content is then written to predictable sequential filenames: ```bash # Format filename with zero-padding printf -v FILENAME "%02d.%s" $i "$EXT" FILEPATH="${OUTPUT_DIR}/${FILENAME}" echo "[$i/$TOTAL] Downloading: $FILENAME" # Download with Referer header HTTP_CODE=$(curl -sL -w "%{http_code}" -H "Referer: $REFERER" "$IMG_URL" -o "$FILEPATH" 2>/dev/null) ``` The Skill documentation recommends a fixed shared path: ```bash bash {baseDir}/scripts/download_article_images.sh "$ARTICLE_URL" /tmp/article-img/ ``` ### Technical Analysis The documented workflow uses the predictable shared directory `/tmp/article-img/`, while downloaded files receive predictable names such as `01.jpg` and `02.png`. The script does not: - Create a uniquely named private directory. - Verify ownership or permissions of an existing directory. - Reject symbolic links. - Create output files with exclusive creation semantics. - Check whether a destination file already exists. - Remove stale files before later upload. - Apply restrictive permissions. On a multi-user system, another local process may pre-create the directory or predictable destination entries. If an entry is a symbolic link, `curl -o` may follow it and overwrite the linked target when the Agent has permission to write that target. Existing ordinary files can also remain in the directory and may be mistaken for newly downloaded article images during the subsequent Feishu upload workflow. ### Attack Path 1. A l ...[truncated 1363 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a unique private directory for every invocation: ```bash umask 077 OUTPUT_DIR=$(mktemp -d "${TMPDIR:-/tmp}/article-images.XXXXXX") ``` 2. Register cleanup immediately: ```bash trap 'rm -rf -- "$OUTPUT_DIR"' EXIT HUP INT TERM ``` 3. Do not accept or document a fixed shared temporary directory as the default. 4. If callers may supply an output directory, verify that it is owned by the current user, is not a symbolic link, and is not writable by other users. 5. Reject pre-existing destination files and symbolic links. 6. Create files atomically with exclusive creation semantics before writing. 7. Apply restrictive directory and file permissions. 8. Enumerate only files created during the current invocation when uploading to Feishu. 9. Ensure cleanup occurs both after success and after any intermediate failure. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download_images.sh:25
Finding
Unbounded Remote Downloads Enable Resource Exhaustion and Unvalidated File Ingestion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/download_images.sh:25-58`; related behavior in `scripts/download_article_images.sh:71-78, 117-128` **Vulnerability Type**: Unbounded network resource consumption and missing content validation **Risk Level**: Medium ### Vulnerable Code From `scripts/download_images.sh`: ```bash echo "Fetching article content..." CONTENT=$(curl -sL "${JINA_API}${URL}" 2>/dev/null) # Extract image URLs IMAGE_URLS=$(echo "$CONTENT" | grep -oE 'https?://[^)"'\'' ]+\.(jpg|jpeg|png|gif|webp)' | sort -u) if [ -z "$IMAGE_URLS" ]; then echo "No images found in the article." exit 0 fi # Count images TOTAL=$(echo "$IMAGE_URLS" | wc -l) echo "Found $TOTAL images. Downloading..." # Download images with Referer header i=1 for IMG_URL in $IMAGE_URLS; do # Extract extension EXT="${IMG_URL##*.}" # Handle query parameters in extension EXT=$(echo "$EXT" | cut -d'?' -f1) # Format filename with zero-padding printf -v FILENAME "%02d.%s" $i "$EXT" FILEPATH="${OUTPUT_DIR}/${FILENAME}" echo "[$i/$TOTAL] Downloading: $FILENAME" # Download with Referer header (anti-hotlink bypass) curl -sL -H "Referer: $REFERER" "$IMG_URL" -o "$FILEPATH" # Check if download succeeded if [ -f "$FILEPATH" ]; then SIZE=$(stat -c%s "$FILEPATH" 2>/dev/null || stat -f%z "$FILEPATH" 2>/dev/null || echo "unknown") echo " Size: $SIZE bytes" else echo " Failed to download!" fi ((i++)) done ``` The generic downloader similarly performs unconstrained downloads: ```bash HTML=$(curl -sL "$URL" 2>/dev/null) IMAGE_URLS=$(echo "$HTML" | grep -oE '(https?://[^"'\''()<>]+\.(jpg|jpeg|png|gif|webp))' | sort -u | head -50) ``` ```bash HTTP_CODE=$(curl -sL -w "%{http_code}" -H "Referer: $REFERER" "$IMG_URL" -o "$FILEPATH" 2>/dev/null) ``` ### Technical Analysis The network requests do not define: - A connection timeout. - A total execution timeout. - A ...[truncated 2263 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add strict curl limits, including connection timeout, total timeout, redirect limit, and failure on HTTP errors. 2. Enforce a maximum article-response size before processing it. 3. Cap the number of images, individual image size, and aggregate download size. 4. Stream responses rather than storing an unbounded article body in a shell variable. 5. Check HTTP status codes and reject unsuccessful responses. 6. Validate `Content-Type` against an explicit image MIME allowlist. 7. Verify file signatures after download rather than trusting URL extensions or response headers. 8. Download to a temporary partial file and atomically rename it only after validation. 9. Delete partial, undersized, oversized, or invalid files. 10. Run downloads under filesystem, memory, CPU, and network quotas. 11. Consider explicit settings such as: ```bash curl --fail --show-error \ --connect-timeout 5 \ --max-time 30 \ --max-redirs 3 \ --location \ ... ``` A wrapper or streaming downloader should additionally enforce byte limits because timeout settings alone do not prevent fast oversized responses. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
描述强调这是一个可把多种网站文章导入飞书、自动下载图片并按顺序插入的技能;而给出的代码仅是 `convert_to_feishu.sh` 模板,注释和输出都明确说明“Actual conversion must be done by AI agent using feishu tools”。它能做的主要是调用 `download_images.sh`、`fetch_article.sh`,统计图片、预览内容,并提示后续人工/AI agent 如何调用 `feishu_create_doc`、`feishu_update_doc`、`feishu_doc_media`。因此,代码的实际行为与声明的完整能力存在实质差距:核心的飞书文档生成与插图并未在代码中实现,且站点支持范围也未体现为多站点实现,而是明显偏向 Toutiao。

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
声明的核心能力是“把网页文章转换为飞书文档”,包括处理文章内容并将图片插入飞书。实际代码只是一个 shell 脚本:接收文章 URL 和输出目录,自动推断 referer,抓取页面 HTML,用正则提取图片 URL,然后将图片下载到本地目录。虽然这与“自动下载图片”这一子功能部分相关,但它缺少声明中最关键的主功能:解析文章正文、生成飞书文档、调用飞书接口、插入内容与图片。因此代码实际行为仅覆盖声明功能中的一个辅助步骤,主目的与对外描述存在明显不一致。

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
声明的核心用途是“把网页文章转换为飞书文档”,并支持多个站点、自动插图。实际代码只是一个 shell 脚本,用于从文章内容中提取图片 URL 并下载到本地文件夹,且注释和参数都表明其主要针对 Toutiao。代码中没有任何飞书 API 调用、文档生成、正文解析重组、图片插入到文档、或多平台适配逻辑。因此其主要目的与声明严重不符,属于明显描述与行为不一致。

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared skill describes an end-to-end article-to-Feishu conversion tool supporting multiple websites and automatic image handling. The supplied code only retrieves page content through r.jina.ai and extracts image links with grep, outputting deduplicated URLs. This is only a small helper-like behavior and does not implement the core declared purpose: no Feishu API usage, no document generation, no article text extraction/formatting, no image downloading, and no ordered insertion. The code’s actual scope is materially narrower and different from the declared functionality.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
声明的核心功能是把网页文章转换并导入飞书文档,且支持多网站与图片处理。但提供的代码块只是一个简单抓取脚本:它读取输入 URL,构造 r.jina.ai 代理地址,并通过 curl 获取页面内容。代码没有任何飞书 API 调用、文档生成、认证、图片下载、图片重排/插入、站点适配解析等实现。因此其实际行为仅覆盖“抓取文章文本内容”的一小部分前置步骤,与声明的主要用途存在实质性不一致。

Tool Parameter Abuse

High
Category
Tool Misuse
Content
└────────┬────────┘
         ▼
┌─────────────────┐
│  6. 清理临时文件 │  rm -rf /tmp/article-img/
└─────────────────┘
```
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
└────────┬────────┘
         ▼
┌─────────────────┐
│  6. 清理临时文件 │  rm -rf /tmp/article-img/
└─────────────────┘
```
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
echo "  # Step 5: Continue with more sections..."
    echo ""
    echo "  # Step 6: Cleanup"
    echo "  rm -rf /tmp/article-img/"
    exit 0
fi
Confidence
100% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
echo "  # Step 5: Continue with more sections..."
    echo ""
    echo "  # Step 6: Cleanup"
    echo "  rm -rf /tmp/article-img/"
    exit 0
fi
Confidence
100% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
echo "  # Step 5: Continue with more sections..."
    echo ""
    echo "  # Step 6: Cleanup"
    echo "  rm -rf /tmp/article-img/"
    exit 0
fi
Confidence
100% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
echo "  # Step 5: Continue with more sections..."
    echo ""
    echo "  # Step 6: Cleanup"
    echo "  rm -rf /tmp/article-img/"
    exit 0
fi
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
echo "  # Step 5: Continue with more sections..."
    echo ""
    echo "  # Step 6: Cleanup"
    echo "  rm -rf /tmp/article-img/"
    exit 0
fi
Confidence
100% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill explicitly instructs use of shell commands such as bash, curl, grep, and rm, but declares no tool scope or allowed-tools restrictions. That leaves the runtime free to expose broader shell capability than necessary, increasing the chance of command execution beyond the intended workflow if the URL or paths are mishandled elsewhere.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill instructs use of Jina AI Reader and Feishu without warning users that article URLs, article contents, and possibly embedded resources may be sent to third-party services. This can cause unintended disclosure of private or access-controlled content, especially if a user supplies sensitive URLs assuming the process is local.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest describes converting articles from many supported sites into Feishu documents, but this script is explicitly limited to downloading images from a Toutiao article. It neither handles other listed sites nor performs any Feishu document creation, so the implemented behavior does not match the claimed skill functionality for this component.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The script explicitly advertises and implements anti-hotlink bypass by setting a forged Referer header when downloading remote images. In the context of an article-import skill, this exceeds normal content conversion behavior and enables access patterns intended to evade origin protections, which can violate site controls and facilitate unauthorized retrieval of remote assets.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The script fetches untrusted remote content derived from a user-supplied URL, extracts image links, and writes downloaded files to a local directory with no validation of content type, size, source trustworthiness, or storage limits. In a skill that processes arbitrary public webpages, this increases the risk of privacy leakage, unwanted network access, disk consumption, and storage of unexpected or harmful content under the guise of image downloads.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script sends the user-supplied article URL to a third-party proxy service (r.jina.ai) to retrieve content, which exposes the target URL and potentially associated access patterns to an external party without explicit disclosure or consent. In the context of a skill that converts arbitrary web articles, this creates a real privacy and data-handling risk, especially if users provide sensitive, private, or internal links expecting direct retrieval by the tool itself.

Static analysis

No suspicious patterns detected.