T07 · Tool Hijacking and Spoofing
- Location
journal_meta.py:265- Finding
Automatic Discovery and Execution of Untrusted Local Python Tools
- Content
View full analysis
Vulnerability Details
File Location:
journal_meta.py, lines 265–321, with invocation points at lines 329–330 and 346–347
Vulnerability Type: Untrusted local tool discovery and execution
Risk Level: HighVulnerable Code
python def _find_sibling(basename, env_var): if basename in _SIBLING_CACHE: return _SIBLING_CACHE[basename] override = os.environ.get(env_var) if override and os.path.isfile(override): _SIBLING_CACHE[basename] = override return override here = os.path.dirname(os.path.abspath(__file__)) roots = [ here, os.path.dirname(os.path.dirname(here)), # <repo>/skills/journal-meta -> <repo> os.path.dirname(os.path.dirname(os.path.dirname(here))), # workspace root (siblings live here) os.path.expanduser("~/.claude/skills"), os.path.expanduser("~/.config/openclaw/skills"), os.path.expanduser("~/.openclaw/skills"), os.path.expanduser("~/.claude/plugins"), ] found = None seen = set() for root in roots: if not root or root in seen or not os.path.isdir(root): continue seen.add(root) for dirpath, dirnames, filenames in os.walk(root): depth = dirpath[len(root):].count(os.sep) # keep the walk shallow if depth > 5: dirnames[:] = [] continue dirnames[:] = [d for d in dirnames if d not in (".git", "node_modules", "cache", "__pycache__", ".venv")] if basename in filenames: found = os.path.join(dirpath, basename) break if found: break _SIBLING_CACHE[basename] = found return found def _call_cli(path, args, timeout=40): try: p = subprocess.run([sys.executable, path, *args, "--format", "json"], capture_output=True, text=True, timeout=timeout) except (subprocess.TimeoutExpired, OSError): ...[truncated 3094 chars]- Remediation
View remediation
Remediation Suggestions
- Remove recursive filename-based discovery across workspace, Skill, and plugin trees.
- Require explicit configuration of sibling-tool paths, or resolve tools only from fixed installation directories controlled by the trusted package manager.
- Canonicalize configured paths with
os.path.realpath()and verify that they remain within an allowlisted root. - Reject symbolic links and files with unsafe ownership or permissions.
- Verify sibling tools using a pinned cryptographic hash, signed manifest, or authenticated package identity before execution.
- Avoid executing source files directly where possible. Prefer a trusted, versioned Python package with a documented API.
- Disable optional delegation by default when tool authenticity cannot be established; use the network fallback or require explicit user opt-in.
- Run optional enrichment tools in a restricted subprocess with a minimal environment, constrained filesystem access, no unnecessary network access, and resource limits.
- Validate subprocess output as untrusted data even after tool verification.
- If environment-variable overrides remain supported, clearly document that they are executable-code trust boundaries and apply the same path, ownership, permission, and integrity checks.
