Back to skill

Security audit

九马免费对口型数字人

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to generate Jiuma digital-human videos as described, but its login flow handles API credentials in ways that can expose or persist them insecurely.

Review before installing. Use this only if you are comfortable sending prompts, audio/avatar URLs, and generated-task data to Jiuma. Avoid sensitive or regulated content. If you complete the login flow, treat the local .jiuma files and terminal logs as sensitive, restrict their permissions, and rotate the Jiuma key if it may already have been printed or captured.

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

T09 · Insecure Skill Coding Practices

Error
Location
utils.py:19
Finding

API Secret Disclosed Through Standard Output

Content
View full analysis

Vulnerability Details

File Location: utils.py:19-34
Vulnerability Type: Sensitive credential exposure through logging
Risk Level: High

Vulnerable Code

python
def jiuma_request(url, data={}):
    try:
        response = requests.post(url, data, timeout=30)
        if response.status_code != 200:
            output_result({
                "status": "error",
                "message": f"请求远程API失败,状态码: {response.status_code}",
                "data": {}
            })
            return None
        json_result = response.json()
        if json_result.get("code") != 200:
            output_result({
                "status": "error",
                "message": f"API返回错误: {json_result.get('message', '未知错误')}",
                "data": json_result
            })
            return
        print(json_result)
        return json_result.get("data")

The affected helper is used by the login-status workflow:

python
def check_login_status(access_token):
    data = jiuma_request(f"{CHECK_API}?rand_string={access_token}")
    if not data:
        return
    save_jiuma_api_key(data["secret_key"])

Technical Analysis

jiuma_request() prints the complete successful API response before returning its data field. The login-status endpoint returns a secret_key, which check_login_status() subsequently saves as the user's API key. Therefore, the complete response containing that credential can be written to standard output.

Standard output is not a protected secret-storage channel. In an agent or automation environment, it may be captured in tool transcripts, conversation history, CI logs, terminal recordings, monitoring systems, or centralized log storage. This expands access to the API key beyond the process that legitimately needs it.

Attack Path

  1. A user completes the QR-code login flow.
  2. The user invokes login.py --check with a valid login t ...[truncated 945 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove print(json_result) from the shared request helper.
  • Return parsed results internally without logging complete response objects.
  • Use an allowlist when operational output is necessary, such as status code and a non-sensitive message.
  • Implement recursive redaction for fields including secret_key, api_key, access_token, rand_string, authorization, and similar credential names.
  • Ensure error handling does not include complete server response bodies where credentials might also be present.
  • Review and purge retained agent, terminal, and CI logs that may already contain exposed keys.
  • Rotate API keys that may have passed through the vulnerable login flow.

T09 · Insecure Skill Coding Practices

Warning
Location
utils.py:6
Finding

API Key and Login Token Stored Without Enforced Restrictive Permissions

Content
View full analysis

Vulnerability Details

File Location: utils.py:6-9, 67-74
Vulnerability Type: Insecure plaintext credential storage
Risk Level: Medium

Vulnerable Code

python
JIUMA_API_KEY_SAVE_DIR = f"{os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))}/.jiuma"
os.makedirs(JIUMA_API_KEY_SAVE_DIR, exist_ok=True)
JIUMA_API_KEY_SAVE_PATH = f"{JIUMA_API_KEY_SAVE_DIR}/jiuma_api_key"
JIUMA_RAND_STR_SAVE_PATH = f"{JIUMA_API_KEY_SAVE_DIR}/jiuma_rand_str"
python
def save_jiuma_api_key(api_key):
    with open(JIUMA_API_KEY_SAVE_PATH, "w") as f:
        f.write(api_key)


def save_jiuma_rand_str(rand_str):
    with open(JIUMA_RAND_STR_SAVE_PATH, "w") as f:
        f.write(rand_str)

Technical Analysis

The Skill stores the API key and login token as plaintext at predictable filesystem paths. Neither the directory nor the files are created with explicit restrictive permissions.

os.makedirs(..., exist_ok=True) applies default permissions subject to the process umask. Similarly, open(path, "w") creates files using default creation permissions subject to the umask. In common configurations, this can result in a directory readable or traversable by other users and credential files with mode 0644.

This behavior contradicts the documentation's claim that only the current user can read the API key. The implementation also does not reject symbolic links or verify ownership before opening the predictable files, creating additional risk if an attacker can modify the parent directory or pre-create those paths.

Attack Path

  1. The Skill creates the predictable .jiuma directory and credential files under the calculated parent path.
  2. The process runs with a permissive umask, resulting in group-readable or world-readable files.
  3. Another local user or process locates .jiuma/jiuma_api_key or .jiuma/jiuma_rand_str.
  4. The attacker reads the plaintext API key or acti ...[truncated 936 chars]
Remediation
View remediation

Remediation Suggestions

  • Create the credential directory with mode 0700 and verify its owner before use.
  • Create credential files atomically with mode 0600, for example through os.open() using O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW where supported.
  • Apply os.chmod(path, 0o600) to existing credential files and os.chmod(directory, 0o700) to an existing directory after validating ownership.
  • Reject symbolic links and non-regular files before reading or writing credentials.
  • Store credentials in a platform keyring or operating-system secret manager instead of plaintext whenever possible.
  • Avoid placing shared credentials in a project-relative parent directory; use a user-specific configuration directory with documented ownership requirements.
  • Use atomic replacement through a protected temporary file to avoid partial writes and race conditions.
  • Update the documentation so its permission guarantees accurately reflect the implementation.

T09 · Insecure Skill Coding Practices

Warning
Location
login.py:47
Finding

Login Token Exposed in Process Arguments and URL Query String

Content
View full analysis

Vulnerability Details

File Location: login.py:47-48, 62-64
Vulnerability Type: Sensitive token exposure through command-line arguments and URL logging
Risk Level: Medium

Vulnerable Code

python
def check_login_status(access_token):
    data = jiuma_request(f"{CHECK_API}?rand_string={access_token}")
    if not data:
        return
    save_jiuma_api_key(data["secret_key"])
    output_result({
        "status": "success",
        "message": "登录成功,已保存api_key",
        "data": {}
    })
python
parser.add_argument('--login', action='store_true', help="获取登录渠道和access_token")
parser.add_argument('--check', action='store_true', help="检测是否完整注册/登录,并获取API_KEY")
parser.add_argument('--access_token', type=str, default='', help="获取API_KEY的通行证")

The documented invocation explicitly places the token on the command line:

bash
python3 login.py --check --access_token "<your_access_token>"

Technical Analysis

The login token is accepted as a command-line argument. Depending on the operating system and execution environment, process arguments may be visible to other users through process inspection, retained in shell history, recorded by automation tooling, or stored in agent execution transcripts.

The token is then interpolated into the query string of the login-status URL. Query strings are routinely captured in reverse-proxy logs, application access logs, observability systems, exception reports, and network debugging tools. Although HTTPS protects the request in transit, it does not prevent the complete URL from being logged at the client, proxy, or server endpoint.

The token is sensitive because the login-status response can yield data["secret_key"]. Its handling should therefore follow credential-protection requirements rather than ordinary request-parameter handling.

Attack Path

  1. The user runs the documented command with --access_token.
  2. The ...[truncated 900 chars]
Remediation
View remediation

Remediation Suggestions

  • Do not accept login tokens directly as command-line arguments.
  • Read the token from protected standard input, a platform credential store, or a file restricted to mode 0600.
  • Send the token in the HTTPS POST body or a dedicated authorization header rather than in the URL query string.
  • Configure client, proxy, and server logging to redact authentication headers and sensitive request fields.
  • Avoid including tokens in exception messages, debug output, agent transcripts, or telemetry.
  • Make login tokens short-lived and single-use, and invalidate them immediately after successful exchange.
  • Document secure invocation methods and remove examples that place credentials directly in shell commands.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill is presented as a media-generation utility, but the docs indicate a separate login flow, QR-based authentication, polling, and local credential retrieval/storage. Undisclosed authentication and credential-handling behavior materially changes the security profile because it can cause users to expose account access or permit local secret persistence they did not knowingly approve.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill is presented as a media-generation utility, but the docs indicate a separate login flow, QR-based authentication, polling, and local credential retrieval/storage. Undisclosed authentication and credential-handling behavior materially changes the security profile because it can cause users to expose account access or permit local secret persistence they did not knowingly approve.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The entire skill file presents instructions and operational details exclusively in Chinese. This can violate a language/locale policy when users are not given a choice of language and the locale restriction is not documented as required or region-specific.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documents network access plus local file read/write behavior but does not declare any tool scope or allowed-tools boundaries. This weakens runtime containment and increases the chance that an agent invokes broader capabilities than users expect, especially since the skill also references login flows and local credential handling.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The activation description is broad enough that an agent may invoke the skill whenever a user asks for digital-human video generation, without clear exclusions or preconditions. Overbroad triggering is dangerous in agent settings because it can route sensitive user content to an external service or start authentication/payment flows unexpectedly.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill does not warn that submitted text, audio URLs, and avatar/media URLs are sent to an external API service. This is a real privacy and data-governance issue because users may share proprietary, personal, or regulated content under the mistaken belief it is processed locally or only within the agent environment.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The usage guidance repeats the same broad invocation rule without adding guardrails, which reinforces unsafe auto-selection behavior. In context, this is more concerning because the skill can lead to third-party network transmission, login handling, and possible local state changes.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The documentation claims results are automatically saved locally, but the described commands and API responses only create remote jobs and return IDs or URLs. Misstating local write behavior is risky because operators may not know whether files are being downloaded and stored, which affects disk usage, data retention, and privacy expectations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The file's docstrings, CLI descriptions, and user-facing status/error messages are written only in Chinese, which imposes a specific language on users without any opt-in or alternative locale support. The policy explicitly calls out language or locale constraints as violations when the skill does not offer user choice or clearly justify the restriction.

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 · generate_video.py (reported line 51)May include surrounding context.

python
try:
            print(f"正在生成视频... 数字人ID: {human_id}, 音色ID: {voice_id}")
            response = requests.post(url, headers=self.headers, json=payload)
            response.raise_for_status()

            result = response.json()

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 · generate_video.py (reported line 86)May include surrounding context.

python
try:
            print(f"正在生成视频... 数字人ID: {human_id}, 音色ID: {voice_id}")
            response = requests.post(url, headers=self.headers, json=payload)
            response.raise_for_status()

            result = response.json()

Tainted flow: 'data' from requests.post (line 85, 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 · generate_video.py (reported line 86)May include surrounding context.

python
try:
            data = {"human_video_id": str(human_video_id)}
            response = requests.post(url, headers=self.headers, json=data)
            response.raise_for_status()

            result = response.json()

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · login.py (reported line 7)May include surrounding context.

python
from utils import jiuma_request, output_result, save_jiuma_api_key,save_jiuma_rand_str, get_jiuma_rand_str, \
    JIUMA_RAND_STR_SAVE_PATH

LOGIN_API = "https://api.jiuma.com/user/getLoginQrcode"
CHECK_API = "https://api.jiuma.com/user/checkLoginStatus"

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · login.py (reported line 8)May include surrounding context.

python
from utils import jiuma_request, output_result, save_jiuma_api_key,save_jiuma_rand_str, get_jiuma_rand_str, \
    JIUMA_RAND_STR_SAVE_PATH

LOGIN_API = "https://api.jiuma.com/user/getLoginQrcode"
CHECK_API = "https://api.jiuma.com/user/checkLoginStatus"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code saves the returned API secret key immediately to local storage via save_jiuma_api_key(data["secret_key"]) without any user-facing confirmation, warning, or indication of how it will be stored. Persisting credentials silently increases the risk of accidental long-term exposure, especially if the storage location or file permissions are weak elsewhere in the skill.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This JSON contains natural-language values such as gender and role labels only in Chinese (for example "女", "男", "卡通", "真人") and Chinese-character names, but provides no documented locale constraint or user opt-in. Under the policy, forcing a specific language without user choice or justification is a natural-language locale violation.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill creates a local hidden directory and defines file paths for storing the API key and a related token/random string on disk, which extends its behavior beyond transient video-generation into credential persistence. Persisting secrets in plaintext increases exposure to local compromise, accidental leakage, or reuse by other processes, especially since the manifest does not disclose this storage behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The function writes the API key directly to a local file in plaintext without any warning, consent flow, or protection mechanism. A plaintext API key on disk can be read by other local users, malware, backups, or tooling, enabling unauthorized use of the external service and possible account abuse.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The natural-language instructions, workflow, and operational guidance are presented only in Chinese, which can amount to a language policy issue if users are not given an opt-in or alternative locale. There is no statement that the skill is region-specific or that Chinese is required for a justified reason.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The documentation mentions automatic saving of generated results without warning about local file creation or storage location effects. Even if benign, undisclosed local writes can surprise operators, create retention issues, or store sensitive media in insecure locations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The function stores a token-like random string to disk without disclosure or protection. Even if this value is not the primary credential, related tokens can support session hijacking, request forgery, or facilitate use of the associated API workflow when combined with other information.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.