AI 生成的代码能跑,为什么不能直接上线?
不是"AI 代码不可信",而是"能跑"和"能上线"之间,少了一道能复现的检查。
我最近经常被问到的三类问题
最近聊技术时,总有人把 AI 生成代码的问题描述得很具体:
- "AI 帮我写的 API 已经能跑了,为什么你还建议上线前再查一遍?"
- "我自己扫了一遍,结果报了一堆,我怎么知道哪些是误报?"
- "外包代码准备交给客户,对方问有没有做过安全检查,我怎么证明?"
这三个问题其实是同一件事:代码有没有经过一套"自动扫描 + 人工确认"的可复现检查。
先说结论
- AI 能很快写出"功能正常"的代码,也可能很自然地写出
SQL 字符串拼接、pickle.loads、shell=True这类写法; - 上线前先做一轮本地自动扫描,扫描过程不要把代码上传给别人;
- 扫描结果不能直接当结论,要逐条人工确认;
- 检查不能只做一次,应该能生成基线、接进 CI,让后续改动继续被查。
下面是一个很典型的 AI 生成代码片段,功能上看起来没问题:
python
username = request.form["username"]
password = request.form["password"]
sql = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
cursor.execute(sql)
这段代码能执行查询,但它把用户输入直接拼进了 SQL 字符串。只看"能不能登录",这个问题会被漏掉。
我建议的第一步不是让人肉去搜代码,而是先跑一轮自动扫描:
bash
code-audit app --format html --output report.html
扫描在本地完成,不会把项目代码上传到云端。
如果项目中还有一段这样的代码:
python
encoded = request.args.get("data")
data = pickle.loads(base64.b64decode(encoded))
以及:
python
subprocess.run(command, shell=True)
扫描结果会按文件给出位置、规则名、级别和风险原因。
典型的第一轮结果:
| 级别 | 规则 | 原因 |
|---|---|---|
| High | sql-concat |
SQL 由 f-string 拼接生成,可能被注入 |
| High | pickle-loads |
反序列化不可信输入,可能执行危险代码 |
| High | eval-exec-subprocess |
使用 shell 执行动态命令 |
| Medium | raw-html-reflect |
用户输入直接反射到 HTML,可能需要编码 |
| Medium | unvalidated-file-path |
文件路径可能来自用户输入且未限制范围 |
二、看到结果后,我不会直接"全改"
自动扫描解决的是"哪里需要看",不负责替你下最终结论。
SQL 拼接
我会确认:
- 数据是从请求、上传文件还是外部数据库来;
- 最终是否进入 SQL 执行;
- 有没有参数化查询或白名单。
如果用户输入直接进入 cursor.execute(sql),那一般要先改成参数化查询,而不是只加关键字过滤。
pickle.loads
我会确认:
encoded是不是用户可控;- 反序列化数据是否来自上传、请求参数或第三方;
- 有没有更安全的序列化方案。
如果输入确实不可信,pickle.loads 就不应该出现在这里。
subprocess + shell=True
我会确认:
command里有没有用户输入;- 能不能改成参数列表形式;
- 当前运行环境是否已经限制了执行权限。
即使代码只是内部工具,shell=True 也会让问题更难排查,能避免就先避免。
三、误报怎么处理
启发式规则一定存在误报。比如规则只看"代码长得很像",不判断运行时真实数据流。
真正上线前,我会逐条看:
- 代码位置;
- 输入来源;
- 风险是否可被利用;
- 修复方式会不会破坏功能。
确认是误报后,可以用规则开关临时跳过,但前提是已经人工看过:
bash
code-audit app --skip-rule raw-html-reflect
不要因为"看着像误报"就直接把整类规则关掉。
四、把它变成以后能重复执行的流程
如果只是上线前扫一次,价值有限。
我会先生成基线:
bash
code-audit src --write-baseline baseline.json
以后每次改动只报告新增问题:
bash
code-audit src --baseline baseline.json
也可以把扫描接进 CI,发现 high 风险时直接失败:
bash
code-audit src --format sarif --output scan.sarif --fail-on high
这样"我检查过代码"就不再是一句话,而是一条可复现的流程。
这套流程的边界
- 它适合快速筛选常见高危写法,不代表"证明代码没有漏洞";
- 自动扫描结果必须人工确认;
- 它不做未授权渗透测试,也不能替代生产环境的动态安全测试;
- 只处理你拥有或明确授权的代码。
如果你也被这类问题卡住
遇到问题的人,通常已经卡在某个具体位置,而不是缺一句"要注意安全"。
如果你也在处理 AI 生成代码、外包接手代码或准备上线的项目,可以先按上面的流程跑一轮。需要继续判断时,沟通时带上这些信息会更快:
- 语言和框架;
- 代码是自己写的、AI 生成的,还是外包接手的;
- 大概代码量和准备上线的范围;
- 自动扫描结果或具体报错;
- 你需要的是一句话结论、修复建议,还是要一份可交付的确认记录。
不要在公开评论区直接贴完整代码、密钥或客户项目;只发脱敏后的片段和扫描结果即可。
这一步先做对,后面才是"这个项目应该怎么处理"。