Back to skill

Security audit

fecify-site-manager-v1

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its Fecify store-management purpose, but it needs review because it stores API tokens and can make broad live store changes with weak safeguards.

Install only if you trust the publisher and need this Fecify workflow. Use a dedicated least-privilege token, bind only HTTPS sites, prefer a test store first, inspect CSV image URLs before import, do not use --skip-validation in production, and rotate or delete stored tokens when finished.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/csv-import/import-shopify-csv.js:282
Finding

Server-Side Request Forgery Through CSV-Controlled Image URLs

Content
View full analysis
{ const transport = url.startsWith('https:') ? https : http; transport.get(url, { timeout: 30000 }, (res) => { if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { return downloadImage(res.headers.location).then(resolve).catch(reject); } if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode}`)); const bufs = []; res.on('data', d => bufs.push(d)); res.on('end', () => resolve(Buffer.concat(bufs))); }).on('error', reject).on('timeout', () => reject(new Error('Timeout'))); }); } async function uploadImages(images, productTitle, imgConcurrency = 5, imgRetries = 3) { const slugify = s => s.replace(/[^a-zA-Z0-9\u4e00-\u9fff-]/g, '_').substring(0, 30); const results = await concurrentMap(images, imgConcurrency, async (img) => { let lastErr; for (let attempt = 0; attempt <= imgRetries; attempt++) { try { const buf = await downloadImage(img.src); const ext = getExt(img.src); const r = await api.post('/api/skill/base-image/upload', { image_base64encode: buf.toString('base64'), image_name: `${slugify(productTitle)}_${img.position}.${ext}`, group_type: 'product' }); ``` ### Technical Analysis The importer obtains `img.src` from the CSV `Image Src` column and passes it directly to `http.get` or `https.get`. It performs no validation of: - The URL scheme - The destination hostname - Resolved IP addresses - Loopback, link-local, private, or reserved address ranges - Redirect destinations - ...[truncated 1915 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/base/api-client.js:55
Finding

Access Tokens Can Be Transmitted over Unencrypted HTTP

Content
View full analysis
{ ``` The same behavior occurs during configuration initialization: ```js const options = { hostname: baseUrl.hostname, port: baseUrl.port || (baseUrl.protocol === 'https:' ? 443 : 80), path: apiPath, method: 'GET', headers: { 'skill-access-token': token, 'Content-Type': 'application/json' }, timeout: 30000 }; const transport = baseUrl.protocol === 'https:' ? https : http; ``` ### Technical Analysis The configured site URL is accepted without requiring the `https:` protocol. When the URL uses `http:`, the code deliberately selects Node.js's unencrypted HTTP transport but still places the reusable access token in the `skill-access-token` header. HTTP provides no transport confidentiality or server authentication. Any party able to observe or modify the connection can read the token or impersonate the configured server. The protocol is also not explicitly restricted to supported values. Any protocol other than `https:` is routed through the HTTP module, resulting in unsafe and inconsistent behavior. ### Attack Path 1. ...[truncated 948 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/base/site-config.js:62
Finding

Persistent Access Tokens Are Stored in Plaintext with Default Filesystem Permissions

Content
View full analysis
/config.json`. 3. A local user, co-located process, backup reader, or support process with filesystem access reads the file. 4. The token is extracted from the JSON document. 5. The attacker uses the token to invoke the corresponding Fecify API. ### Impact Assessment Successful exploitation discloses a persistent bearer-style credential. The attacker receives the API privileges assigned to that token and can continue using it until it is revoked or rotated. The scope includes the configured site and any product, image, or other management APIs authorized for the token. This issue does not independently provide operating-system privilege escalation, but it can cause remote application-level account compromise. ]]>
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/base/site-config.js:27
Finding

Path Traversal Through the FECIFY_DOMAIN Environment Variable

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/csv-import/import-shopify-csv.js:287
Finding

Unbounded Buffering of Remote Image and API Responses

Content
View full analysis
{ const transport = url.startsWith('https:') ? https : http; transport.get(url, { timeout: 30000 }, (res) => { if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { return downloadImage(res.headers.location).then(resolve).catch(reject); } if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode}`)); const bufs = []; res.on('data', d => bufs.push(d)); res.on('end', () => resolve(Buffer.concat(bufs))); }).on('error', reject).on('timeout', () => reject(new Error('Timeout'))); }); } ``` The API client similarly buffers complete responses: ```js const req = transport.request(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { const json = JSON.parse(data); ``` ### Technical Analysis Both request implementations accumulate complete response bodies in memory without enforcing a maximum byte count. The image importer allows concurrent downloads and configurable retry counts, multiplying memory and bandwidth use. The timeout does not impose a response-size limit. A server can return a very large body quickly enough to remain within the timeout, or continuously provide data in a manner that consumes resources before termination. Declared `Content-Length` is not checked, and chunked responses have no limit at all. After download, `Buffer.concat` creates another allocation, and Base64 encoding further expands the data by approximately one third. ### Attack Path 1. An attacker supplies a CSV with image URLs under their control. 2. The imp ...[truncated 974 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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 (43)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

代码行为与声明的核心用途不一致。声明描述的是一个多站点 Fecify 管理技能,重点包括站点绑定、API Token、配置持久化,以及商品/订单/CSV 导入等业务能力;而实际代码只是一个 CSV 检测脚本,读取本地文件后识别 Shopify 商品 CSV 的表头特征、排除非商品表、分析变体结构并校验数据质量。它既不连接 Fecify 站点,也不处理会话、令牌或持久化,更不执行商品/订单管理或实际导入。虽然声明中提到“CSV 批量导入”,该代码可被视为导入前的辅助检测组件,但其对象是 Shopify CSV 且功能范围远窄于声明,因此属于明显的描述-行为不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

该代码块的核心功能非常明确:执行 Shopify 商品 CSV 到 Fecify 的批量导入,包括 CSV 解析、图片抓取与上传、商品 JSON 构建、标签生成、并发导入、失败落盘和结果汇总。它确实属于声明中“支持商品、CSV 批量导入”等范围的一部分,但声明的主要卖点——多站点管理、会话与站点绑定、URL/API Token 配置持久化、以及订单操作——在这段代码中都没有体现。按评估标准,这不是轻微实现细节缺失,而是声明的主要能力与代码实际行为存在明显范围差异,因此应判定为描述与行为不匹配。

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

md
node scripts/csv-import/import-shopify-csv.js <CSV> [--max=N] [--skip=N] [--dry-run] [--use-network-images] [--gen-tags=none|auto|force] [--tag-count=N] [--img-

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
91% confidence
Finding

The documented import command exposes a --skip-validation flag even though the skill earlier states detection/validation cannot be skipped. In this context, bypassing validation on bulk CSV imports can allow malformed or malicious data, bad image references, or integrity-breaking records to be ingested into a live commerce system, undermining the safety guard the workflow claims to enforce.

Content

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

node scripts/csv-import/detect-shopify-csv.js <CSV文件>

Step 2 — 执行(根据用户选择组装参数)

node scripts/csv-import/import-shopify-csv.js [--max=N] [--skip=N] [--dry-run] [--use-network-images] [--gen-tags=none|auto|force] [--tag-count=N] [--img-concurrency=N] [--img-retries=N] [--import-concurrency=N] [--skip-validation]

text

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The documented --skip-validation flag disables execution-layer validation for a workflow that creates products and uploads images based on user-supplied CSV content and network resources. Even though it is labeled 'debug only, not recommended,' exposing this option in agent-facing documentation makes it easier to bypass safeguards and submit malformed or dangerous data to downstream APIs.

Content

Scanner excerpt · docs/csv-import/shopify-csv-product-import.md (reported line 73)May include surrounding context.

node scripts/csv-import/import-shopify-csv.js --img-concurrency=10 --import-concurrency=5

跳过执行层校验(仅调试用,不推荐)

node scripts/csv-import/import-shopify-csv.js --skip-validation

text

(必须带 `FECIFY_SESSION` env)

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 · scripts/base/api-client.js (reported line 48)May include surrounding context.

js
return new Promise((resolve, reject) => {
        const config = getCurrentConfig();
        if (!config || !config.url || !config.token) {
            return reject(new Error('未配置站点信息,请先提交 URL 和 Access Token。'));
        }

        // 校验 /api/apps/{addon}/... 路径:插件必须已安装

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% 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).

Content

Scanner excerpt · scripts/csv-import/import-shopify-csv.js (reported line 25)May include surrounding context.

js
*   --img-concurrency=N      图片下载上传并发数(默认 5)
 *   --img-retries=N          图片下载失败最大重试次数(默认 3)
 *   --import-concurrency=N   商品导入并发数(默认 2)
 *   --skip-validation        跳过执行层数据校验(不推荐)
 *   FECIFY_SESSION=xxx       指定会话(同其他 api-call 规则)
 */

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

The script exposes a runtime flag that disables execution-layer validation before importing products. In this context, the importer already performs network image fetching, file writes, and product creation across multiple managed stores, so bypassing validation makes it easier for malformed or unintended data to be pushed into production, amplifying operational and integrity risk.

Content

Scanner excerpt · scripts/csv-import/import-shopify-csv.js (reported line 529)May include surrounding context.

js
const max = maxArg ? parseInt(maxArg.split('=')[1]) : Infinity;
  const skipArg = args.find(a => a.startsWith('--skip='));
  const skip = skipArg ? parseInt(skipArg.split('=')[1]) : 0;
  const skipValidation = args.includes('--skip-validation');
  const dryRun = args.includes('--dry-run');
  const useNetworkImages = args.includes('--use-network-images');

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
93% confidence
Finding

The script accepts arbitrary HTTP methods and paths from command-line arguments and forwards them directly to the underlying authenticated API client, including destructive methods like DELETE. In this skill context, where a session is bound to a persisted site URL and API token, this becomes a powerful generic proxy that can modify or delete remote store data if an upstream agent, prompt, or user input is abused.

Content

Scanner excerpt · scripts/proxy/api-call.js (reported line 11)May include surrounding context.

js
*   node scripts/proxy/api-call.js GET /api/products/list '{"page":1}'
 *   node scripts/proxy/api-call.js POST /api/products/create '{"title":"test"}'
 *   node scripts/proxy/api-call.js PUT /api/products/123 '{"title":"updated"}'
 *   node scripts/proxy/api-call.js DELETE /api/products/123
 */

const api = require('../base/api-client');

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill explicitly states that site URL and API token are persisted under data/fecify-shared/ and survive restarts, but it gives no user-facing warning about credential storage, retention, or access controls. Storing long-lived API credentials without transparent disclosure increases the risk of accidental exposure, unauthorized reuse across sessions, and insecure handling by operators.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The instructions tell the agent to ask for 站点URL and AccessToken, then pass them directly to a save script that persists configuration and fetches initialization data, yet no warning is provided about transmitting or storing sensitive credentials. This can cause users to disclose secrets without informed consent and may place tokens into command history, logs, process listings, or persistent files.

Content

No source excerpt is available for this finding.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
88% confidence
Finding

Even if --skip-validation is optional rather than default-enabled, documenting it in the normal execution path creates an unsafe operational default because users or downstream agents may invoke it to save time. In a data-import skill for commerce operations, that weakens integrity protections and increases the chance of corrupt, unreviewed, or attacker-crafted content entering the system.

Content

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

node scripts/csv-import/detect-shopify-csv.js <CSV文件>

Step 2 — 执行(根据用户选择组装参数)

node scripts/csv-import/import-shopify-csv.js [--max=N] [--skip=N] [--dry-run] [--use-network-images] [--gen-tags=none|auto|force] [--tag-count=N] [--img-concurrency=N] [--img-retries=N] [--import-concurrency=N] [--skip-validation]

text

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The entire skill documentation is written in Chinese and does not indicate that other languages are supported or that the language choice is optional. Under the stated policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale constraint is documented and justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation explicitly requires a session credential and states that failed imports are archived with full API request bodies and raw responses, but it does not warn about the sensitivity of credentials, product data, image URLs, or archived failure artifacts. This creates a realistic risk of inadvertent exposure of secrets and business data through logs, temp files, or operator handling, especially in shared environments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The guidance explicitly directs implementers to add image downloading/uploading and API-based imports, which can transmit local or third-party data to remote services. Because the document does not require any user notice, confirmation step, or clear indication that network actions and remote mutations will occur, downstream skills built from this guidance may perform externally visible actions without informed consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documented main flow includes POST-based product creation as a standard execution path, but it does not require an approval gate before modifying remote store data. In the context of a site-management skill with persistent site URL and API token, this omission is more dangerous because an agent following the guidance could make irreversible changes to a bound production store.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The documentation provides a live product-creation POST workflow, including a complete request example, but does not warn that invoking it will create persistent store data. In a skill that manages real e-commerce sites with persisted site bindings and API tokens, this increases the risk of accidental unauthorized or unintended writes to production catalogs by users or downstream agents.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This documentation describes a destructive product update flow where callers are instructed to fetch full product data, modify fields, and resubmit complete images/variants/options arrays, but it does not clearly warn that omitted sub-entities may be deleted or overwritten. In a skill that manages persistent e-commerce sites bound to real shop credentials, this increases the chance of accidental inventory, media, or variant loss through normal operator use rather than an external exploit.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The module description states that it automatically reads the bound URL and token and all business scripts use it to access the API, and the implementation sends the token in the skill-access-token header. This is a safety-relevant network operation involving credentials, but the file contains no confirmation prompt or user-facing disclosure about that transmission.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code persists a sensitive access token via config.saveConfig(domain, url, token). Although the header comment describes usage, it does not warn that the token will be stored locally, and there is no runtime disclosure or confirmation before saving the credential.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This script sends the provided access token to an arbitrary user-supplied URL and permits plain HTTP as well as HTTPS. In the context of a site-management skill that binds persistent credentials for multiple stores, this creates a real risk of credential exposure through misconfiguration, phishing, SSRF-like internal targeting, or network interception when HTTP is used.

Content

No source excerpt is available for this finding.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · docs/csv-import/shopify-csv-product-import.md (reported line 73)May include surrounding context.

md
*   --img-concurrency=N      图片下载上传并发数(默认 5)
 *   --img-retries=N          图片下载失败最大重试次数(默认 3)
 *   --import-concurrency=N   商品导入并发数(默认 2)
 *   --skip-validation        跳过执行层数据校验(不推荐)
 *   FECIFY_SESSION=xxx       指定会话(同其他 api-call 规则)
 */

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/csv-import/import-shopify-csv.js (reported line 25)May include surrounding context.

js
*   --img-concurrency=N      图片下载上传并发数(默认 5)
 *   --img-retries=N          图片下载失败最大重试次数(默认 3)
 *   --import-concurrency=N   商品导入并发数(默认 2)
 *   --skip-validation        跳过执行层数据校验(不推荐)
 *   FECIFY_SESSION=xxx       指定会话(同其他 api-call 规则)
 */

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/csv-import/import-shopify-csv.js (reported line 529)May include surrounding context.

js
*   --img-concurrency=N      图片下载上传并发数(默认 5)
 *   --img-retries=N          图片下载失败最大重试次数(默认 3)
 *   --import-concurrency=N   商品导入并发数(默认 2)
 *   --skip-validation        跳过执行层数据校验(不推荐)
 *   FECIFY_SESSION=xxx       指定会话(同其他 api-call 规则)
 */