registry  /  @tianshu-ai/tianshu  /  0.4.27

@tianshu-ai/tianshu@0.4.27

An open AI agent platform with a sidecar browser. Built in public.

AI Security Review

scanned 4d ago · by lpm-firewall-ai

No confirmed malicious attack surface is established. The package is an AI agent platform with explicit CLI setup, sandbox execution, web fetch, update, and WeChat media-upload capabilities that align with its stated functionality.

Static reason
One or more suspicious static signals were detected.; previous stored version diff introduced dangerous source
Trigger
User invokes tianshu CLI commands, setup/update flows, plugin tools, or workboard tasks
Impact
Powerful local/sandbox operations may run by user request, but no unconsented install-time or hidden attack behavior was found
Mechanism
user-invoked service setup and sandboxed agent/plugin execution
Rationale
Static inspection shows suspicious primitives are explicit product features: a CLI-managed local service, sandboxed agent execution, guarded web fetching, updater, and WeChat media upload. There is no install-time execution, hidden persistence, credential harvesting, or unconsented AI-agent control-surface mutation.
Evidence
package.jsonbin/tianshu.mjsbin/serve.mjspackages/server/dist/cli.jspackages/server/dist/setup/start-server.jspackages/server/dist/setup/launchd.jspackages/server/dist/setup/service.jspackages/server/dist/setup/update.jsplugins/workboard/dist/worker/opencode-worker.jsplugins/web-search/dist/tools/web-fetch.jsplugins/wechat/dist/ilink-media.js~/.tianshu/.env~/Library/LaunchAgents/ai.tianshu*.plist~/Library/Logs/tianshu/*.logopencode/<taskId>/opencode.jsonopencode/<taskId>/.prompt.txt
Network endpoints3
registry.npmjs.orgnovac2c.cdn.weixin.qq.com/c2copencode.ai/config.json

Decision evidence

public snapshot
AI called this Clean at 88.0% confidence as Benign with medium false-positive risk.
Evidence for block
  • plugins/workboard/dist/worker/opencode-worker.js installs/runs opencode-ai@1.17.13 in a tenant shell sandbox for workboard tasks
  • packages/server/dist/setup/start-server.js and launchd.js write ~/Library/LaunchAgents plist and .env during explicit setup/start flow
  • plugins/wechat/dist/ilink-media.js reads a caller-supplied file path and uploads encrypted media to WeChat/iLink endpoints
  • packages/server/dist/setup/update.js can run npm install -g during explicit tianshu update
Evidence against
  • package.json has no consumer install hook; prepublishOnly only runs before publishing
  • bin/tianshu.mjs is a thin CLI shim that imports packages/server/dist/cli.js only when invoked
  • web-fetch.js explicitly blocks localhost, private, link-local, and cloud metadata hosts before fetch and after redirect
  • launchd persistence is prompted/user-invoked via setup/start commands, not install-time or import-time
  • OpenCode proxy token is per-task and revoked in finally; real LLM key/baseUrl are not written into sandbox
  • No credential harvesting, hidden exfiltration, destructive behavior, or reviewer/prompt manipulation found in inspected files
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemNativeBindingsNetworkShellWebSocket
Supply chain
HighEntropyStringsMinifiedObfuscatedProtestwareUrlStrings
Manifest
WildcardDependency
scanned 333 file(s), 8.15 MB of source, external domains: 127.0.0.1, api.anthropic.com, api.openai.com, dashscope.aliyuncs.com, example.com, generativelanguage.googleapis.com, github.com, host.docker.internal, host.openshell.internal, ilinkai.weixin.qq.com, mcp.exa.ai, novac2c.cdn.weixin.qq.com, opencode.ai, raw.githubusercontent.com, react.dev, reactrouter.com, registry.npmjs.org, search.parallel.ai, www.apple.com, www.docker.com, www.w3.org

Source & flagged code

5 flagged · loading source
bin/tianshu.mjsView file
29L30: const { main } = await import(distEntry); L31: const code = await main(process.argv.slice(2));
Medium
Dynamic Require

Package source references dynamic require/import behavior.

bin/tianshu.mjsView on unpkg · L29
plugins/wechat/dist/ilink-media.jsView file
18// L19: // The CDN URL itself is `https://novac2c.cdn.weixin.qq.com/c2c` L20: // (platform constant, matches what Tencent's plugin hard-codes). ... L76: }); L77: const resp = JSON.parse(raw); L78: if (resp.ret && resp.ret !== 0) { ... L92: headers: { "Content-Type": "application/octet-stream" }, L93: body: new Uint8Array(opts.ciphertext), L94: });
Low
Weak Crypto

Package source references weak cryptographic algorithms.

plugins/wechat/dist/ilink-media.jsView on unpkg · L18
packages/server/dist/setup/start-server.jsView file
21import fs from "node:fs"; L22: import net from "node:net"; L23: import os from "node:os"; ... L36: // typically run `tianshu setup` from their home dir, so L37: // process.cwd() won't be the repo. Walk up from this module's L38: // location until we hit a package.json named L39: // '@tianshu-ai/tianshu' (or run out of parents). ... L50: ? path.join(repoRoot, ".env") L51: : path.join(process.env.TIANSHU_HOME ?? L52: path.join(process.env.HOME ?? "", ".tianshu"), ".env")); ... L137: if (!r.ok) { L138: p.log.error(`launchctl kickstart failed: ${r.stderr ?? "(unknown)"}`);
Medium
Install Persistence

Source writes installer persistence such as shell profile or service configuration.

packages/server/dist/setup/start-server.jsView on unpkg · L21
plugins/web-search/dist/tools/web-fetch.jsView file
1// `web_fetch(url, extractMode?, maxChars?)`. L2: // ... L14: // L15: // SSRF: we block private / loopback / link-local / metadata hosts L16: // before fetching AND re-check after redirects, so an agent can't ... L93: const ctype = res.headers.get("content-type") ?? ""; L94: const body = await res.text(); L95: let out; ... L110: text, L111: data: { L112: url,
High
Cloud Metadata Access

Source reaches cloud instance metadata or link-local credential endpoints.

plugins/web-search/dist/tools/web-fetch.jsView on unpkg · L1
plugins/workboard/dist/worker/opencode-worker.jsView file
matchType = previous_version_dangerous_delta matchedPackage = @tianshu-ai/tianshu@0.4.25 matchedIdentity = npm:QHRpYW5zaHUtYWkvdGlhbnNodQ:0.4.25 similarity = 0.992 summary = stored previous version shares package body but lacks this dangerous source file
Critical
Previous Version Dangerous Delta

This package version adds a dangerous source file absent from the previous stored version.

plugins/workboard/dist/worker/opencode-worker.jsView on unpkg

Findings

1 Critical1 High7 Medium7 Low
CriticalPrevious Version Dangerous Deltaplugins/workboard/dist/worker/opencode-worker.js
HighCloud Metadata Accessplugins/web-search/dist/tools/web-fetch.js
MediumDynamic Requirebin/tianshu.mjs
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencepackages/server/dist/setup/start-server.js
MediumProtestware
MediumStructural Risk Force Deep Review
MediumWildcard Dependency
LowNon Install Lifecycle Scripts
LowScripts Present
LowWeak Cryptoplugins/wechat/dist/ilink-media.js
LowFilesystem
LowObfuscated
LowHigh Entropy Strings
LowUrl Strings