.agents/issue/ssrf-vulnerability-fix.md
漏洞编号: GHSA-6g6x-8hq5-9cw4 漏洞类型: Server-Side Request Forgery (SSRF) - CWE-918 严重程度: High 影响版本: <= 4.8.22
FastGPT 的 HTTP Tool 连接器在处理用户控制的 URL 时缺乏 SSRF 保护:
受影响文件:
packages/service/core/app/http.ts (lines 127-166) - runHTTPTool() 函数projects/app/src/pages/api/core/app/httpTools/runTool.ts - API 端点问题代码:
export const runHTTPTool = async ({ baseUrl, toolPath, method, ... }) => {
const { data } = await axios({
method: method.toUpperCase(),
baseURL: baseUrl.startsWith('http') ? baseUrl : `https://${baseUrl}`,
url: toolPath,
// 没有任何 IP 验证!
});
};
isInternalAddress() 函数默认被禁用:
文件: packages/service/common/system/utils.ts (line 142)
if (process.env.CHECK_INTERNAL_IP !== 'true') {
return false; // 默认允许内部地址!
}
这意味着 http468 工作流节点和 readFiles 也缺乏 SSRF 保护,除非显式设置 CHECK_INTERNAL_IP=true。
认证用户可以使用 HTTP Tool 进行以下攻击:
AWS 凭证窃取:
baseUrl: http://169.254.169.254toolPath: /latest/meta-data/iam/security-credentials/Kubernetes 密钥泄露:
baseUrl: http://kubernetes.default.svctoolPath: /api/v1/namespaces/default/secrets/内部网络扫描和服务利用
修改文件: packages/service/core/app/http.ts
在 runHTTPTool 函数中,在发起请求前添加 URL 验证:
export const runHTTPTool = async ({
baseUrl,
toolPath,
method = 'POST',
params,
headerSecret,
customHeaders,
staticParams,
staticHeaders,
staticBody
}: RunHTTPToolParams): Promise<RunHTTPToolResult> => {
try {
// 构建完整 URL
const fullBaseUrl = baseUrl.startsWith('http://') || baseUrl.startsWith('https://')
? baseUrl
: `https://${baseUrl}`;
// SSRF 保护:验证 URL 是否指向内部地址
const fullUrl = new URL(toolPath, fullBaseUrl).toString();
if (await isInternalAddress(fullUrl)) {
return { errorMsg: 'Access to internal addresses is not allowed' };
}
const { headers, body, queryParams } = buildHttpRequest({
method,
params,
headerSecret,
customHeaders,
staticParams,
staticHeaders,
staticBody
});
const { data } = await axios({
method: method.toUpperCase(),
baseURL: fullBaseUrl,
url: toolPath,
headers,
data: body,
params: queryParams,
timeout: 300000
});
return { data };
} catch (error: any) {
return { errorMsg: getErrText(error) };
}
};
修改文件: packages/service/common/system/utils.ts
将默认行为从"允许"改为"拒绝":
// 3. 如果未启用内部 IP 检查,则默认拒绝(安全优先)
if (process.env.CHECK_INTERNAL_IP === 'false') {
return false; // 显式禁用检查时才允许
}
// 默认启用内部 IP 检查
注意: 这个改动可能影响向后兼容性,需要在文档中说明。
在 isInternalAddress 函数中,可以添加 DNS rebinding 保护:
这需要修改 axios 请求的方式,使用已解析的 IP 而不是域名。
runHTTPTool 中添加 isInternalAddress 验证CHECK_INTERNAL_IP 默认行为为启用CHECK_INTERNAL_IP 环境变量的变化创建测试文件: test/cases/service/core/app/http.test.ts
测试用例:
/api/core/app/httpTools/runToolCHECK_INTERNAL_IP 默认值变更:
影响范围:
CHECK_INTERNAL_IP=false 来恢复旧行为(不推荐)对于需要访问内部服务的合法用例:
CHECK_INTERNAL_IP=false(不安全,仅用于开发环境)CHECK_INTERNAL_IP=true(默认)