关于 ln-628-concurrency-auditor
ln-628-concurrency-auditor 是用于审计并发、异步模式和跨进程资源访问的技能。它采用两层检测,并向协调器提交带评分的发现结果。
主要功能
- 01检查异步竞态
- 02检查线程与 goroutine 安全
- 03检测 TOCTOU 和死锁
- 04查找异步代码中的阻塞 I/O
- 05检查资源争用
- 06分析跨进程竞态
适用场景
- 01检查并发代码中的竞态条件
- 02调查跨进程共享资源访问
MCP 相关
该技能可使用 hex-graph 进行数据流或调用路径分析,并使用 hex-line 读取局部代码。若这些 MCP 工具不可用或不适用,则改用内置文件与搜索工具。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ levnikolaevich/ claude-code-skills --skill ln-628-concurrency-auditor安装后在 Claude Code 中输入/ln-628-concurrency-auditor确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/audit_output_schema.mdaudit_scoring.mdaudit_summary_contract.mdaudit_worker_core_contract.mdcleanup_evidence_contract.mdevaluation_coordinator_runtime_contract.mdevaluation_parallelism_policy.mdevaluation_research_contract.mdevaluation_summary_contract.mdevaluation_worker_runtime_contract.mdloop_health_contract.mdmcp_integration_patterns.mdmcp_tool_preferences.mdrefinement_trace_contract.mdtwo_layer_detection.mdreferences/scripts/evaluation-runtime/cli.mjsreferences/templates/audit_worker_report_template.md详细介绍
路径: 文件路径(
references/、../ln-*)均相对于此技能目录。
并发审计员(L3 Worker)
类型: L3 Worker
专门审计并发、异步模式和跨进程资源访问的 Worker。
目的与范围
- 审计并发(类别 11:高优先级)
- 7 项检查:异步竞态、线程安全、TOCTOU、死锁、阻塞 I/O、资源争用、跨进程竞态
- 双层检测:grep 查找候选项,Agent 根据上下文进行判断
- 计算合规评分(X/10)
输入
必须阅读: 加载 references/audit_worker_core_contract.md。
必须阅读: 加载 references/mcp_tool_preferences.md 和 references/mcp_integration_patterns.md
接收包含以下内容的 contextStore:tech_stack、best_practices、codebase_root、output_dir。
如果数据流或调用路径分析能实质性提升并发审计结果,先使用 hex-graph。如果可用,局部读取代码时先使用 hex-line。如果 MCP 不可用、不受支持或未建立索引,则使用内置的 Read/Grep/Glob/Bash 继续,并在报告中说明所用的替代方案。
工作流
必须阅读: 加载 references/two_layer_detection.md 以了解检测方法。
- 解析上下文——从
contextStore中提取tech_stack、语言和output_dir - 逐项检查(1-7):
- 第一层: 使用 Grep/Glob 扫描以查找候选项
- 第二层: 阅读每个候选项周围的 20-50 行。应用该项检查的关键问题。分类:已确认 / 误报 / 需要上下文
- 收集已确认的问题及其严重性、位置、工作量和建议
- 根据
references/audit_scoring.md计算评分 - 撰写报告——在内存中构建报告,并写入
{output_dir}/ln-628--global.md(通过单次 Write 原子写入) - 向协调器返回摘要
审计规则
统一严重性升级: 对于所有检查——如果问题影响支付/身份验证/金融代码,则无论其他因素如何,均升级为严重。
1. 异步/事件循环竞态(CWE-362)
内容: 单线程异步代码中的共享状态在 await/yield 边界处遭到破坏。
第一层——Grep 模式:
| 语言 | 模式 | Grep |
|---|---|---|
| JS/TS | 跨 await 的读取-修改-写入 | \w+\s*[+\-*/]?=\s*.*await(例如,result += await something) |
| JS/TS | 检查后初始化竞态 | 同一代码块中的 if\s*\(!?\w+\),后接 \w+\s*=\s*await |
| Python | 跨 await 的读取-修改-写入 | async def 内的 \w+\s*[+\-*/]?=\s*await |
| Python | 异步代码中的模块级共享状态 | 模块级 \w+\s*=,并在 async def 内修改 |
| 所有语言 | 无锁的共享缓存 | 异步函数中出现 `.set( |
第二层——关键问题:
- 该变量是共享变量(模块/全局作用域)还是局部变量?
- 两个异步任务能否在此 await 点交错执行?
- 是否有锁/mutex/semaphore 保护该访问?
严重性: 严重(支付/身份验证)| 高(面向用户)| 中(后台)
安全模式排除项: 局部变量、const 声明、单次使用 await(不可能发生交错)。
工作量: M
2. 线程/协程安全(CWE-366)
内容: 多个线程/协程在未同步的情况下访问共享可变状态。
第 1 层 -- Grep 模式:
| 语言 | 模式 | Grep |
|---|---|---|
| Go | 未使用互斥锁的映射访问 | 结构体中出现 map\[.*\].*=,但没有 sync.Mutex 或 sync.RWMutex |
| Go | 被协程捕获的变量 | go func + 被修改的外部作用域变量 |
| Python | 在线程中修改全局变量 | 函数中出现 global\s+\w+,且同一文件中出现 threading.Thread |
| Java | 多个线程共享 HashMap | 同一类中出现 HashMap + Thread|Executor|Runnable,但没有 synchronized|ConcurrentHashMap |
| Rust | 多线程上下文中的 Rc | 同一文件中出现 Rc<RefCell + thread::spawn|tokio::spawn |
| Node.js | Worker Threads 共享状态 | 出现 workerData|SharedArrayBuffer|parentPort,且存在未使用 Atomics 的可变访问 |
第 2 层 -- 关键问题:
- 这个结构体/对象实际上会在线程间共享吗?(单线程代码 -> 误报)
- 互斥锁/锁是在嵌入的结构体中,还是在导入的模块中?(grep 可能会漏掉)
go func是按值捕获(安全)还是按引用捕获(不安全)?
严重程度: 严重(支付/身份验证) | 高(可能导致数据损坏) | 中(内部)
安全模式排除项: 在 goroutine 启动前,于 init() 或 main() 中使用的 Go 映射。Rust Arc<Mutex<T>>(本身已安全)。Java Collections.synchronizedMap()。
工作量: M
3. TOCTOU -- 检查与使用之间的竞态(CWE-367)
内容: 检查资源状态后再使用,但状态可能在检查与使用之间发生变化。
第 1 层 -- Grep 模式:
| 语言 | 检查 | 使用 | Grep |
|---|---|---|---|
| Python | os.path.exists() | open() | 同一变量上的 os\.path\.exists\( 与 open\( 相邻出现 |
| Python | os.access() | os.open() | os\.access\( 与 os\.open\(|open\( 相邻出现 |
| Node.js | fs.existsSync() | fs.readFileSync() | existsSync\( 与 readFileSync\(|readFile\( 相邻出现 |
| Node.js | fs.accessSync() | fs.openSync() | accessSync\( 与 openSync\( 相邻出现 |
| Go | os.Stat() | os.Open() | os\.Stat\( 与 os\.Open\(|os\.Create\( 相邻出现 |
| Java | .exists() | new FileInputStream | \.exists\(\) 与 new File|FileInputStream|FileOutputStream 相邻出现 |
第 2 层 -- 关键问题:
- 检查结果用于控制流(易受攻击),还是仅用于日志记录(安全)?
- 检查与使用的序列周围是否有锁/重试?
- 文件是否位于由应用控制的临时目录中(风险较低)?
- 攻击者能否替换该文件(符号链接攻击)?
严重程度: 严重(安全敏感:权限、身份验证令牌、配置) | 高(面向用户的文件操作) | 中(内部/后台)
安全模式排除项: 在带重试的 try/catch 中进行检查。检查仅用于日志/指标。检查与使用由文件锁保护。
工作量: S-M(将先检查再使用替换为直接使用并处理错误)
4. 死锁风险(CWE-833)
含义: 以不一致的顺序获取锁,或在持有锁时执行阻塞操作。
第 1 层 -- Grep 模式:
| 语言 | 模式 | Grep |
|---|---|---|
| Python | 嵌套锁 | with\s+\w+_lock:(多行:嵌套使用两个不同的锁) |
| Python | 循环中的锁 | for.*:,且循环体内有 \.acquire\(\) |
| Python | 锁 + 外部调用 | \.acquire\(\) 后、释放锁前出现 await|requests\.|urllib |
| Go | 未使用 defer 解锁 | \.Lock\(\) 后的下一行没有 defer.*\.Unlock\(\) |
| Go | 嵌套锁 | 同一函数中有两个 \.Lock\(\) 调用,且中间没有 \.Unlock\(\) |
| Java | 嵌套 synchronized | synchronized\s*\((多行:嵌套块使用不同的监视器) |
| JS | 异步互斥锁嵌套 | await\s+\w+\.acquire\(\)(同一函数中使用两个不同的互斥锁) |
第 2 层 -- 关键问题:
- 这是同一个锁(可重入 = 安全),还是不同的锁(存在死锁风险)?
- 所有调用点的锁顺序是否一致?
- 锁内的外部调用是否设置了超时?
严重程度: 严重(支付/身份验证) | 高(存在应用卡死风险)
安全模式排除项: 可重入锁(同一个锁获取两次)。设置了显式超时的锁(asyncio.wait_for、tryLock)。
工作量: L(重新设计锁的顺序)
5. 异步上下文中的阻塞 I/O(CWE-400)
含义: 在异步函数或事件循环处理程序中调用同步阻塞操作。
第 1 层 -- Grep 模式:
| 语言 | 阻塞调用 | Grep | 替代方案 |
|---|---|---|---|
| Python | async def 中的 time.sleep | async def 中的 time\.sleep | await asyncio.sleep |
| Python | async def 中的 requests.* | async def 中的 requests\.(get|post|put|delete) | httpx 或 aiohttp |
| Python | async def 中的 open() | async def 中的 open\( | aiofiles.open |
| Node.js | async 中的 fs.readFileSync | fs\.readFileSync|fs\.writeFileSync|fs\.mkdirSync | fs.promises.* |
| Node.js | async 中的 execSync | 异步处理程序中的 execSync|spawnSync | 使用 promises 的 exec |
| Node.js | async 中的同步加密 | crypto\.pbkdf2Sync|crypto\.scryptSync | crypto.pbkdf2(回调) |
第 2 层 -- 关键问题:
- 这是热路径(API 处理程序)还是冷路径(启动脚本)?
- 阻塞时长是否显著(>100ms)?
- 是否有合理原因(例如,启动时同步读取小型配置文件)?
严重程度: 高(阻塞事件循环/异步上下文) | 中(轻微阻塞 <100ms)
安全模式排除项: 在 if __name__ == "__main__" 中调用阻塞操作(启动时)。初始化时加载配置的 readFileSync。处理小型输入的同步加密。
工作量: S-M(替换为异步替代方案)
6. 资源争用(CWE-362)
含义: 多个并发访问者在没有协调的情况下争用同一资源。
第 1 层 -- Grep 模式:
| 模式 | 风险 | Grep |
|---|---|---|
| 未同步的共享内存 | 数据损坏 | SharedArrayBuffer|SharedMemory|shm_open|mmap 附近没有 Atomics|Mutex|Lock |
| 未协调的 IPC | 消息顺序 | 并发循环中的 process\.send|parentPort\.postMessage |
| 并发追加文件 | 写入交错 | 并行任务将多个 appendFile|fs\.write 写入同一路径 |
第 2 层 -- 关键问题:
- 多个写入者是否真的并发?(顺序执行 = 安全)
- 是否有操作系统级的原子性保证?(例如,小型写入使用
O_APPEND) - 顺序是否会影响正确性?
严重程度: 高(数据损坏) | 中(顺序问题)
安全模式排除项: 单一写入者模式。操作系统保证的原子操作(小型管道写入、O_APPEND)。具有顺序保证的消息队列。
工作量: M
7. 跨进程与不可见副作用(CWE-362、CWE-421)
内容: 多个进程,或进程与 OS,同时访问同一个独占资源;也包括对共享 OS 资源产生不明显副作用的操作。
第 1 层——搜索入口点:
| 模式 | 风险 | 搜索 |
|---|---|---|
| 剪贴板双重访问 | 同一流程中同时使用 OSC 52 和原生剪贴板 | 同一文件中出现 osc52|\\x1b\\]52 和 clipboard|SetClipboardData|pbcopy|xclip |
| 子进程 + 共享文件 | 父进程和子进程写入同一文件 | spawn|exec|Popen + 对同一路径执行 writeFile|open.*"w" |
| OS 独占资源 | Win32 剪贴板、串行端口、命名管道 | OpenClipboard|serial\.Serial|CreateNamedPipe|mkfifo |
| 终端转义序列 | stdout 触发终端 OS 访问 | \\x1b\\]|\\033\\]|writeOsc|xterm |
| 外部剪贴板工具 | 通过生成的进程访问剪贴板 | pbcopy|xclip|xsel|clip\.exe |
第 2 层——此检查比其他任何检查都更依赖推理:
-
构建资源清单:
资源 是否独占? 访问方 1 访问方 2 是否存在同步? -
追踪时间线:
t=0ms operation_A() -> resource_X accessed t=?ms side_effect -> resource_X accessed by external process t=?ms operation_B() -> resource_X accessed again -> CONFLICT? -
关键问题:
- 其他进程(终端、OS、子进程)能否同时访问此资源?
- 此操作是否会对共享 OS 资源产生不可见副作用?
- 外部进程的速度比预期慢或快时会发生什么?
- 用户快速连续触发此操作两次时会发生什么?
严重性: 严重(对独占 OS 资源有两个访问方且没有同步)| 高(子进程 + 共享文件且没有锁)| 高(通过推理检测到不可见副作用)
安全模式排除项: 只有一个访问方。存在重试/退避模式。操作之间使用显式延迟/await 进行排序。
工作量: M-L(可能需要移除冗余的访问路径)
评分算法
必须阅读: 加载 references/audit_worker_core_contract.md 和 references/audit_scoring.md。
输出格式
必须阅读: 加载 references/audit_worker_core_contract.md 和 references/templates/audit_worker_report_template.md。
按照 references/audit_summary_contract.md 编写 JSON 摘要。在托管模式下,调用方会同时传入 runId 和 summaryArtifactPath;在独立模式下,Worker 会根据共享契约生成自己的运行级产物路径。
将报告写入 {output_dir}/ln-628--global.md,并设置 category: "Concurrency",检查项包括:async_races、thread_safety、toctou、deadlock_potential、blocking_io、resource_contention、cross_process_races。
按照 references/audit_summary_contract.md 返回摘要。
当 summaryArtifactPath 缺失时,将独立运行时摘要写入 .hex-skills/runtime-artifacts/runs/{run_id}/evaluation-worker/{worker}--{identifier}.json,并可选择在结构化输出中回显相同的摘要。
Report written: .hex-skills/runtime-artifacts/runs/{run_id}/audit-report/ln-628--global.md
Score: X.X/10 | Issues: N (C:N H:N M:N L:N)
关键规则
必须阅读: 加载 references/audit_worker_core_contract.md。
- 不要自动修复: 仅报告——并发问题的修复需要谨慎的人工审查
- 两层检测: 始终在第 1 层搜索后应用第 2 层推理。绝不脱离上下文分析而直接报告原始搜索结果
- 语言感知检测: 针对每项检查使用特定语言的模式
- 统一严重级别升级: 支付/身份验证/金融代码中的任何发现 = 严重
- 合理估算工作量: S = <1 小时,M = 1-4 小时,L = >4 小时
- 排除项: 跳过测试文件、单线程 CLI 工具和生成的代码
完成定义
必须阅读: 加载 references/audit_worker_core_contract.md。
- 已解析 contextStore(语言、并发模型、output_dir)
- 已完成全部 7 项检查,并采用两层检测:
- 异步竞态、线程安全、TOCTOU、死锁可能性、阻塞 I/O、资源争用、跨进程竞态
- 已对每个候选项应用第二层推理(已确认 / 误报 / 需要上下文)
- 已收集发现项,并注明严重程度、位置、工作量、建议
- 已根据
references/audit_scoring.md计算评分 - 已将报告写入
{output_dir}/ln-628--global.md(通过单次原子 Write 调用) - 已根据契约撰写摘要
参考文件
- 两层检测方法:
references/two_layer_detection.md - 审计输出架构:
references/audit_output_schema.md
版本: 4.0.0 最后更新: 2026-03-04