T05 · Unauthorized Access and Privilege Escalation
- Location
soulharbor/storage/kv_store.py:22- Finding
Non-Injective Key Normalization Enables Cross-User Profile Access
- Content
View full analysis
Path: """Get file path for key""" # Use safe file name safe_key = key.replace("/", "_").replace("\\", "_") return self.store_path / f"{safe_key}.json" ``` The affected method is called with a key derived directly from a user-controlled identifier: ```python def load_user_profile(self, user_id: str) -> UserProfile: """Load user profile from storage""" if user_id in self._user_profiles: return self._user_profiles[user_id] # Load from KV store data = self.kv_store.get(f"user_profile_{user_id}") if data: profile = UserProfile.from_dict(data) else: # Create new user profile profile = UserProfile(user_id=user_id) self._user_profiles[user_id] = profile return profile ``` ### Technical Analysis The filename normalization algorithm is not injective: multiple distinct logical keys can be transformed into the same physical filename. Both `/` and `\` are replaced with `_`, while an existing underscore remains unchanged. For example: ```text user_profile_a/b -> user_profile_a_b.json user_profile_a_b -> user_profile_a_b.json ``` Consequently, two distinct user identifiers can address the same JSON profile. No validation restricts the format of `user_id`, and the loaded profile is not checked to ensure that its serialized `user_id` matches the requested identity. This is a broken object-isolation issue at the storage layer. It does not require path traversal because the attempted path-safety transformation itself creates the collision. ### Attack Path 1. A victim uses the identifier `a_b`. 2. `MemorySystem.save_user_profile()` creates the logical key `user_profile_a_b`. 3. ...[truncated 1194 chars]- Remediation
View remediation
