smart-tool@0.9.71
CAUTION· startup onlyPublisher claims: "Local MCP server that gives coding agents (Claude Code, Codex) cheaper, sharper tools than their built-in search. Windows." Observed in sandbox: no network, touches nothing outside the project, writes no memory.
Coverage
Startup only; authenticated tool behavior not tested.- Tested
- install scripts, with decoy credentials in place · second launch with the clock 45 days ahead · server startup over stdio (initialize sent) · every file read, file written and host contacted by what ran
- Not tested
- the tool list (the server exited before answering) · what the tools do when called with real credentials
What this means for the label: Caution here covers what ran. The server's tools were not exercised with a real credential, so nothing about their behavior is asserted; the credential summary below says what to do with that.
Before you give it your token
- It will ask for
- no credential variables read in the code
- Where it talks to
- no vendor host named in the codeAlso claude.com, chatgpt.com, microsoft.com, cursor.com, openxmlformats.org, oclc.org, osv.dev, your.site — not the publisher's domain; check what for before connecting.
- What the honeypot saw
- no credential files read · no network
- What we could not test
- the tool list (the server exited before answering) · what the tools do when called with real credentials
Connect it under the guard. Startup only; authenticated tool behavior not tested. The code names no credential variable; the guard pins the network to what the honeypot saw and logs every call.
Never paste a credential into a chat, a ticket or a report, including ours. How the guard holds it.
Is [email protected] safe to install?
KillerSkills ran it in the KillerSkills honeypot sandbox (3 scenarios; startup only; authenticated tool behavior not tested) on 2026-11-11 and scored it 68/100 (Caution). It is not known to be malicious, but it has behaviour or code a security policy should decide on before install. Notable findings: Access to sensitive file paths; Auto-update or dynamic fetch configuration; Auto-update or dynamic fetch configuration. Summary: no network, touches nothing outside the project, writes no memory.
Behavior trace
Honeypot run · 21 s · 3 scenarios · 0 deviationsStatic findings
r"os\.getenv\(\s*[\"']([A-Za-z_][A-Za-z0-9_]*)[\"']", r"process\.env\.([A-Za-z_][A-Za-z0-9_]*)",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.def auto_update(cfg=None):Fix: Pin versions and sources; vendor anything fetched at install time."auto_update": True,Fix: Pin versions and sources; vendor anything fetched at install time.value = (cfg if cfg is not None else load_config()).get("auto_update", DEFAULT_CONFIG["auto_update"])Fix: Pin versions and sources; vendor anything fetched at install time.return env.UV_NATIVE_TLS !== undefined ? null : { ...env, UV_NATIVE_TLS: "1" };Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.r"\.env[^/]*|go\.(mod|sum|work(\.sum)?))$")Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.r"process\.env\[\s*[\"']([A-Za-z_][A-Za-z0-9_]*)[\"']", r"System\.getenv\(\s*\"([A-Za-z_][A-Za-z0-9_]*)\"",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.raise ValueError(f"Invalid auto_update ({value!r}) in {CONFIG_PATH}: use true or false.")Fix: Pin versions and sources; vendor anything fetched at install time.return { ...env, NODE_USE_SYSTEM_CA: "1", SMART_TOOL_SYSTEM_CA_RETRY: "1" };Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.if (!input.value.trim()) { setMsg(msg, "error", "Paste the API key before saving."); return; }Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.subprocess.Popen([pythonw if os.path.isfile(pythonw) else sys.executable, os.path.join(folder, "update_splash.py"),Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.".gpg", ".env", ".tfvars", ".har",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."""settings.json text with our PreToolUse and PostToolUse hook URLs moved to base, or None when none changed."""Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.def should_auto_update(latest, now=None):Fix: Pin versions and sources; vendor anything fetched at install time.return subprocess.run(["powershell.exe", "-NoProfile", "-Command", script], env={**os.environ, **(env or {})},Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.runner = next((cmd for key, cmd in (("vitest", "npx vitest run"), ("jest", "npx jest"),Fix: Pin versions and sources; vendor anything fetched at install time."""Remove tmp de gravação interrompida (kill -9, queda de energia) do mesmo arquivo.Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell."""Python modules a test imports inside a string (subprocess.run([sys.executable, "-c", "import click"])), resolvedFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.raise SystemExit(f"No test suite in {SOURCE}; a packaged install runs with --skip-tests (npx @allansantos-dev/smart-tool@{version.VERSION} install).")Fix: Pin versions and sources; vendor anything fetched at install time.result = subprocess.run(["git", *args], cwd=root, capture_output=True, timeout=60)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.result = subprocess.run(["schtasks", "/Query", "/TN", TASK_NAME, "/XML"], capture_output=True, text=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run(["taskkill", "/PID", str(proc.pid), "/T", "/F"], capture_output=True, creationflags=flags)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.done = subprocess.run([str(install_runtime.BROWSER_PYTHON), "-c", _CHROMIUM_PROBE], capture_output=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.("mocha", "npx mocha"), ("node --test", "node --test"))Fix: Pin versions and sources; vendor anything fetched at install time.return subprocess.run([str(python), "-m", "pip", "freeze", "--disable-pip-version-check"],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out._CODEX_URL_RE = re.compile(r'(\[mcp_servers\.smart-tool\][^\[]*?\burl\s*=\s*")http://127\.0\.0\.1:\d+(/mcp")')Fix: Namespace tool names and keep tool descriptions literal; no instructions to the agent inside them.subprocess.run(["taskkill", "/PID", str(proc.pid), "/T", "/F"], capture_output=True, creationflags=flags)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.Popen([executable, *command[1:]], stdout=subprocess.PIPE, stderr=subprocess.PIPE,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.return subprocess.run(['git',*args],cwd=root,capture_output=True,timeout=30,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.<version>: a pinned version keeps npx from reusing an older package from its cache. For a version published minutesFix: Pin versions and sources; vendor anything fetched at install time.pass # no console and no other channel here; a full disk must not kill the notice threadFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.result = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.done = subprocess.run([sys.executable, "-I", "-c", _MEASURE_SCRIPT, os.path.dirname(os.path.abspath(__file__)), stage],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.config.update_config(lambda cfg: cfg.__setitem__("auto_update", not config.auto_update(cfg)))Fix: Pin versions and sources; vendor anything fetched at install time.const USAGE = `Usage: npx @allansantos-dev/smart-tool@<version> install [--target DIR] [--no-start] [--skip-deps]Fix: Pin versions and sources; vendor anything fetched at install time.process=subprocess.run([web_search_adapters.executable_path(web_search_adapters.NODE_EXECUTABLE),f'--max-old-space-size={heap}',str(Path(__file__).with_name(script))],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.def _toggle_auto_update(icon, item):Fix: Pin versions and sources; vendor anything fetched at install time.child = subprocess.Popen(self.command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.Usage: python uninstall.py [--target DIR] [--keep-data] (npm: npx @allansantos-dev/smart-tool@<version> uninstall)Fix: Pin versions and sources; vendor anything fetched at install time.subprocess.run([str(python), "-m", "pip", "install", "--disable-pip-version-check", "-q", "-r",Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.Popen([resolved, *entry["args"]], cwd=cwd, env=env, stdin=subprocess.PIPE,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.listed=subprocess.run(['git','ls-files','-z'],cwd=root,capture_output=True,timeout=30,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run(["taskkill", "/PID", str(proc.pid), "/T", "/F"], capture_output=True, creationflags=flags)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.result = subprocess.run(['git', '--no-optional-locks', '-C', root, *args],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.result = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.listed = subprocess.run(["git", "ls-files", "-z"], cwd=root, capture_output=True, timeout=30)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.return subprocess.run([str(python), str(target / "install_runtime.py"), "--check"], cwd=target,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.Popen(["cmd.exe", "/c", f"ping -n 4 127.0.0.1 >nul & {commands}"], stdin=subprocess.DEVNULL,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.done = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.Popen(command, cwd=workdir, stdin=subprocess.PIPE, stdout=subprocess.PIPE,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.done = subprocess.run([sys.executable, "-I", "-c", PDF_SCRIPT, str(max_pages), str(max_chars)],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.result = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.Usage: npx @allansantos-dev/smart-tool@<version> uninstall [--target DIR] [--keep-data]Fix: Pin versions and sources; vendor anything fetched at install time.subprocess.run(["taskkill", "/PID", str(child.pid), "/T", "/F"], capture_output=True, creationflags=_NO_WINDOW)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# onde vive metade dos arquivos de credencial (.env, .npmrc, .netrc).Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."""Automatic updates are on: the tray switch (config `auto_update`, on by default) and no environment opt-out."""Fix: Pin versions and sources; vendor anything fetched at install time.the tray announced. `@latest` would let npx reuse an older package from its cache and install that instead;Fix: Pin versions and sources; vendor anything fetched at install time.with subprocess.Popen(command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.timer = threading.Timer(TIMEOUT_S, lambda: subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.`@latest`, which lets npx reuse an older package from its cache; --prefer-online because npm's cached version listFix: Pin versions and sources; vendor anything fetched at install time."""The npx command that installs version target, as told to the user and to agent sessions. Pinned rather thanFix: Pin versions and sources; vendor anything fetched at install time."""argv of the update: the npx command a user types, through cmd.exe because npx is a .cmd script, for the versionFix: Pin versions and sources; vendor anything fetched at install time.return f"npx --yes --prefer-online {PACKAGE}@{target} install"Fix: Pin versions and sources; vendor anything fetched at install time.npx = node_locator.which("npx.cmd")Fix: Pin versions and sources; vendor anything fetched at install time.f"Add a line `@AGENTS.md` to {os.path.join(project, 'CLAUDE.md')} (create the file "Fix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct."--expect-version", target], npxFix: Pin versions and sources; vendor anything fetched at install time.NPM_CLAUDE_FIX = "npm install -g @anthropic-ai/claude-code@latest --include=optional --allow-scripts=@anthropic-ai/claude-code"Fix: Pin the exact version (`[email protected]`, `==1.2.3`) so every install gets the bytes that were reviewed.it runs the install command with no console window and shows each step and the result. npx is looked up by theFix: Pin versions and sources; vendor anything fetched at install time.Cost to the agent
Tokens estimated at four characters each. The tool list is re-read by the agent on every turn, so it is the number to compare between servers that do the same job: ranked across the index.
Known vulnerabilities
No advisories in OSV for @allansantos-dev/smart-tool@0.9.71 as of 3d ago. This is the package itself, not its dependencies.
What would make this Verified
12 points to 80 · weights: behavior 45%, static 25%, prompt 15%, publisher 15%- Prompting user to enter sensitive credentials≈ +9 on the totalStop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.
- Unclaimed publisher≈ +8 on the totalClaim allansantos-dev: a verified publisher gets +50 on publisher trust. It is free and usually instant with GitHub sign-in.
- Access to sensitive file paths≈ +4 on the totalStop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.
- Auto-update or dynamic fetch configuration≈ +4 on the totalPin versions and sources; vendor anything fetched at install time.
- Python subprocess execution detected≈ +2 on the totalBuild commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.
- File type combined with upload action≈ +2 on the totalRemove the call, or declare the host in frontmatter and explain in the README what is sent and why.