Back to skill

Security audit

Feishu Card Sender

Security checks for vulnerabilities and agentic risk

Overview

This skill sends Feishu cards but also runs callback workflows that can create MoviePilot subscriptions and handle credentials in unsafe ways, so it needs careful review before installation.

Install only if you intentionally want a Feishu-to-MoviePilot automation, not just a card sender. Before use, require HTTPS and an explicit MoviePilot base URL, remove the hard-coded default endpoint, require Feishu callback signature verification, bind callbacks to the original recipient and media, restrict poster downloads to trusted HTTPS image hosts, and protect or avoid plaintext token caches and persistent callback state.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/subscribe_callback_handler.py:12
Finding
MoviePilot Credential Transmitted to a Hard-Coded Plaintext Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/subscribe_callback_handler.py`, lines 12 and 130-167 **Vulnerability Type**: Credential exposure through plaintext HTTP and URL query parameters **Risk Level**: Critical ### Vulnerable Code ```python DEFAULT_BASE = "http://home.dobby.lol:1001" ``` ```python cred = load_cred(args.channel, args.user_id) token = cred.get('token') base = cred.get('base_url') or os.getenv('MP_DEFAULT_BASE_URL') or DEFAULT_BASE if not token: raise SystemExit('missing movipilot token') mediaid = f'tmdb:{tmdb_id}' sub = mp_get( f"{base}/api/v1/subscribe/media/" f"{parse.quote(mediaid)}?token={parse.quote(token)}" ) ``` ```python resp = mp_post( f"{base}/api/v1/subscribe/?token={parse.quote(token)}", create_payload ) if not resp.get('success'): media = mp_get( f"{base}/api/v1/media/{parse.quote(mediaid)}" f"?type_name={parse.quote(type_name)}" f"&token={parse.quote(token)}" ) create_payload = { 'name': media.get('title') or payload.get('title') or '', 'year': str(media.get('year') or ''), 'type': type_name, 'tmdbid': int(tmdb_id), 'mediaid': mediaid, 'season': None, } resp = mp_post( f"{base}/api/v1/subscribe/?token={parse.quote(token)}", create_payload ) ``` ### Technical Analysis The handler retrieves a per-user MoviePilot token from an external credential store. If the credential record and environment do not provide a `base_url`, the code defaults to the hard-coded endpoint `http://home.dobby.lol:1001`. The endpoint does not use TLS, so the token and associated API traffic are exposed to passive network observers and active man-in-the-middle attackers. The token is also included in URL query parameters. Query strings are commonly recorded by reverse proxies, web servers, monitoring systems, error reports, and network security products. The hard-coded domain is not a Feishu endpoint ...[truncated 1311 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the hard-coded remote default and require administrators to configure a MoviePilot endpoint explicitly. 2. Reject any endpoint that does not use HTTPS. 3. Validate the destination against an administrator-controlled allowlist. 4. Do not place bearer credentials in query strings. Use an authorization header, such as: ```python headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json", } ``` 5. Ensure redirects cannot move authenticated requests to another host. 6. Redact credentials and authenticated URLs from exceptions, logs, queue records, and monitoring output. 7. Bind each stored token to its approved MoviePilot origin and reject attempts to use it with another origin. 8. Rotate any tokens that may already have been sent through the hard-coded HTTP endpoint. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/feishu_callback_worker.py:14
Finding
Public Callback Listener Accepts Unsigned Requests When Its Encryption Key Is Unset<![CDATA[ ## Vulnerability Details **File Location**: `scripts/feishu_callback_worker.py`, lines 14-22 and 84-106 **Vulnerability Type**: Fail-open callback authentication **Risk Level**: High ### Vulnerable Code ```python HOST = '0.0.0.0' PORT = 18081 ROUTER = '/root/.openclaw/workspace-dev/skills/feishu-card-sender/scripts/card_callback_router.py' USER_ID_FALLBACK = os.getenv('FEISHU_CALLBACK_USER_FALLBACK', '').strip() ACCOUNT_ID = os.getenv('FEISHU_CALLBACK_ACCOUNT_ID', '1').strip() or '1' ENCRYPT_KEY = os.getenv('FEISHU_CALLBACK_ENCRYPT_KEY', '').strip() MAX_SKEW_SECONDS = int(os.getenv('FEISHU_CALLBACK_MAX_SKEW_SECONDS', '300')) ``` ```python def _verify_signature(self, raw_body: str): if not ENCRYPT_KEY: return True, 'no_encrypt_key' ts = self.headers.get('X-Lark-Request-Timestamp') or self.headers.get('X-Lark-Request-Ts') nonce = self.headers.get('X-Lark-Request-Nonce') sig = self.headers.get('X-Lark-Signature') if not ts or not nonce or not sig: return False, 'missing_signature_headers' try: ts_i = self._parse_ts_to_epoch(ts) except Exception as ex: return False, str(ex) if abs(int(time.time()) - ts_i) > MAX_SKEW_SECONDS: return False, 'timestamp_skew' base = f"{ts}{nonce}{ENCRYPT_KEY}{raw_body}".encode('utf-8') calc = hashlib.sha256(base).hexdigest() if calc != sig: return False, 'signature_mismatch' return True, 'ok' ``` The accepted request is subsequently trusted and forwarded: ```python header = req.get('header') or {} event = req.get('event') or {} event_type = header.get('event_type') action_value = ((event.get('action') or {}).get('value') or {}) token = str(event.get('token') or '') user_id = ((event.get('operator') or {}).get('open_id')) or USER_ID_FALLBACK if event_type != 'card.action.trigger' or not token or not isinstance(action_value, dict): self._log('callback_rejected', reason='invalid_payload_shape', event_type=event_type, keys=l ...[truncated 2294 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Refuse to start the callback service unless all required verification credentials are configured. 2. Never return authentication success merely because a verification key is absent. 3. Authenticate every action callback using the documented Feishu signature scheme. 4. Use `hmac.compare_digest` or another constant-time comparison function for signature comparison. 5. Add replay protection by recording recently accepted event IDs, callback tokens, or nonce/timestamp combinations. 6. Bind the listener to a private interface or loopback address when it is expected to operate behind an authenticated reverse proxy. 7. Apply firewall rules and request-rate limits. 8. Treat URL verification separately and validate it according to Feishu's documented protocol without weakening action callback authentication. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/send_feishu_card.py:334
Finding
Unrestricted Poster URL Fetch Enables SSRF and Local File Exfiltration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/send_feishu_card.py`, lines 334 and 382-395 **Vulnerability Type**: Server-side request forgery and unrestricted URI scheme handling **Risk Level**: High ### Vulnerable Code ```python parser.add_argument( "--poster-url", help="download image from URL, upload to Feishu, and fill poster_img_key" ) ``` ```python # Optional: upload poster first and inject poster_img_key if args.poster_url or args.poster_file: if args.poster_url: req = request.Request( args.poster_url, headers={"User-Agent": "Mozilla/5.0 OpenClaw/feishu-card-sender"} ) with request.urlopen(req, timeout=30) as resp: image_bytes = resp.read() filename = Path(args.poster_url.split("?")[0]).name or "poster.jpg" else: p = Path(args.poster_file) if not p.exists(): raise FileNotFoundError(f"poster file not found: {args.poster_file}") image_bytes = p.read_bytes() filename = p.name image_key = upload_image_bytes(token, image_bytes, filename=filename) variables["poster_img_key"] = image_key ``` ### Technical Analysis The value supplied through `--poster-url` is passed directly to `urllib.request.urlopen`. The code does not enforce HTTPS, restrict destination hosts, reject local or private network addresses, validate redirects, or prohibit non-network schemes such as `file:`. The response is read without a maximum size and without validating that the data is actually an image. The resulting bytes are uploaded to Feishu using the tenant token. This creates two related vulnerabilities: - SSRF against loopback, private, link-local, metadata, or otherwise internal services. - Local file disclosure through URI handlers such as `file:///...`, followed by upload of the bytes to Feishu. ### Attack Path 1. An attacker or untrusted caller controls the `--poster-url` argument. 2. The caller supplies an internal URL ...[truncated 759 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only `https` URLs. 2. Maintain an explicit allowlist of trusted image hosts when possible. 3. Resolve the hostname before connecting and reject loopback, private, link-local, multicast, reserved, and unspecified IP ranges. 4. Revalidate the destination after every redirect and prevent redirects to a different or prohibited origin. 5. Disable `file:`, `ftp:`, `data:`, and all other non-HTTPS schemes. 6. Stream the response while enforcing a strict byte limit. 7. Validate both the declared content type and the file signature before upload. 8. Apply connection, read, and total-operation timeouts. 9. If arbitrary user-provided images are required, fetch them through a dedicated, isolated image proxy with no access to internal networks or sensitive local files. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/card_callback_router.py:15
Finding
Feishu Tenant Bearer Token Stored in a Predictable File Without Explicit Access Controls<![CDATA[ ## Vulnerability Details **File Location**: `scripts/card_callback_router.py`, lines 15 and 44-58 **Vulnerability Type**: Insecure plaintext credential storage **Risk Level**: Medium ### Vulnerable Code ```python TOKEN_CACHE = Path( '/root/.openclaw/workspace-dev/skills/' 'feishu-card-sender/tmp/tenant_token_cache.json' ) ``` ```python def get_tenant_token_cached(app_id: str, app_secret: str): now = __import__('time').time() try: if TOKEN_CACHE.exists(): c = json.loads(TOKEN_CACHE.read_text(encoding='utf-8')) if c.get('app_id') == app_id and c.get('token') and float(c.get('exp_at', 0)) - now > 120: return c['token'] except Exception: pass token, ttl = get_tenant_token(app_id, app_secret) if token: TOKEN_CACHE.parent.mkdir(parents=True, exist_ok=True) TOKEN_CACHE.write_text( json.dumps({ 'app_id': app_id, 'token': token, 'exp_at': now + max(300, ttl - 60) }), encoding='utf-8' ) return token ``` ### Technical Analysis A privileged tenant access token is written in plaintext to a predictable path. The code does not explicitly create the directory with mode `0700` or the file with mode `0600`. Effective permissions therefore depend on the process umask and existing directory permissions. The write is also not atomic and does not verify that the target is a regular file owned by the expected account. In an environment where another local principal can modify the parent directory, this can introduce symlink or replacement-file risks. ### Attack Path 1. The router obtains a Feishu tenant access token using the configured application secret. 2. The token is written to `tmp/tenant_token_cache.json`. 3. A local principal with sufficient directory or file access reads the cache. 4. The principal extracts the bearer token and uses it directly with Feishu APIs be ...[truncated 580 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer an in-memory cache or an operating-system credential store. 2. If filesystem caching is necessary, create the containing directory with mode `0700`. 3. Create the cache atomically with mode `0600`, using flags that reject symbolic links. 4. Verify the file is a regular file owned by the expected service account before reading it. 5. Store only the minimum required data and delete expired tokens promptly. 6. Run the service under a dedicated, unprivileged account rather than relying on root-owned workspace paths. 7. Ensure backup, monitoring, and log collection systems do not copy the cache. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/card_callback_router.py:115
Finding
Callback Authorization Is Not Bound to the Original Card Recipient or Stored Media Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/card_callback_router.py`, lines 115-119; `scripts/card_snapshot_store.py`, lines 76-95 **Vulnerability Type**: Insecure direct object reference and missing callback context validation **Risk Level**: Medium ### Vulnerable Code ```python card_key = str(payload.get('card_key') or '') snapshot = None if card_key: snapshot = find_snapshot_by_card_key(card_key) message_id_for_update = ( (snapshot or {}).get('message_id') if isinstance(snapshot, dict) else None ) ``` ```python def find_snapshot_by_card_key(card_key: str): conn = _conn() try: cur = conn.execute( 'SELECT raw_card_json, account_id, title, created_at, ' 'receive_id, media_type, tmdb_id, message_id ' 'FROM card_snapshots WHERE card_key=? ' 'ORDER BY created_at DESC LIMIT 1', (card_key,), ) row = cur.fetchone() if not row: return None return { 'raw_card_json': row[0], 'account_id': row[1] or None, 'title': row[2] or None, 'created_at': row[3], 'receive_id': row[4] or None, 'media_type': row[5] or None, 'tmdb_id': row[6] or None, 'message_id': row[7] or None, } finally: conn.close() ``` ### Technical Analysis The router looks up a stored card using only the callback-provided `card_key`. Although the snapshot contains the original `receive_id`, account, media type, and TMDB ID, the router does not compare those values with the authenticated callback operator or callback payload. Consequently, possession of a valid card key is treated as sufficient authorization. The callback's `user_id` is independently passed to the credential lookup, while its media fields are independently passed to the subscription handler. This permits context mixing between a stored card, a chosen user identity, and att ...[truncated 1053 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind each callback to all relevant stored attributes: - Card key - Original recipient - Feishu account - Permitted action - Media type - TMDB ID 2. Reject the callback if the authenticated operator does not match the intended recipient or an explicitly authorized actor. 3. Do not trust media identifiers returned from the card. Load authoritative action data from server-side state. 4. Use cryptographically random, expiring, single-use callback nonces. 5. Mark a nonce as consumed atomically before executing the external action. 6. Add an expiration timestamp to snapshots and reject callbacks for expired cards. 7. Bind message updates to the snapshot's stored account rather than an independently supplied account ID. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/feishu_callback_worker.py:315
Finding
Sensitive Feishu Callback Tokens and User Identifiers Are Written to Logs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/feishu_callback_worker.py`, lines 315-332 **Vulnerability Type**: Sensitive information exposure through logging **Risk Level**: Low ### Vulnerable Code ```python token = str(event.get('token') or '') user_id = ((event.get('operator') or {}).get('open_id')) or USER_ID_FALLBACK if event_type != 'card.action.trigger' or not token or not isinstance(action_value, dict): self._log( 'callback_rejected', reason='invalid_payload_shape', event_type=event_type, keys=list(req.keys())[:20] ) return self._send(200, {'toast': {'type': 'error', 'content': '回调结构不符合预期'}}) if not user_id: self._log('callback_rejected', reason='missing_user_id', token=token) return self._send(200, {'toast': {'type': 'error', 'content': '缺少用户信息,无法处理'}}) payload = json.dumps(action_value, ensure_ascii=False) msg_id = f'card-action-{token}' if token else '' self._log( 'callback_accepted', token=token, user_id=user_id, account_id=ACCOUNT_ID ) ``` ### Technical Analysis The worker writes the complete callback token and Feishu user identifier to standard output. Service output is commonly retained by process supervisors, container systems, centralized log collectors, or monitoring tools. Callback tokens should be treated as sensitive correlation or authorization material. Logging the complete value unnecessarily broadens the number of systems and personnel that can access it. ### Attack Path 1. A callback is accepted or rejected after token extraction. 2. The full token and, for accepted requests, the user's open ID are written to standard output. 3. A log collector or service supervisor persists the event. 4. A principal with log access retrieves the token and user identifier. 5. The principal attempts callback replay or uses the data to support another callback attack. ### Impact Assessment The direct impact depends on Feishu's token lifetime and replay contro ...[truncated 218 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not log callback tokens in plaintext. 2. Use a short, one-way hash as a correlation identifier if callback tracing is necessary. 3. Minimize or pseudonymize user identifiers in operational logs. 4. Define structured log redaction rules for token, secret, authorization, and user ID fields. 5. Set short retention periods and strict access controls for callback logs. 6. Review existing retained logs and delete or restrict any records containing callback tokens. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (61)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill claims to send Feishu card messages, but the documented callback flow performs MoviePilot subscription queries/creation, reads local credentials for external services, and maintains local idempotency state. Hidden cross-system write capabilities materially elevate risk because a user invoking a messaging skill may unknowingly authorize writes to another external system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill claims to send Feishu card messages, but the documented callback flow performs MoviePilot subscription queries/creation, reads local credentials for external services, and maintains local idempotency state. Hidden cross-system write capabilities materially elevate risk because a user invoking a messaging skill may unknowingly authorize writes to another external system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill claims to send Feishu card messages, but the documented callback flow performs MoviePilot subscription queries/creation, reads local credentials for external services, and maintains local idempotency state. Hidden cross-system write capabilities materially elevate risk because a user invoking a messaging skill may unknowingly authorize writes to another external system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill claims to send Feishu card messages, but the documented callback flow performs MoviePilot subscription queries/creation, reads local credentials for external services, and maintains local idempotency state. Hidden cross-system write capabilities materially elevate risk because a user invoking a messaging skill may unknowingly authorize writes to another external system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill claims to send Feishu card messages, but the documented callback flow performs MoviePilot subscription queries/creation, reads local credentials for external services, and maintains local idempotency state. Hidden cross-system write capabilities materially elevate risk because a user invoking a messaging skill may unknowingly authorize writes to another external system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill claims to send Feishu card messages, but the documented callback flow performs MoviePilot subscription queries/creation, reads local credentials for external services, and maintains local idempotency state. Hidden cross-system write capabilities materially elevate risk because a user invoking a messaging skill may unknowingly authorize writes to another external system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill claims to send Feishu card messages, but the documented callback flow performs MoviePilot subscription queries/creation, reads local credentials for external services, and maintains local idempotency state. Hidden cross-system write capabilities materially elevate risk because a user invoking a messaging skill may unknowingly authorize writes to another external system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill claims to send Feishu card messages, but the documented callback flow performs MoviePilot subscription queries/creation, reads local credentials for external services, and maintains local idempotency state. Hidden cross-system write capabilities materially elevate risk because a user invoking a messaging skill may unknowingly authorize writes to another external system.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This document describes callback handling that can create MoviePilot subscriptions, which is materially broader than the declared purpose of a skill that should only send Feishu interactive cards via OpenAPI. That scope expansion introduces an undeclared write path into an external system, increasing the chance of unauthorized actions through crafted callback payloads or operator misuse.

Context-Inappropriate Capability

High
Confidence
95% confidence
Finding
The documented behavior includes querying and writing to an external MoviePilot subscription API, which gives this skill side-effecting capabilities unrelated to Feishu card delivery. In the context of a messaging skill, such hidden integration is especially risky because interactive card callbacks can become a bridge for unauthorized state changes in another system if not strongly bound to authenticated users and approved actions.

Context-Inappropriate Capability

High
Confidence
95% confidence
Finding
The script executes a separate local handler with user-controlled payload data, creating an additional execution boundary and broadening the skill from simple card sending into local orchestration of other code. In a skill context, this is dangerous because any weakness or unexpected behavior in the downstream handler inherits the privileges of this process and may process untrusted callback data.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The skill metadata says it only sends Feishu cards via OpenAPI and does not use the message channel, but this file exposes a network listener on 0.0.0.0:18081, accepts Feishu callbacks, decrypts/verifies requests, extracts user identity, and routes actions into another local script. That is a materially broader capability than declared, increasing attack surface and enabling external event-driven behavior that users and operators would not reasonably expect from a send-only skill.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The file performs MoviePilot subscription creation and lookup based on callback input, which is outside the declared scope of a Feishu card sender skill and introduces privileged side effects on an external system. This scope mismatch is dangerous because users or reviewers may authorize a messaging skill while the code actually drives subscription-management actions using stored credentials and network calls.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill documentation exposes capabilities that imply environment access, local file read/write, shell execution, and network access, but it does not declare any tool scope restrictions such as permissions or allowed-tools. This creates an over-privileged skill surface where an agent may invoke broader capabilities than a user would reasonably expect from a 'send Feishu card' utility.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The documentation instructs sending card content and recipient identifiers such as open_id/chat_id to Feishu, but it does not clearly warn users that their content and identifiers will be transmitted to an external service. This omission can lead to unintended disclosure of sensitive data, especially when the card payload includes structured notifications or personal information.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The documentation describes the skill as only sending Feishu cards, but later declares callback routing and automatic 'subscribe now' handling that writes into MoviePilot. This is a scope deception issue: hidden side effects on an external system can surprise users and bypass informed approval of state-changing operations.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The callback flow automatically performs subscription writes to MoviePilot after a card action, but the documentation does not provide a clear user-facing warning that this modifies external system state. Automatic write actions tied to callbacks can cause unintended subscriptions or business-side effects without sufficiently informed consent.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This JSON manifest contains user-facing validation messages entirely in Chinese, such as "title 不能为空" and the poster guidance text, with no indication that the skill is China-specific or that users can opt into the locale. The policy explicitly calls out language or locale policy violations when a skill forces a specific language without user opt-in.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This JSON file contains multiple user-facing validation/error messages in Chinese, such as 'title 不能为空' and the longer poster image guidance text. Because the file provides only Chinese output and does not offer locale selection or document a justified region-specific constraint, it creates a language/locale policy issue under the natural-language policy category.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
This JSON template contains user-facing labels such as '剧情简介' and other Chinese text directly in the rendered content. Because the file forces a specific language in multiple UI strings and provides no user opt-in or locale selection, it violates the language/locale policy for natural-language content.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The header title is fixed as '🎬 《${title}》电影介绍', which presents the card in Chinese regardless of user language preference. This is a natural-language policy issue because the template enforces one language rather than offering a configurable or justified locale.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This JSON template contains multiple user-facing strings in Chinese, such as section headings and button text, and does not indicate any user opt-in or locale selection. That creates a language-policy issue because the skill appears to force a specific language for all users rather than offering a choice or documenting a region-specific constraint.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The worker builds and executes an external Python command via subprocess.run to process queued jobs, but there is no confirmation prompt, user-visible logging, or explanatory comment/docstring disclosing that external command execution will occur. For a code file, subprocess or shell execution should have some visible disclosure unless clearly documented as part of the skill's stated purpose in accompanying markdown, which is not evident from this file alone.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
'--account-id', str(data.get('account_id', '1')),
        '--payload', json.dumps(data['payload'], ensure_ascii=False),
    ]
    return subprocess.run(cmd, capture_output=True, text=True, timeout=180)


def recover_orphan_processing_files():
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The cleanup_history function silently deletes files beyond retention limits using unlink, and the finally block also deletes claimed job files after processing. The file contains no user-facing warning, logging, or explanatory comment describing these deletions, which are safety-relevant file operations under the code-file criteria.

Static analysis

No suspicious patterns detected.