T09 · Insecure Skill Coding Practices
- Location
scripts/billing.js:12- Finding
Hard-Coded Production Billing API Credential
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a disclosed session-password guard, but its authentication, recovery, and billing implementation has serious security and consent concerns.
Review carefully before installing. This skill handles session access, recovery secrets, local audit/state files, and paid billing calls, but the reviewed artifact has major implementation gaps and unsafe secret-handling patterns. Do not rely on it as a security boundary unless the authentication schema, recovery flow, billing consent, and hardcoded credential issues are fixed.
scripts/billing.js:12Hard-Coded Production Billing API Credential
scripts/setup.js:22Authentication Guard Is Not Reliably Enforced Due to Incompatible Configuration Schemas
scripts/email-recovery.js:23Recovery Codes Use Non-Cryptographic Randomness and Have No Attempt Limit
scripts/email-recovery.js:85Plaintext Recovery Code and Email Are Exposed in Stub Mode
scripts/email-recovery.js:174Password Recovery Downgrades Credentials to Unsalted SHA-256
scripts/auth-core.js:307Authentication CLI Exposes Passwords Through Process Arguments
scripts/test-billing.js:40Billing Test Uses Production Credentials and Performs a Real Charge Request
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.
return { locked: true, remainingMinutes: remainingMin };
}
// Lock expired, reset
state.lockedUntil = null;
state.failedAttempts = 0;
saveJson(AUTH_STATE_FILE, state);
The CLI accepts the passphrase as a positional argument, which can expose the secret through shell history, process listings, audit tooling, and logs on multi-user systems. This creates a real credential disclosure risk even if the underlying verification logic is otherwise correct.
The trigger conditions are broad and based on common authentication-related words and session start, which can cause the skill to activate in contexts where the user is only discussing passwords rather than requesting access control. Because this skill appears to gate session access and includes commands like uninstalling the auth skill, ambiguous activation increases the risk of unintended interception, denial of service, or socially engineered invocation.
The specification states that authentication events and credential-related state are stored in local files, but it does not warn users about this data handling or describe retention, access controls, and sensitivity of the logs. In a local skill environment, undisclosed logging and storage of authentication metadata can create privacy and security risks, especially if audit logs, recovery data, or state files are accessible to other processes or users.
The documented trigger conditions are broad enough to activate the authentication skill on generic words like "password" or "auth," which can cause unintended invocation during normal conversation. In an agent context, unexpected activation can interrupt workflows, expose authentication state transitions, or trigger sensitive operations such as logout, recovery, or uninstall paths without sufficiently explicit user intent.
This file is entirely hard-coded in zh-CN and presents all setup, authentication, recovery, and command text only in Simplified Chinese. Under the policy rule for natural-language violations, forcing a specific language is a concern unless the skill explicitly offers language choice or clearly documents a justified region-specific constraint.
The manifest hardcodes a live-looking billing API key and declares payment/billing integration inside a package described as a session password/authentication guard. Embedding secrets in a distributable package exposes the credential to anyone with package access, and the unrelated monetization logic increases the attack surface and raises concern about hidden external calls in a security-sensitive skill.
The top-level documentation states the module implements "email recovery," creating an expectation of an actual recovery mechanism. In the implementation, the only related behavior is exposing stored recovery metadata via getRecoveryEmail/getSecurityQuestion and verifying a security answer; there is no email dispatch, token generation, or reset workflow.
This code returns authentication prompts and lockout messages only in Chinese string literals. For a general-purpose authentication module, forcing a specific language without user opt-in or documented regional scope is a natural-language policy violation under the locale-choice requirement.
The file header advertises a pricing model of 29 USDT buyout and 0.9 USDT per call, while the executable code sets PRICE_PER_CALL to 0.01 USDT and does not implement the documented buyout in the main flow. Security-relevant billing mismatches are dangerous because users and integrators may make consent and trust decisions based on false pricing, enabling deceptive charging behavior or unauthorized access assumptions.
The code includes a checkPurchased function and comments promising buyout handling, but handleBilling ignores purchase status and always attempts a per-call charge. This can cause previously entitled users to be charged again, which is a real billing integrity issue and could amount to unauthorized repeat charging.
This function performs a live billing charge over the network as soon as it is invoked, with no indication in this file of any prior user confirmation, pre-charge notice, or review step. In a skill context, silent charging is more dangerous because invocation may be indirect or automated, increasing the risk of non-consensual charges and dispute exposure.
The skill sends and displays user-facing content primarily in Chinese, including the email subject and CLI/status messages, without offering a language choice or documenting a locale-specific constraint. This can violate organizational language/locale policy when the skill is not clearly limited to Chinese-speaking users.
In stub mode, the recovery code is written in plaintext to a predictable local file inside the workspace, and the function even returns the code in the result object. In an agent/workspace context, other local processes, skills, or users with workspace access could read the file and use the code to assist account takeover, especially since this module handles password recovery secrets.
The CLI help and command name present this path as a simple verification action, but verifyRecoveryCode has a side effect: on success it sets record.used = true and writes the record back to disk. This is an intent-level contradiction because a user or caller invoking 'verify' would reasonably expect a read/check operation, not one that irreversibly consumes the code.
The header comment describes this as a 'Session Password' module that generates documents for a password-authentication skill, and the document body repeatedly presents implemented security features such as bcrypt hashing, lockouts, recovery email, and audit logs. However, the actual code performs no authentication, hashing, recovery, or security enforcement; it only constructs and writes DOCX files to disk.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
const OUTPUT_DIR = path.join(process.env.OPENCLAW_WORKSPACE || path.join(process.env.HOME, '.openclaw', 'workspace'), 'session password');
// Create output directory
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
This code emits password validation feedback exclusively in Chinese from validatePassword(), even though the skill later offers a language choice. A user selecting English would still receive Chinese-only error strings, which is a natural-language locale policy issue because the skill does not consistently honor the user's language preference.
The setup wizard tells users that recovery codes will be sent to the configured email, but this script only validates and stores the email address locally and does not implement any delivery mechanism. This creates a misleading security/recovery guarantee that can cause account lockout and unsafe operational assumptions during incident recovery.
The final success message repeats that forgotten-password recovery codes can be sent by email, but no such functionality exists in the script. Reaffirming a nonexistent recovery path increases the chance that users rely on it and fail to provision alternate recovery controls.
This test script performs an actual POST to a live billing endpoint using a hardcoded production-looking API key and submits a charge request, so running it can trigger real financial operations rather than a harmless mock test. In the context of a billing integration skill, labeling the action as a test does not reduce the risk because developers or operators may execute it assuming it is non-destructive, causing unauthorized charges or abuse of exposed credentials.
The uninstall flow always requires the literal English string "yes" to proceed, even when the UI is presented in Chinese. This is a real usability and safety flaw because users in the non-English flow may misunderstand the confirmation requirement, causing failed or repeated uninstall attempts, but it does not create unauthorized access or code execution by itself.
Using a caret range for bcrypt means installs may resolve to different releases over time, which weakens reproducibility and makes it harder to verify whether a vulnerable version is being pulled in. In a security-focused package, dependency drift is especially undesirable because cryptographic and auth components should be tightly controlled.
"node": ">=18.0.0"
},
"dependencies": {
"bcrypt": "^5.1.1",
"axios": "^1.6.0"
},
"pricing": {
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Using an unpinned axios version allows future installs to pick up different releases, complicating verification against known advisories and potentially introducing exploitable HTTP-client issues. Because this skill already advertises external billing/payment communication, axios is likely used for outbound network requests, which makes dependency risk more relevant than in a purely local package.
},
"dependencies": {
"bcrypt": "^5.1.1",
"axios": "^1.6.0"
},
"pricing": {
"type": "paid",
No suspicious patterns detected.