T09 · Insecure Skill Coding Practices
- Location
deep_recall.py:410- Finding
Requested recall scope is not enforced when selecting and reading files
- Content
View full analysis
Vulnerability Details
File Location:
deep_recall.py:410-447; related index construction inmemory_indexer.py:100-143
Vulnerability Type: Scope authorization bypass and excessive disclosure of workspace memory
Risk Level: HighVulnerable Code
python # 2. Scan memory files ws = Path(workspace) if workspace else _find_workspace() scanner = MemoryScanner(workspace=ws) scanner.scan(scope=scope) if not scanner.files: return "[DeepRecall] No memory files found in workspace." # 3. Build memory index memory_index = build_memory_index(workspace=ws) # 4. Manager: pick the relevant files try: selected_files = _manager_call(query, memory_index, max_files, provider) except Exception as exc: return f"[DeepRecall] Manager call failed: {exc}" if not selected_files: return "[DeepRecall] No relevant memory files identified for this query." # 5. Workers: extract quotes in parallel worker_results: list[dict] = [] with ThreadPoolExecutor(max_workers=min(len(selected_files), 4)) as pool: futures = {} for fpath in selected_files: content = _read_file(fpath, ws) if content is None: continue fut = pool.submit(_worker_call, query, fpath, content, provider) futures[fut] = fpathThe independently constructed index includes all Markdown memory files:
python memory_dir = workspace / "memory" memory_md = workspace / "MEMORY.md" # Collect all daily logs daily_logs = {} if memory_dir.exists(): for f in sorted(memory_dir.glob("*.md")): # Extract date from filename date_match = re.match(r"(\d{4}-\d{2}-\d{2})", f.name) if date_match: date_str = date_match.group(1) content = f.read_text(errors="replace") topics = extract_topics(content, f.name) daily_logs[date_str] = { "path": f"memory/{f.name}", ...[truncated 3065 chars]- Remediation
View remediation
Remediation Suggestions
- Treat the canonical paths in
scanner.filesas an authorization allowlist:python allowed_paths = { item.path.resolve() for item in scanner.files } for fpath in selected_files: resolved = _safe_path(fpath, ws) if resolved is None or resolved not in allowed_paths: logger.warning("Rejected out-of-scope manager selection: %r", fpath) continue - Build the manager index directly from the already-scoped scanner result rather than rescanning the workspace.
- Change
build_memory_index()to accept an explicit collection of authorized files or a validated scope. - Apply scope validation after manager output because model responses are untrusted, even if the prompt instructs the model to honor a scope.
- Add regression tests proving that
identitycannot index or read files undermemory/, and thatmemorycannot select arbitrary project files. - Ensure documentation accurately describes both metadata and full-content boundaries for every scope.
- Treat the canonical paths in
