T09 · Insecure Skill Coding Practices
- Location
scripts/feishu-calendar.sh:25- Finding
Predictable and Insecure Plaintext Access-Token Cache
- Content
View full analysis
Vulnerability Details
File Location:
scripts/feishu-calendar.sh, lines 25–52
Vulnerability Type: Insecure temporary file and plaintext credential storage
Risk Level: HighVulnerable Code
bash # 缓存 token 到文件(2小时有效) TOKEN_CACHE="/tmp/feishu_interview_token_cache" get_token() { if [[ -f "$TOKEN_CACHE" ]]; then cached=$(cat "$TOKEN_CACHE") expire=$(echo "$cached" | jq -r '.expire // 0') now=$(date +%s) if (( now < expire )); then echo "$cached" | jq -r '.token' return fi fi local resp resp=$(curl -s -X POST "$BASE_URL/auth/v3/tenant_access_token/internal" \ -H "Content-Type: application/json" \ -d "{\"app_id\":\"${FEISHU_APP_ID}\",\"app_secret\":\"${FEISHU_APP_SECRET}\"}") local token expire_at token=$(echo "$resp" | jq -r '.tenant_access_token // empty') if [[ -z "$token" ]]; then echo "ERROR: Failed to get token: $resp" >&2 exit 1 fi expire_at=$(( $(date +%s) + 7000 )) echo "{\"token\":\"$token\",\"expire\":$expire_at}" > "$TOKEN_CACHE" echo "$token" }Technical Analysis
The script stores a Feishu tenant access token as plaintext at the fixed, globally predictable path
/tmp/feishu_interview_token_cache. It does not set a restrictiveumask, explicitly apply mode0600, verify file ownership, reject symbolic links, or create and replace the file atomically.The resulting permissions depend on the process's existing umask. In an environment with a permissive umask, other local users may be able to read the bearer token. Because the path is predictable and the file is written using ordinary shell redirection, the implementation is also exposed to temporary-file race and symbolic-link risks where platform protections or directory permissions do not prevent them.
The cache is trusted solely based on its JSON expiration value. There is no validation that the file is owned by the ...[truncated 1802 chars]
- Remediation
View remediation
Remediation Suggestions
- Store the token in a private per-user runtime directory, preferably
${XDG_RUNTIME_DIR}, rather than a shared/tmppath. - Set
umask 077before creating any file that contains credentials. - Create the cache with mode
0600and verify its ownership before reading it. - Reject symbolic links and non-regular files. Where available, use APIs or utilities that provide
O_NOFOLLOW-equivalent behavior. - Write the cache atomically by creating a securely randomized temporary file in the same private directory, setting its permissions, and renaming it into place.
- Do not trust an existing cache unless its owner, permissions, type, and contents have been validated.
- Prefer an operating-system credential store or avoid persistent token caching if repeated authentication is acceptable.
- Remove the cache on termination when practical, and ensure expired cache files are securely deleted.
- Configure the Feishu application according to least privilege so that theft of a tenant token has the smallest possible impact.
A hardened implementation should use a pattern similar to:
bash umask 077 CACHE_DIR="${XDG_RUNTIME_DIR:-$HOME/.cache}/feishu-interview" mkdir -p -- "$CACHE_DIR" chmod 700 -- "$CACHE_DIR" TOKEN_CACHE="$CACHE_DIR/token.json" tmp_file=$(mktemp "$CACHE_DIR/token.XXXXXX") chmod 600 -- "$tmp_file" jq -n --arg token "$token" --argjson expire "$expire_at" \ '{token: $token, expire: $expire}' > "$tmp_file" mv -f -- "$tmp_file" "$TOKEN_CACHE"Before reading the cache, the script should also verify that it is a regular, non-symbolic-link file owned by the current user and not accessible by group or other users.
- Store the token in a private per-user runtime directory, preferably
