T09 · Insecure Skill Coding Practices
Warning
- Location
- src/memory.py:103
- Finding
- Persistent Agent Memory Is Stored Without Explicitly Restrictive Permissions## Vulnerability Details **File Location**: `src/memory.py`, lines 103–105 and 112 **Vulnerability Type**: Plaintext sensitive data stored with umask-dependent permissions **Risk Level**: Medium ### Vulnerable Code ```python if db_path is None: db_dir = Path.home() / ".agent-memory" db_dir.mkdir(exist_ok=True) db_path = str(db_dir / "memory.db") self.db_path = db_path self._init_db() ``` The database is subsequently created or opened without enforcing its permissions: ```python conn = sqlite3.connect(self.db_path) ``` ### Technical Analysis The default directory is created without an explicit restrictive mode, and the SQLite database is opened without verifying or enforcing file ownership and permissions. Their effective permissions therefore depend on the process umask and any pre-existing filesystem object at the path. The database stores conversation-derived facts, lessons, personal entities, preferences, and arbitrary attributes in plaintext. In a multi-user environment with a permissive umask or incorrectly configured parent directory, another local account may be able to read this persistent context. If write access is available, that account may also tamper with the database and influence information recalled by the agent in later sessions. The implementation also does not reject a pre-existing symbolic link at the default database path. Under an environment where an attacker can modify the memory directory, this may enable redirection to an attacker-controlled database or another writable target. Exploitation requires local filesystem access and inadequate surrounding permissions; no remote exploitation path is present in the reviewed code. ### Attack Path 1. An agent invokes `AgentMemory()` with the default path. 2. The application creates `~/.agent-memory` and `memory.db` using permissions derived from the process umask. 3. The agent stores sensitive conversation facts, behavioral lessons, preferences, or entity attributes in th ...[truncated 1233 chars]
- Remediation
- ## Remediation Suggestions 1. Create the default directory with owner-only permissions: ```python db_dir.mkdir(mode=0o700, parents=True, exist_ok=True) db_dir.chmod(0o700) ``` 2. Securely create the database file with mode `0600` before connecting, or immediately enforce that mode after creation: ```python import os fd = os.open(db_path, os.O_CREAT | os.O_RDWR, 0o600) os.close(fd) os.chmod(db_path, 0o600) ``` 3. Use `lstat()` and reject symbolic links for the default database path. Verify that both the directory and database are owned by the expected user. 4. Apply equivalent validation to custom database paths or clearly document that callers are responsible for securing them. 5. Document that secrets, credentials, authentication tokens, and other highly sensitive values should not be stored in plaintext memory. 6. Where local-user isolation is insufficient, use an encrypted storage design with keys obtained from an operating-system keychain or another protected secret store. 7. Add tests that initialize the default storage under different umasks and assert directory mode `0700`, database mode `0600`, expected ownership, and symbolic-link rejection.
