T05 · Unauthorized Access and Privilege Escalation
Warning
- Location
- scripts/token-audit.py:72
- Finding
- Overbroad Access to Sensitive Agent State and Unselected Workspace Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/token-audit.py:72-83`, `scripts/token-audit.py:99-136` **Vulnerability Type**: Overbroad filesystem access and cross-workspace scanning **Risk Level**: Medium ### Complete Code Snippet ```python # Core workspace files core_files = [ "SOUL.md", "AGENTS.md", "HEARTBEAT.md", "USER.md", "MEMORY.md", "TOOLS.md", "IDENTITY.md", "MISSION.md", "BOOTSTRAP.md", ] for fname in core_files: fpath = workspace / fname if fpath.exists(): content = read_file_safe(fpath) tokens = count_tokens(content) results["files"].append({ "name": fname, "path": str(fpath), "size_bytes": len(content.encode("utf-8")), "tokens": tokens, "category": "core", }) results["total_context_tokens"] += tokens results["categories"].setdefault("core", 0) results["categories"]["core"] += tokens # Memory files (if loaded into context) memory_dir = workspace / "memory" if memory_dir.exists(): for mf in sorted(memory_dir.glob("*.md")): content = read_file_safe(mf) tokens = count_tokens(content) results["files"].append({ "name": f"memory/{mf.name}", "path": str(mf), "size_bytes": len(content.encode("utf-8")), "tokens": tokens, "category": "memory", "note": "loaded per AGENTS.md rules (daily + cross-session)", }) # Only count today's + yesterday's + cross-session as always-loaded results["categories"].setdefault("memory", 0) results["categories"]["memory"] += tokens # Installed skills skill_dirs = [] for skills_root in [ workspace / "skills", Path.home() / ".openclaw" / "workspace" / "skills" ]: if skills_root.exists(): for skill_md in skills_root.rglob("SKILL.md"): skill_dir = skill_md.parent if skill_dir not in skill_dirs: ...[truncated 2876 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Restrict scanning to the explicitly selected workspace by default. Remove the unconditional default-workspace skills root: ```python skill_roots = [workspace / "skills"] ``` 2. Introduce an explicit opt-in option such as `--include-global-skills` before accessing `~/.openclaw/workspace/skills`. 3. Require separate opt-in flags such as `--include-memory` and `--include-identity-files` for files likely to contain private agent state. 4. Resolve and validate every candidate path before reading it: ```python workspace = workspace.expanduser().resolve() candidate = candidate.resolve() if candidate != workspace and workspace not in candidate.parents: raise ValueError("Refusing to scan outside the selected workspace") ``` 5. Avoid following symlinks that resolve outside the authorized workspace, or apply the containment check after symlink resolution. 6. Use filesystem byte sizes for basic estimates where possible instead of reading complete sensitive files. If tokenization requires content, process data incrementally and discard it immediately. 7. Redact absolute paths by default. Return workspace-relative paths unless a separate `--show-absolute-paths` option is supplied. 8. Clearly document which state files are read, and display the final scan roots before execution so users can provide informed consent. ]]>
