T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/evolution.py:16- Finding
Unscoped Collection and Processing of Sensitive Workspace Learnings
- Content
View full analysis
Vulnerability Details
File Location:
scripts/evolution.py, lines 16-76
Vulnerability Type: Unrestricted access to persistent agent interaction data
Risk Level: MediumVulnerable Code
python # Default paths WORKSPACE = Path.home() / ".openclaw" / "workspace" LEARNINGS_DIR = WORKSPACE / ".learnings" MEMORY_DIR = WORKSPACE / "memory" MEMORY_FILE = WORKSPACE / "MEMORY.md" EVOLUTION_LOG = WORKSPACE / ".evolution" / "evolution-log.md" def ensure_evolution_dir(): """Ensure evolution directory exists.""" evol_dir = WORKSPACE / ".evolution" evol_dir.mkdir(parents=True, exist_ok=True) return evol_dir def parse_date(date_str: str) -> Optional[datetime]: """Parse various date formats.""" formats = [ "%Y-%m-%d", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M:%SZ", "%d %b %Y", "%b %d, %Y", ] for fmt in formats: try: return datetime.strptime(date_str.strip(), fmt) except ValueError: continue return None def extract_learnings(days: int = 30) -> list: """Extract learning entries from .learnings/ directory.""" learnings = [] cutoff = datetime.now() - timedelta(days=days) if not LEARNINGS_DIR.exists(): return learnings for file_path in LEARNINGS_DIR.glob("*.md"): content = file_path.read_text(encoding="utf-8") # Split into entries entries = re.split(r'^##\s+\[', content, flags=re.MULTILINE)[1:] # Skip header for entry in entries: # Extract date date_match = re.search(r'\*\*Logged\*\*:\s*(.+?)(?:\n|$)', entry) if date_match: entry_date = parse_date(date_match.group(1)) if entry_date and entry_date >= cutoff: # Extract category category_match = re.match(r'([A-Z]+-\d+-\d+)\]\s+(\w+)', entry) if category_match: entry_id = category_matc ...[truncated 3069 chars]- Remediation
View remediation
Remediation Suggestions
- Require the caller to provide an explicit source directory rather than automatically scanning a global workspace location.
- Resolve and validate the selected path against an allowlisted workspace root, including checks against symbolic-link traversal.
- Display the files that will be processed and require explicit approval before reading persistent interaction data.
- Apply data minimization: retain only the fields required for analysis and remove the complete
"content": entryfield unless strictly necessary. - Redact common credential formats, access tokens, private keys, and other secrets before storing, printing, or passing extracted text downstream.
- Enforce maximum file sizes, entry lengths, and file counts to reduce uncontrolled data ingestion.
- Treat all loaded learning text as untrusted data. Ensure it is never interpreted as executable instructions without separate validation and human review.
- Restrict permissions on
.openclaw/workspace/.learningsso that only the intended account and trusted processes can write to it. - Avoid emitting raw or derived interaction content by default; provide a metadata-only output mode and require an explicit flag for content-bearing output.
- Add tests covering unauthorized paths, symbolic links, maliciously structured entries, secret redaction, and oversized input files.
