T09 · Insecure Skill Coding Practices
- Location
SKILL.md:72- Finding
Plaintext Persistent Storage of DingTalk Credentials and Access Tokens
- Content
View full analysis
/dev/null | cut -d= -f2-) TOKEN_EXPIRY=$(grep '^DINGTALK_TOKEN_EXPIRY=' "$CONFIG" 2>/dev/null | cut -d= -f2-) NOW=$(date +%s) if [ -n "$CACHED_TOKEN" ] && [ -n "$TOKEN_EXPIRY" ] && [ "$NOW" -lt "$TOKEN_EXPIRY" ]; then TOKEN=$CACHED_TOKEN else RESP=$(curl -s -X POST https://api.dingtalk.com/v1.0/oauth2/accessToken \ -H 'Content-Type: application/json' \ -d "{\"appKey\":\"$APP_KEY\",\"appSecret\":\"$APP_SECRET\"}") TOKEN=$(echo "$RESP" | grep -o '"accessToken":"[^"]*"' | cut -d'"' -f4) sed -i '/^DINGTALK_ACCESS_TOKEN=/d;/^DINGTALK_TOKEN_EXPIRY=/d' "$CONFIG" echo "DINGTALK_ACCESS_TOKEN=$TOKEN" >> "$CONFIG" echo "DINGTALK_TOKEN_EXPIRY=$((NOW + 7000))" >> "$CONFIG" fi ``` ### Technical Analysis The workflow stores the DingTalk application secret and cached bearer token in `~/.dingtalk-skills/config` as plaintext. It neither creates the directory and file with restrictive permissions nor validates the file's owner, permissions, or type before reading and modifying it. The configuration update also follows symbolic links because ordinary shell redirection and `sed -i` are used without checking the destination. Consequently, the security of the credentials depends on the caller's existing `umask`, directory permissions, and filesystem state. Masking credentials in user-visible output does not protect the values at rest. A process or local account capable of reading the config ...[truncated 1653 chars]- Remediation
View remediation
