Announcing Beacon: Self-improving memory for coding agents
← All skills
Skill

add-tavily-tool

skill:nanocoai/nanoclaw#add-tavily-tool

Add Tavily Search and Extract as keyless remote MCP tools for selected NanoClaw agent groups. Use when installing Tavily web search or URL extraction without an API key.

Verdict
Suspicious

Risky behavior the analysis could not rule out.

Analyzed Oct 27, 2026, 22:12 UTC at acc2b1c

Dispute security verdict

If you believe this verdict is incorrect, submit a dispute and we'll review it.

1
findings
high
highest severity
1
threat classes
1,343
files scanned
348/354
checks satisfied
0
package advisories

Why this verdict

  • suspicious: unverified finding skill:.claude/skills/add-tavily-tool:container/agent-runner/src/providers/claude-history.ts:58:EXFIL

Security findings 1

Data exfiltration

highUnverifiedlow confidence

newestClaudeTranscript() walks ~/.claude/projects and returns the newest Claude transcript path, declared as the history.readTrace source for an /upload-trace surface whose remote destination is not shown in the available content.

return best?.path ?? null;
vector:code

Open questions 19

What the analysis could not settle from the code alone.

Whether the HTML-comment-wrapped block injected into groups/<group-folder>/instructions.prepend.md is rendered invisibly to the human operator or read only in raw form by the agent (functional idempotency markers vs concealment).
Does NanoClaw's container isolation actually bound the agent running with permissionMode 'bypassPermissions' and allowDangerouslySkipPermissions true, as the in-code comment claims?
Privilege escalation
The provider declares newestClaudeTranscript (~/.claude/projects scan) for a /upload-trace surface; is the returned transcript path/content sent off-host by that surface, and to what destination?
Data exfiltration
No shown unit contains any Tavily or remote-MCP registration despite the target's declared description; whether the skill's actual instructions (appending to cli-tools.json and running build.sh, or writing MCP config) match the declared purpose cannot be settled from these units.
[file request .claude/skills/add-onecli/payload/docs/onecli-upgrades.md] Does the OneCLI upgrade document contain only documented upgrade steps, or does it instruct execution, downloads, or configuration changes beyond the declared Tavily install purpose?
Supply chain
[file request container/pull.sh] Which registry and repository does pull.sh pull the agent image from, is the reference pinned by digest or resolved by a mutable tag, and does it verify the dev.nanoclaw.agent-runner-lock-sha256 label against the checkout's bun.lock sha256 before retagging it as the local build tag?
Supply chain
[file request container/agent-runner/src/providers/claude.ts] Where is the /upload-trace surface implemented and what remote destination receives the transcript path or content returned by newestClaudeTranscript?
Data exfiltration
[file request container/agent-runner/src/providers/claude.ts] When the provider registers MEMORY_SESSION_HOOK, what exactly is written into Claude settings.json, and does that write touch permission, allowlist, or other hook settings beyond the memory hook command and sources?
Persistence
[file request container/install-cli-tools.sh] What does install-cli-tools.sh, which the build overlay runs as root inside the image, install for each cli-tools.json entry, and does it fetch anything unpinned or from a non-official registry?
Supply chain
[file request container/Dockerfile] Which base image and tag does the full docker build use, and is that remote image reference pinned by digest or a mutable tag?
Supply chain
[file request container/install-cli-tools.sh] What does the overlay install script run for each cli-tools.json entry (registry, pinned install, build-script handling), and can it download or execute remote or unpinned code at build time?
Code execution
[file request docs/onecli-upgrades.md] SKILL.md Phase 5, check-grants-gateway.sh, and upgrade-instructions.md all direct the agent or user to docs/onecli-upgrades.md for gateway/CLI upgrades; does that file contain only documented upgrade steps, or does it instruct execution, download, or configuration changes beyond the declared Tavily install purpose?
Supply chain
[file request container/pull.sh] Which registry, repository, and tag or digest does container/pull.sh acquire the agent image from, and is the source pinned or verified against the checkout lock label before it is retagged as the local build tag?
Supply chain
[file request container/agent-runner/src/memory/session-hook.ts] What does the memory session hook write into Claude settings.json, and does that write touch permission, allowlist, or hook settings beyond injecting the shared memory tree?
Persistence
[file request container/pull.sh] Which registry or URL does pull.sh fetch the agent image from, and is the pulled reference pinned by digest or checksum-verified, or mutable by tag?
Supply chain
[file request docs/onecli-upgrades.md] Do the OneCLI upgrade instructions that the skill defers to (gateway and CLI upgrade, post-upgrade check) fetch code from remote URLs or execute downloaded content?
Code execution
[file request container/agent-runner/src] Where is the /upload-trace surface implemented and what remote destination receives the transcript path/content returned by newestClaudeTranscript?
Data exfiltration
[file request container/pull.sh] What registry or URL does container/pull.sh fetch the agent image from, how is the tag resolved, and what integrity checks (e.g. the agent-runner lock-sha256 label comparison referenced by build.sh) does it apply before retagging the image the host runs?
Supply chain
[file request container/Dockerfile] What base image and RUN instructions does the container Dockerfile use for the full build path, and does it download or execute any content from remote or unpinned sources at build time?
Supply chain
Refuted findings 9

Candidates the review stage examined and rejected, kept for transparency.

Persistence

criticalRefutedmedium confidence

The skill instructs the agent to substitute values into upgrade-instructions.md and write the resulting block into each selected group's groups/<group-folder>/instructions.prepend.md, installing standing instructions that make group agents persistently offer a Tavily paid-key upgrade until removed.

`groups/<group-folder>/instructions.prepend.md`
Why it was refuted

The persistence is the skill's openly declared Phase 5 feature: the write target, the HTML-comment markers as documented idempotent replacement delimiters, and removal (REMOVE.md) are all stated in the artifact, so the conceal:markup/undeclared premise fails even though the write occurs.

Code execution

criticalRefutedmedium confidence

The skill instructs the agent to execute a shell script from a different skill's dot-directory (.claude/skills/add-onecli/scripts/check-grants-gateway.sh) whose body is not shown in the evidence and whose 'Reads only' self-description is an unverifiable status claim.

sh .claude/skills/add-onecli/scripts/check-grants-gateway.sh /add-tavily-tool
Why it was refuted

The script's full body is in the shown evidence (SRC:efeffd9d09ea59ee, among the finding's own citations) and performs only read-only checks (config read, /api/health GET, agents list, version echo) with no writes, so the 'body not shown / unverifiable' premise is false and the exec is benign.

Credential access

criticalRefutedlow confidence

SKILL.md Phase 5 instructs dumping the onecli container's full environment via docker inspect to extract APP_URL, reading container environment variables beyond the single value that is used.

docker inspect onecli --format '{{range .Config.Env}}{{println .}}{{end}}' | grep '^APP_URL='
Why it was refuted

The inspect output is piped through grep '^APP_URL=', so the only value surfaced to the agent is the dashboard URL that the declared APP_URL flow exists to resolve; no credential is exposed, so no CRED harm and the lookup is part of the declared flow.

Persistence

criticalRefutedmedium confidence

The persisted template conditions a future agent on Tavily HTTP 429 responses and directs it to steer the user into saving a Tavily Authorization secret through a prefilled OneCLI dashboard deeplink and then re-registering the Tavily MCP server with that credential attached.

Open this link and paste the key into the prefilled form, then save:
Why it was refuted

The block is the declared upgrade template (D24-D26 quote its steps verbatim, and SKILL.md's keyless-limit section declares the re-registration), and its own text keeps the agent out of credential handling, so the conditional steering is neither concealed nor undeclared.

Credential access

criticalRefutedmedium confidence

The persistent upgrade block installed by the skill instructs the agent to run onecli agents grants attach-secret to attach the operator's saved Tavily API key from the OneCLI credential vault to the agent group, giving the group's agents access to the stored credential.

onecli agents grants attach-secret --id
Why it was refuted

The attach step is the declared design (SKILL.md's keyless-limit section names the one-liner and says the gateway injects the key into bridge requests), and the artifact mitigates agent credential access outright: the agent never sees the key.

Privilege escalation

criticalRefutedmedium confidence

The repository's Claude provider runtime comments state that the SDK's own permission prompts are disabled for every agent group (corroborated by detector hits citing bypassPermissions at lines 94 and 100), relying on container isolation and the OneCLI allow-list as the boundary instead.

Claude runs unrestricted inside the container: NanoClaw's container
Why it was refuted

The cited text is a code comment that openly declares the security model — container isolation plus the OneCLI allow-list as the boundary — so nothing is concealed, and broad runtime permissions alone are a carve-out.

Privilege escalation

criticalRefutedhigh confidence

The NanoClaw Claude provider's resolveClaudeExecutionPolicy returns permissionMode 'bypassPermissions' and allowDangerouslySkipPermissions true for every group unconditionally, with flag-level settings that outrank the groups' own settings files, so no SDK permission prompt, consent, or approval mechanism is preserved.

permissionMode: 'bypassPermissions',
Why it was refuted

Unconditional bypassPermissions for headless, containerized agents is broad permissions alone — the immediately preceding comment declares container isolation and the OneCLI allow-list as the boundary — and the design is stated openly, so neither harm nor undeclared survives.

Credential access

highRefutedlow confidence

Undeclared residue: the agent runner's newestClaudeTranscript() enumerates every project directory under ~/.claude/projects and stats each .jsonl transcript (sensitive conversation data), a read the declared Tavily-install purpose does not need, though open comments tie it to /upload-trace diagnostics.

fs.readdirSync(projects)
Why it was refuted

The enumeration stats only metadata (mtimes) of the runner's own transcripts — no credential content is read — and the read is openly declared on the runtime contract for the /upload-trace diagnostic, so it is neither a credential read nor undeclared residue.

Supply chain

highRefutedmedium confidence

The install script writes /root/.npmrc with only-built-dependencies opt-ins so that manifest packages run their postinstall build scripts during the root-stage container image build — an install-time code-execution capability not covered by the skill's declared description, mitigated only by exact-pinned versions and container scoping.

require(
Why it was refuted

The script installs exact-pinned packages from the registry via pnpm and documents the onlyBuilt opt-in in its own header, so enabling build scripts for the two pinned official tools falls under the pinned official-registry-install carve-out and is not concealed.

Coverage gaps 17

Parts of the artifact the static analysis could not fully examine.

context:unanalyzable_binary binary content is only byte-scanned
.claude/skills/add-clidash/add/tools/clidash/public/favicon.ico
context:unanalyzable_binary binary content is only byte-scanned
src/drivers/docker-driver.ts
no_dataflow_for_dynamic_code line 28: invoked code is not structurally extracted
.claude/skills/add-onecli/scripts/check-grants-gateway.sh
no_dataflow_for_dynamic_code line 17: invoked code is not structurally extracted
container/install-cli-tools.sh
no_dataflow_for_dynamic_code line 26: invoked code is not structurally extracted
container/install-cli-tools.sh
ledger_finding_without_valid_finding run 1: declared-vs-actual.2 SRC:50939d20b339dd5e
ledger_finding_without_valid_finding run 1: behavior-chains.1 SRC:c5ff26f8ce57c100
ledger_finding_without_valid_finding run 1: behavior-chains.1 SRC:50939d20b339dd5e
ledger_finding_without_valid_finding run 1: behavior-chains.1 SRC:ddcd48d148d55391
ledger_finding_without_valid_finding run 1: behavior-chains.1 SRC:34bdcf0875154bc8
ledger_finding_without_valid_finding run 1: behavior-chains.1 SRC:f323c85a34561fdf
invalid_judge_finding declared-vs-actual.0
invalid_judge_finding declared-vs-actual.2
invalid_judge_finding behavior-chains.1
request_unanswered request.2: request.0/req-install-cli-tools-sh: finding: no valid finding cites the answer's evidence
request_unanswered request.2: request.1/install-cli-tools-sh: finding: no valid finding cites the answer's evidence
invalid_judge_finding request.2