- Implemented the OpenAI-compatible AI provider plugin, including configuration, chat, and chat_stream functionalities. - Added support for SSE streaming and tool calls. - Integrated Boost.JSON for JSON handling. - Created CMake configuration for the plugin. - Added error handling and logging throughout the plugin.
5.9 KiB
Security Logging Audit (W9.3): 错误日志凭证泄露审计
审计人: 曹武 (security-cao)
日期: 2026-05-27
审计范围: 8 个核心/插件源码文件
结论: 未发现真实凭证泄露漏洞(CVSS 不适用,零高危/中危/低危可利用漏洞)
审计方法论
对每个文件搜索以下输出调用:
host->log(...)/g_host->log(...)(插件日志 API)printf/fprintf(stderr, ...)(C 标准输出)std::cerr/std::cout(C++ 标准流)
对每个匹配项检查其格式字符串和参数是否包含 api_key、Authorization header、token 或原始 request body/headers。
文件清单
1. plugins_upper/openai/src/openai_plugin.cpp -- 安全
| 行号 | 调用 | 内容 | 风险 |
|---|---|---|---|
| 242-245 | g_host->log(INFO, ...) |
输出 model / base_url / max_tokens / temperature | 无 -- api_key 被有意排除在格式字符串外 |
| 442 | g_host->log(ERROR, ...) |
静态字符串 "http service not found" | 无 |
| 446 | g_host->log(INFO, ...) |
静态字符串 "initializing OpenAI-compatible AI plugin" | 无 |
| 453 | g_host->log(INFO, ...) |
静态字符串 "shutdown" | 无 |
build_headers_json() (行 59-63): 构建 {"Authorization":"Bearer <key>"} 并传给 HTTP 服务。该字符串从未传递给任何 log 调用,仅在 http_post_json() / http_post_stream() 的参数链中使用,最终由 Beast 直接设置到 HTTP request headers -- 全程无日志记录。
parse_response() 错误路径 (行 135-151): HTTP 错误响应体仅用于提取 JSON error.message 字段放入 r.error,不会输出到日志。原始 response_body 在解析后被 g_host->free() 释放。
2. plugins_upper/anthropic/src/anthropic_plugin.cpp -- 安全
| 行号 | 调用 | 内容 | 风险 |
|---|---|---|---|
| 247-250 | g_host->log(INFO, ...) |
输出 model / base_url / max_tokens / temperature | 无 -- api_key 被有意排除 |
| 453 | g_host->log(ERROR, ...) |
静态字符串 "http service not found" | 无 |
| 457 | g_host->log(INFO, ...) |
静态字符串 "initializing Anthropic AI plugin" | 无 |
| 464 | g_host->log(INFO, ...) |
静态字符串 "shutdown" | 无 |
build_headers_json() (行 59-65): 构建 {"x-api-key":"<key>","anthropic-version":"2023-06-01"} 仅用于 HTTP 请求,不经过日志路径。
3. plugins_middle/network/src/network_plugin.cpp -- 安全
| 行号 | 调用 | 内容 | 风险 |
|---|---|---|---|
| -- | 无任何 host->log / printf / cerr 调用 |
-- | 无 |
parse_headers_json() (行 40-80): 解析包含 api_key 的 headers JSON 字符串。解析结果仅用于 req.set(h.first, h.second) (行 176) 设置 HTTP header,不输出日志。
do_post_stream() 异常路径 (行 280-282): catch (std::exception& e) 将 e.what() 赋值给 result_body。Beast/ASIO 异常消息为 OS 级别错误描述(如 "Connection refused"),不含 HTTP header/body 内容。
4. plugins_base/config/src/config_plugin.cpp -- 安全
| 行号 | 调用 | 内容 | 风险 |
|---|---|---|---|
| -- | 无任何日志调用 | -- | 无 |
ConfigStore 仅提供 get/set/load_file,无日志输出。
5. dstalk_core/src/host.cpp -- 基础设施(不动)
| 行号 | 调用 | 内容 | 风险 |
|---|---|---|---|
| 48,51,52 | fprintf(stderr, ...) |
日志前缀 + vfprintf(格式,参数) + 换行 | 无 -- 基础设施自身不包含业务数据 |
该文件是日志基础设施 (host_log_impl),仅负责格式化输出。安全性依赖于调用方不传敏感数据(本审计已确认所有调用方均安全)。按 W9.3 禁忌不修改此文件。
6. dstalk_core/src/plugin_loader.cpp -- 安全
| 行号 | 调用 | 内容 | 风险 |
|---|---|---|---|
| -- | 无任何日志调用 | -- | 无 |
7. plugins_middle/session/src/session_plugin.cpp -- 安全
| 行号 | 调用 | 内容 | 风险 |
|---|---|---|---|
| 233 | host->log(ERROR, ...) |
静态字符串 "required service 'file_io' not found" | 无 |
该插件处理消息内容(role/content)但不记录任何消息数据到日志。
8. plugins_base/lsp/src/lsp_plugin.cpp -- 低风险
| 行号 | 调用 | 内容 | 风险 |
|---|---|---|---|
| 446 | g_host->log(ERROR, ...) |
静态字符串 "Invalid LSP frame..." | 无 |
| 479 | g_host->log(ERROR, ...) |
"failed to start: %s", server_cmd |
低 -- 理论上 server_cmd 可能含令牌,但实际为 LSP 服务器路径(如 clangd),不属于 API 密钥范畴 |
| 525 | g_host->log(ERROR, ...) |
静态字符串 "initialize timed out" | 无 |
| 535 | g_host->log(INFO, ...) |
"server started: %s", server_cmd |
低 -- 同上 |
| 565 | g_host->log(INFO, ...) |
静态字符串 "server stopped" | 无 |
| 720 | g_host->log(INFO, ...) |
静态字符串 "initializing LSP service plugin" | 无 |
| 728 | g_host->log(INFO, ...) |
静态字符串 "shutdown" | 无 |
server_cmd 是启动 LSP 子进程的命令行(例如 clangd --log=error),不是 API 密钥或 token。若用户将 API key 嵌入命令行(极不寻常且不安全的使用方式),则存在理论泄漏风险。判断为低风险/假阳性,不做代码修改。
总结
| 风险等级 | 数量 | 说明 |
|---|---|---|
| 严重 (CVSS 9.0+) | 0 | 无 |
| 高危 (CVSS 7.0-8.9) | 0 | 无 |
| 中危 (CVSS 4.0-6.9) | 0 | 无 |
| 低危 (CVSS 0.1-3.9) | 0 | 无真实可利用漏洞 |
| 低风险/假阳性 | 2 | 仅 lsp server_cmd 日志和 network e.what() 理论上可能暴露非凭证信息 |
审计结论: 所有日志输出路径均已检查,证实 OpenAI-compatible 和 Anthropic 插件的 my_configure() 日志有意排除了 api_key 字段。HTTP headers 中的凭证仅通过内存传递至 Beast HTTP 请求对象,从未进入日志管道。代码库对此攻击面防御充分,无需修改。