我自己机器上查了一下,253 个 Claude Code 会话记录里,有 16 个出现过 mysql -p 密码、curl -u user:pass 这类写法。顺手看了下 AI 跑这种命令时 ps 里是什么样,发现比我以为的多了一层。
今天在 Mac 上复现( Claude Code 2.1.317 ):让它跑一条带假密码的 curl ,另起一个进程抓 ps:
54958 64286 /bin/zsh -c source ~/.claude/shell-snapshots/… && eval 'curl -s -m 8 -u demo:FAKEPASS123 http://10.255.255.1/' …
54959 54958 curl -s -m 8 -u http://10.255.255.1/
(中间加载环境的一大段我删了)
下面那行是 curl 自己,密码那几位已经被它抹成空格了,curl 确实有做这件事。上面那行是 Claude Code 起的 zsh ,整条命令连密码都在,curl 跑多久它就挂多久。
有个细节:你自己 bash -c 'curl ...' 只跑一条命令的话,bash 会直接 exec 成 curl ,看不到这一层。Claude Code 是把命令包在 source 快照 && ... && eval '你的命令' 里,是复合命令,shell 得留着等它跑完,这份就一直在。
除了 ps ,命令还会原样写进 ~/.claude/projects/ 下面的会话记录( jsonl )。
服务器上更要留意。Linux 默认挂载参数下,proc(5) 写的是 "everybody may access all /proc/pid directories",同机其他用户能看到你的命令行。环境变量反而不一样,读 /proc/pid/environ 要过 ptrace 的权限检查。共用开发机、跳板机的可以注意下。
各家文档其实早就劝过:
- MySQL:命令行里
-p 密码方便但不安全;MYSQL_PWD被写成"极不安全",8.4 已经标了弃用 - PostgreSQL:不推荐
PGPASSWORD,让用~/.pgpass,权限比 0600 宽它直接不读 - curl:
-u能藏就藏,但手册自己也说这不够防同机其他用户 - redis-cli 带
-a会自己打一行警告
说的都是一件事:别放参数里,放权限 600 的配置文件。
自查,只数数量,不打印内容:
P='(mysql|mysqldump|mysqladmin)[^"\\]* -p[^ "\\]|redis-cli[^"\\]* -a [^ "\\]|curl[^"\\]* (-u|--user) [^ "\\:]+:[^ "\\]|PGPASSWORD=[^ $"\\]'
# 有命中的 Claude Code 会话数
grep -lE -- "$P" ~/.claude/projects/*/*.jsonl 2>/dev/null | wc -l
# shell 历史里的行数
cat ~/.zsh_history ~/.bash_history 2>/dev/null | grep -acE -- "$P"
我这边是会话 16 个、shell 历史 8 行。正则比较粗,会漏也会误报,不是 0 就值得翻一下。
不装任何东西的改法:
~/.my.cnf、~/.pgpass各自配好,chmod 600CLAUDE.md/AGENTS.md里加一句:密钥不要出现在命令参数里,用客户端自己的配置文件- 已经进过会话的密码直接换掉。删 jsonl 没用,那段已经发给模型了
我现在用的是自己做的小密盾,让 AI 跑 rootkey run "订单库" --env-var PGPASSWORD -- psql ...,值只进那个子进程的环境变量,ps 和会话记录里只有条目名。也不是银弹:MySQL 官方更推荐的还是 600 的配置文件;同一个用户下跑的恶意程序照样能读你的环境变量和文件。
大家让 AI 连库现在是怎么给密码的?