T09 · Insecure Skill Coding Practices
Error
- Location
- lib/token_manager.py:130
- Finding
- Disabling Token Caching Does Not Prevent Token Persistence<![CDATA[ ## Vulnerability Details **File Location**: `lib/token_manager.py`, lines 130-164 and 204-216 **Vulnerability Type**: Security control bypass resulting in plaintext bearer-token persistence **Risk Level**: High ### Complete Code Snippet ```python def get_cached_token(app_key, app_secret, use_cache=None): """ Get access token, using cached version if available and valid. """ # Check environment variable for cache override if use_cache is None: env_cache = os.environ.get("EZVIZ_TOKEN_CACHE", "1").strip().lower() use_cache = (env_cache not in ["0", "false", "no", "disable"]) cache_key = generate_cache_key(app_key, app_secret) # Try to load from cache first if use_cache: all_cache = load_token_cache() if cache_key in all_cache: cached = all_cache[cache_key] expire_time = cached.get("expire_time", 0) current_time = get_current_timestamp() # Check if cache is still valid (with buffer time) if current_time + TOKEN_BUFFER_TIME < expire_time: expire_str = time.strftime( '%Y-%m-%d %H:%M:%S', time.localtime(expire_time / 1000) ) print(f"[INFO] Using cached global token, expires: {expire_str}") return { "success": True, "access_token": cached["access_token"], "expire_time": expire_time, "from_cache": True } else: print("[INFO] Cached token expired or about to expire, will get new one") # Cache miss or expired, get new token return refresh_token(app_key, app_secret, cache_key) ``` ```python # Save to global cache all_cache = load_token_cache() all_cache[cache_key] = { "cache_key": cache_key, "access_token": access_token, "expire_time": expire_time, "created_at": get_current_timestamp(), ...[truncated 2104 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Pass the cache decision into `refresh_token()` and conditionally suppress all cache operations: ```python def get_cached_token(app_key, app_secret, use_cache=None): if use_cache is None: env_cache = os.environ.get("EZVIZ_TOKEN_CACHE", "1").strip().lower() use_cache = env_cache not in ["0", "false", "no", "disable"] cache_key = generate_cache_key(app_key, app_secret) if use_cache: # Read and validate existing cache. ... return refresh_token( app_key, app_secret, cache_key=cache_key, save_to_cache=use_cache ) def refresh_token(app_key, app_secret, cache_key=None, save_to_cache=True): ... if save_to_cache: all_cache = load_token_cache() all_cache[cache_key] = { "cache_key": cache_key, "access_token": access_token, "expire_time": expire_time, "created_at": get_current_timestamp(), "app_key_prefix": app_key[:8] + "..." if len(app_key) > 8 else app_key } save_token_cache(all_cache) ``` 2. When caching is disabled, avoid creating the cache directory or reading any pre-existing cache. 3. Clearly distinguish between “do not read cache” and “do not persist token” if both behaviors must be supported. 4. Add automated tests confirming that `EZVIZ_TOKEN_CACHE=0` creates neither a cache directory nor a cache file. 5. Consider deleting an existing entry for the relevant account when the user explicitly disables persistence, subject to clear documentation and user consent. ]]>
