Back to skill

Security audit

Bona Movie Production

Security checks for vulnerabilities and agentic risk

Overview

This is a real Bona media-generation client, but it needs Review because command options can redirect API credentials and generation inputs to arbitrary endpoints.

Review before installing. Use only the default Bona endpoints or endpoints you personally control, avoid passing --base-url or --login-url from untrusted instructions, and do not submit secrets, internal URLs, private media, or regulated data as prompts or references unless you are authorized. Treat the built-in --wait polling as unreliable until the status handling is fixed.

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/bona_movie_production.py:189
Finding

Credential and bearer-token disclosure through unrestricted endpoint overrides

Content
View full analysis
str: if not self.api_key: raise RuntimeError("api_key is required for login") response = requests.post( self.login_url, headers={"Content-Type": "application/json"}, json={"accessKey": self.api_key}, timeout=self.timeout, ) payload = self._parse_response(response) data = payload.get("data") if isinstance(payload, dict) else None access_token = data.get("access_token") if isinstance(data, dict) else None if not access_token: raise RuntimeError( f"login response missing access_token: {json.dumps(payload, ensure_ascii=False, indent=2)}") return str(access_token) def _get_access_token(self) -> str: if not self._access_token: self._access_token = self._login() return self._access_token @property def headers(self) -> Dict[str, str]: return { "Content-Type": "application/json", "Authorization": f"Bearer {self._get_access_token()}", "Clientid": "e5cd7e4891bf95d1d19206ce24a7b32e", } def create_image_task(self, payload: Dict[str, Any]) -> Dict[str, Any]: response = requests.post(f"{self.base_url}/image", headers=self.headers, json=payload, timeout=self.timeout) return self._parse_response(response) def create_video_task(self, payload: Dict[str, Any]) -> Dict[str, Any]: response = requests.post(f"{self.base_url}/video", headers=self.headers, json=payload, timeout=self.timeout) return self._parse_response(response) ``` ```python def add_client_args(parser: argparse.ArgumentParser) -> None: parser.add_argument("--base-url", default=DEFAULT_BASE_URL) parser.add_argument("--login-url", default=DEFAULT_LOGIN_URL) parser.add_argument("--api-key", de ...[truncated 2348 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/bona_movie_production.py:17
Finding

Task polling uses terminal-status values that contradict the declared API contract

Content
View full analysis
Dict[str, Any]: deadline = time.time() + max_wait last: Optional[Dict[str, Any]] = None while time.time() <= deadline: last = self.query_task(task_id=task_id, thread_id=thread_id, model_name=model_name) status = extract_status(last) if status in SUCCESS_STATUSES or status in FAILED_STATUSES: return last time.sleep(poll_interval) raise TimeoutError(f"task {task_id} did not finish within {max_wait} seconds") ``` The Skill documentation defines a different numeric state machine: ```text status = 1: continue querying status = 9: return the result link status = -1: return the failure reason ``` ### Technical Analysis The implementation classifies numeric status `1` as successful, while the declared API contract classifies it as processing. It also omits documented success status `9` and failure status `-1` from its terminal-status sets. The polling loop therefore returns immediately when a task is still processing. Conversely, it continues polling after documented successful or failed terminal responses until `max_wait` expires. This is an insecure state-validation practice because downstream automation may trust a processing response as a completed generation. It also prevents reliable distinction between s ...[truncated 1370 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (11)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill declares environment and network capabilities but does not document any explicit tool scope or permission boundaries. That makes it easier for an agent or reviewer to miss that prompts, media URLs, and API-key-backed requests may be sent externally, increasing the chance of over-broad access and unsafe execution in hosts that rely on manifest scoping.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill instructs users to submit prompts and external media references for image/video generation but does not warn that this data is transmitted to third-party generation services. Users may unknowingly send sensitive prompts, private URLs, or proprietary media off-platform, creating confidentiality and privacy risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The instructions explicitly state '必须用英文' for prompt writing, and similar mandatory wording is repeated in multiple sections. Because the file does not offer a language choice, opt-in, or a clearly documented justification for enforcing English, this is a natural-language language-policy violation under SQP-3.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

Beyond the first image-generation section, the markdown continues to require English-only prompts for additional image editing and reference workflows. Repeated mandatory language instructions reinforce a policy issue because they impose a locale/language constraint globally rather than as an informed recommendation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Sections covering view conversion, grid generation, and other creative tasks continue the same 'must use English' requirement. This is a cross-cutting natural-language policy problem because the skill forces a specific language across workflows without giving the user a choice or documenting a narrow compliance need.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/bona_movie_production.py (reported line 189)May include surrounding context.

python
def _login(self) -> str:
        if not self.api_key:
            raise RuntimeError("api_key is required for login")
        response = requests.post(
            self.login_url,
            headers={"Content-Type": "application/json"},
            json={"accessKey": self.api_key},

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/bona_movie_production.py (reported line 217)May include surrounding context.

python
}

    def create_image_task(self, payload: Dict[str, Any]) -> Dict[str, Any]:
        response = requests.post(f"{self.base_url}/image", headers=self.headers, json=payload, timeout=self.timeout)
        return self._parse_response(response)

    def create_video_task(self, payload: Dict[str, Any]) -> Dict[str, Any]:

Tainted flow: 'payload' from requests.post (line 195, network input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/bona_movie_production.py (reported line 217)May include surrounding context.

python
}

    def create_image_task(self, payload: Dict[str, Any]) -> Dict[str, Any]:
        response = requests.post(f"{self.base_url}/image", headers=self.headers, json=payload, timeout=self.timeout)
        return self._parse_response(response)

    def create_video_task(self, payload: Dict[str, Any]) -> Dict[str, Any]:

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/bona_movie_production.py (reported line 221)May include surrounding context.

python
return self._parse_response(response)

    def create_video_task(self, payload: Dict[str, Any]) -> Dict[str, Any]:
        response = requests.post(f"{self.base_url}/video", headers=self.headers, json=payload, timeout=self.timeout)
        return self._parse_response(response)

    def query_task(self, task_id: str, thread_id: Optional[str] = None, model_name: Optional[str] = None) -> Dict[

Tainted flow: 'payload' from requests.post (line 195, network input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/bona_movie_production.py (reported line 221)May include surrounding context.

python
return self._parse_response(response)

    def create_video_task(self, payload: Dict[str, Any]) -> Dict[str, Any]:
        response = requests.post(f"{self.base_url}/video", headers=self.headers, json=payload, timeout=self.timeout)
        return self._parse_response(response)

    def query_task(self, task_id: str, thread_id: Optional[str] = None, model_name: Optional[str] = None) -> Dict[

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This Python file contains user-facing help strings and an error message in Chinese only, such as the parser help text and 错误: output. That imposes a specific language/locale on all users without any opt-in or documented locale constraint, which matches the language policy violation criteria.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.