Async import of the appStore packages - #1
Conversation
There was a problem hiding this comment.
审查摘要
- packages/app-store/_utils/getCalendar.ts: 发现动态属性访问未校验 calendarType,存在路径遍历风险,已委托深审并确认。
- packages/app-store/wipemycalother/lib/reschedule.ts: 发现 forEach 中使用 async 回调但未等待完成,可能导致异步操作被丢弃,已委托深审并确认。
- 其余文件:batch 审计通过,无高危问题。
由 CodeHawk 提供支持 · nuwa
| calendarType = calendarType.split("_other_calendar")[0]; | ||
| } | ||
| const calendarApp = appStore[calendarType.split("_").join("") as keyof typeof appStore]; | ||
| const calendarApp = await appStore[calendarType.split("_").join("") as keyof typeof appStore]; |
There was a problem hiding this comment.
🔴 AI 代码审查发现问题
📋 问题概述
在动态属性访问中,未对 calendarType 的值进行充分校验。如果 calendarType 包含恶意构造的字符串(如特殊字符或非法路径),可能导致模块加载失败、任意模块导入或执行,存在代码注入和路径遍历风险。
split("_").join("")操作也可能因输入异常导致拼接错误,引发运行时错误。
📍 问题详情
🔴 问题 1 | 严重程度: HIGH | 行号: 15
💬 详细说明:
- 攻击者可利用此漏洞访问或执行 appStore 中的任意模块,可能导致服务器端请求伪造、远程代码执行或其他未授权操作。
📝 问题代码:
const calendarApp = await appStore[calendarType.split("_").join("") as keyof typeof appStore];
💡 修复建议:
在使用 calendarType 构造键名前,应验证其是否为预定义的有效类型之一。建议维护一个白名单列表,仅允许已知合法的 calendar 类型通过。同时,确保
appStore中的键名与实际模块路径严格对应,避免任意字符串拼接导致的不安全访问。
✅ 修复示例:
const validCalendarTypes = new Set(['applecalendar', 'caldavcalendar', 'closecom', 'dailyvideo', 'googlecalendar', 'googlevideo', 'hubspot', 'huddle01video', 'jitsivideo', 'larkcalendar', 'office365calendar', 'office365video', 'plausible', 'salesforce', 'zohocrm', 'sendgrid', 'stripepayment', 'tandemvideo', 'vital', 'zoomvideo', 'wipemycalother', 'giphy', 'zapier', 'exchange2013calendar', 'exchange2016calendar', 'exchangecalendar', 'facetime', 'sylapsvideo']);
const normalizedType = calendarType.split('_').join('');
if (!validCalendarTypes.has(normalizedType)) {
log.warn(`Invalid calendar type: ${calendarType}`);
return null;
}
const calendarApp = await appStore[normalizedType as keyof typeof appStore];
🔗 参考链接
无
| ); | ||
| try { | ||
| bookingRefsFiltered.forEach((bookingRef) => { | ||
| bookingRefsFiltered.forEach(async (bookingRef) => { |
There was a problem hiding this comment.
🟡 AI 代码审查发现问题
📋 问题概述
使用 forEach 遍历数组并执行异步操作,但 forEach 不会等待异步任务完成,导致所有异步操作被丢弃,无法捕获异常,造成资源泄漏或逻辑失败。
📍 问题详情
🟡 问题 1 | 严重程度: MEDIUM | 行号: 125
💬 详细说明:
- 使用 forEach 遍历数组并执行异步操作,但 forEach 不会等待异步任务完成,导致所有异步操作被丢弃,无法捕获异常,造成资源泄漏或逻辑失败。
📝 问题代码:
bookingRefsFiltered.forEach(async (bookingRef) => {
💡 修复建议:
将 forEach 替换为 for...of 循环,并在每次迭代中使用 await 等待异步操作完成,确保每个任务都被正确执行和错误处理。
✅ 修复示例:
for (const bookingRef of bookingRefsFiltered) {
if (bookingRef.uid) {
if (bookingRef.type.endsWith('_calendar')) {
const calendar = await getCalendar(credentialsMap.get(bookingRef.type));
if (calendar) {
await calendar.deleteEvent(bookingRef.uid, builder.calendarEvent);
}
} else if (bookingRef.type.endsWith('_video')) {
await deleteMeeting(credentialsMap.get(bookingRef.type), bookingRef.uid);
}
}
}
🔗 参考链接
无
| ); | ||
| try { | ||
| bookingRefsFiltered.forEach((bookingRef) => { | ||
| bookingRefsFiltered.forEach(async (bookingRef) => { |
There was a problem hiding this comment.
🔴 AI 代码审查发现问题
📋 问题概述
在 forEach 中使用 async 回调但未等待其完成,导致异步操作可能未执行完毕就继续执行后续逻辑。这可能导致日历或视频会议取消失败,且错误处理不完整(catch 块仅捕获外层异常,无法捕获内部 async 错误)。此外,若多个并发请求失败,仅记录第一个错误,其余被忽略。
📍 问题详情
🔴 问题 1 | 严重程度: HIGH | 行号: 125
💬 详细说明:
- 日历事件可能不会被正确删除,导致数据不一致;异步操作未完成可能导致资源泄漏和竞态条件,存在安全风险。
📝 问题代码:
bookingRefsFiltered.forEach(async (bookingRef) => {
💡 修复建议:
将 forEach 替换为 for...of 遍历,并使用 await 等待每个异步操作完成;或使用 Promise.allSettled 处理所有异步任务并统一处理结果,确保所有取消操作都被正确执行和监控。
✅ 修复示例:
const promises = bookingRefsFiltered.map(async (bookingRef) => {
if (bookingRef.uid) {
if (bookingRef.type.endsWith("_calendar")) {
const calendar = await getCalendar(credentialsMap.get(bookingRef.type));
return calendar?.deleteEvent(bookingRef.uid, builder.calendarEvent);
} else if (bookingRef.type.endsWith("_video")) {
return deleteMeeting(credentialsMap.get(bookingRef.type), bookingRef.uid);
}
}
});
await Promise.allSettled(promises);
🔗 参考链接
无
What does this PR do?
Async imports of all apps