T09 · Insecure Skill Coding Practices
- Location
SKILL.md:154- Finding
Employee Credentials and Bearer Tokens Transmitted Over Plaintext HTTP
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This CRM assistant has a coherent business purpose, but it handles employee passwords, bearer tokens, and CRM records in ways that are too risky for automatic installation.
Install only if you trust the CRM operator and can tolerate the skill handling employee passwords and CRM data. Before production use, require HTTPS, remove token-in-URL fallback, replace chat passwords with a secure login flow, store tokens in a credential store or locked-down file, narrow the triggers, and document manager/subordinate access clearly.
SKILL.md:154Employee Credentials and Bearer Tokens Transmitted Over Plaintext HTTP
SKILL.md:175Bearer Tokens Stored in an Unprotected Plaintext Cache
SKILL.md:351Full Bearer Token Exposed in Plaintext H5 URL Fallback
SKILL.md:470Unpinned Third-Party Package Installed and Executed at Runtime
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.
The skill instructs the AI to extract account IDs and passwords from free-form chat and reuse them for authentication, without masking, minimization, or a safer delegated login flow. This is dangerous because conversational channels are often logged, retained, or visible to intermediaries, making raw credential handling a serious exposure path.
The skill explicitly says raw tokens must not be exposed in URLs, but the fallback logic appends the full bearer token as a query parameter. Tokens in URLs can leak through browser history, logs, referer headers, screenshots, proxies, and shared links, which could allow account takeover or unauthorized CRM access.
The description defines invocation and usage entirely in Chinese and does not state that the skill is China-only or otherwise locale-restricted. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern unless the locale constraint is clearly justified.
Several trigger patterns are broad enough to activate on ordinary project-related conversation, which can unintentionally launch a skill that accesses CRM records, visit records, or synchronization flows. In a security-sensitive assistant, accidental routing matters because it may expose internal data or prompt for credentials in the wrong conversational context.
Patterns targeting broad employee-data requests can overmatch requests about staff activity or team projects that were not meant for CRM access. Because this skill can query subordinate data, ambiguous routing increases privacy risk and could surface sensitive team information unexpectedly.
The skill can access and display subordinate employees’ CRM data for managers, but that capability is not prominently disclosed in the high-level description. Hidden scope expansion around employee data creates privacy and governance risk, especially in enterprise settings where users may assume self-only access.
The documentation claims all queries only return the current user's own data, but later supports subordinate lookups and team-wide queries. This inconsistency can mislead reviewers and users about the skill’s real data-access scope, increasing the chance of overbroad disclosure or accidental invocation of managerial data views.
The skill directs silent retention and reuse of authentication material across sessions, reducing user awareness and increasing the blast radius if local state is exposed. Persistent auth reuse is especially risky here because the same skill can access CRM and subordinate-related data depending on role.
The skill collects employee credentials from chat and caches authentication material locally, but this sensitive handling is not clearly disclosed up front in the user-facing description. Users may provide credentials without understanding storage and reuse behavior, which increases privacy and account-risk concerns.
This sends employee credentials to an external service over HTTP, not HTTPS, which exposes them to interception on the network. The transmission itself is expected for authentication, but using cleartext transport makes it a genuine security vulnerability.
# AI 从用户回复中提取 employee_id(账号)和 password(密码)
# 用户输入示例:"emp-server-106 123456" 或 "我的账号是 emp-server-106,密码是 123456"
response=$(curl -s -X POST "${FASTAPI_BASE_URL}/auth/login" \
-H "Content-Type: application/json" \
-d "{\"employee_id\": \"${EMPLOYEE_ID}\", \"password\": \"${PASSWORD}\"}" \
--max-time 120)
The skill persists authentication tokens and employee identifiers in a workspace file under the user home directory, with no mention of encryption, permission hardening, or secure storage. Local compromise, backup leakage, or cross-process access could expose reusable session material.
employee_name=$(echo "$response" | jq -r '.data.employee_name')
must_change_pw=$(echo "$response" | jq -r '.data.must_change_pw')
mkdir -p ~/.openclaw/workspace/scripts
echo "{\"token\": \"${API_TOKEN}\", \"employee_id\": \"${EMPLOYEE_ID}\", \"employee_name\": \"${employee_name}\", \"expires_at\": \"${expires_at}\", \"updated_at\": \"$(iso_now)\"}" > "$TOKEN_CACHE"
# 首次登录强制改密检测
The password-change flow transmits both old and new passwords to an external endpoint over plain HTTP. Exposure of either credential in transit can lead to immediate account compromise and persistent unauthorized access.
echo "请输入新密码(至少6位):"
echo "(等待用户输入新密码...)"
pw_response=$(curl -s -X POST "${FASTAPI_BASE_URL}/auth/change-password" \
-H "Content-Type: application/json" \
-d "{\"employee_id\": \"${EMPLOYEE_ID}\", \"old_password\": \"${PASSWORD}\", \"new_password\": \"${NEW_PASSWORD}\"}" \
--max-time 120)
This login request again transmits a password externally over HTTP during account-switch handling. Although authentication requires transmission, the insecure transport and chat-derived secret handling make this a real confidentiality risk.
echo "🔑 检测到账号切换,请重新输入密码"
echo "(等待用户输入密码...)"
response=$(curl -s -X POST "${FASTAPI_BASE_URL}/auth/login" \
-H "Content-Type: application/json" \
-d "{\"employee_id\": \"${INPUT_EMPLOYEE_ID}\", \"password\": \"${PASSWORD}\"}" \
--max-time 120)
This is another path that writes refreshed or switched-account authentication material into the same local cache. Repeated persistence of active session tokens without secure storage broadens the chance of unauthorized reuse across accounts.
employee_name=$(echo "$response" | jq -r '.data.employee_name')
EMPLOYEE_ID="$INPUT_EMPLOYEE_ID"
EMPLOYEE_NAME="$employee_name"
mkdir -p ~/.openclaw/workspace/scripts
echo "{\"token\": \"${API_TOKEN}\", \"employee_id\": \"${EMPLOYEE_ID}\", \"employee_name\": \"${EMPLOYEE_NAME}\", \"expires_at\": \"${new_expires}\", \"updated_at\": \"$(iso_now)\"}" > "$TOKEN_CACHE"
else
error_message=$(echo "$response" | jq -r '.message')
This re-login path sends credentials to the external login endpoint over plain HTTP after token expiry. Repeated insecure credential transmission increases exposure opportunities and undermines the token refresh design.
echo "请输入您的账号和密码,格式:账号 密码"
echo "(等待用户输入...)"
response=$(curl -s -X POST "${FASTAPI_BASE_URL}/auth/login" \
-H "Content-Type: application/json" \
-d "{\"employee_id\": \"${EMPLOYEE_ID}\", \"password\": \"${PASSWORD}\"}" \
--max-time 120)
The renew-failure fallback again transmits the user password to an external service over HTTP. The issue is compounded by repeated prompting for secrets and conversational extraction of passwords.
echo "⚠️ Token 续期失败,请重新输入密码"
echo "(等待用户输入密码...)"
response=$(curl -s -X POST "${FASTAPI_BASE_URL}/auth/login" \
-H "Content-Type: application/json" \
-d "{\"employee_id\": \"${EMPLOYEE_ID}\", \"password\": \"${PASSWORD}\"}" \
--max-time 120)
The exchange-code request sends a bearer token to an external API over plain HTTP. Even though this is a token exchange rather than password transmission, interception would still allow session hijacking or downstream link issuance.
H5_BASE_URL="http://47.116.49.218:5173"
# 获取换码(一次性短码,5分钟有效)
exchange_response=$(curl -s -X POST "${FASTAPI_BASE_URL}/auth/exchange-code" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{}' \
The sync call transmits CRM lead data and an authorization token to an external endpoint over HTTP. This can leak sensitive customer/project data and enable unauthorized API use if intercepted.
# 同步数据至 CRM
curl -s -X POST "${FASTAPI_BASE_URL}/crm-leads/sync" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
Detected: suspicious.generated_source_template_injection