$npx -y skills add 0xShe/PHP-Code-Audit-Skill --skill php-route-tracerPHP Web 路由到 Sink 的多层数据流追踪工具。根据用户指定路由,追踪从 handler 到最终敏感操作点,输出层级证据、参数变量追踪、可控性分析(不做漏洞结论)。
| 1 | # PHP Route Tracer(数据流追踪,不做漏洞结论) |
| 2 | |
| 3 | 根据 `php-route-mapper` 的路由(或 `php-audit-pipeline` 给出的合成入口),追踪从 **handler / CLI 入口 / 指定符号** 到最终 Sink(SQL/命令/文件/SSRF/XSS/模板渲染/反序列化等)的位置,输出完整数据流链、参数变量名变化与可控性分析。 |
| 4 | |
| 5 | ## CRITICAL:只输出追踪,不输出漏洞建议 |
| 6 | - 禁止给出“漏洞结论/风险等级/CVSS/修复建议” |
| 7 | - 只输出:数据流链证据、分支执行路径、Sink 定位、参数可控性判定表(可控性不等于漏洞结论) |
| 8 | |
| 9 | ## 输入依赖 |
| 10 | - `routes_{timestamp}.md`:路由定义(独立落盘时常为 `route_mapping/routes_{timestamp}.md`,见 `shared/IO_PATH_CONVENTION.md`) |
| 11 | - `params_{timestamp}.md`:参数结构(独立落盘时常为 `route_mapping/params_{timestamp}.md`) |
| 12 | - `source_path`:源码根目录 |
| 13 | - `route_id`:来自 `cross_analysis/high_risk_routes_{timestamp}.md`;可为 HTTP 路由序号,或 **`php-audit-pipeline` 阶段 3 的合成 ID**(`ENTRY_CLI:` / `ENTRY_CRON:` / `ENTRY_QUEUE:` / `ENTRY_HOOK:` / `ENTRY_INCLUDE:` / `SINK_ONLY:` 等)。 |
| 14 | - **合成入口(当非 HTTP 路由时必填)**:`entry_file`(相对 `source_path`)、`entry_symbol`(函数/方法或 `global`)、`trace_from`(从何处开始向 sink 追踪的说明)。 |
| 15 | |
| 16 | ## 追踪范围(必做) |
| 17 | 1. handler 入口(controller 方法/闭包函数/中间件最终处理函数);**非 HTTP 任务**时以输入中的 `entry_file` + `entry_symbol` 为追踪起点(见「输入依赖」) |
| 18 | 2. 请求参数进入 handler 的位置(request 获取、解码 JSON、提取 $_GET/$_POST) |
| 19 | 3. 参数在函数/方法之间的传递(assignment、数组字段访问、对象属性访问) |
| 20 | 4. 分支条件(if/switch/try/catch/return/throw)与提前退出点 |
| 21 | 5. 最终 Sink 的调用点与参数位置(函数调用参数名/位置) |
| 22 | |
| 23 | ## 输出文件结构(建议) |
| 24 | ``` |
| 25 | {output_path}/route_tracer/ |
| 26 | └── {route_id}/ |
| 27 | ├── trace_{method}_{timestamp}.md |
| 28 | └── trace_all_{timestamp}.md |
| 29 | ``` |
| 30 | 说明:**HTTP 路由**:`route_id` 宜与 `php-route-mapper` 的 `routes_{timestamp}.md` 中 `=== [N] {route_summary} ===` 的序号 `N` 一致。**CLI / hook / sink-only 等**:使用流水线合成 `route_id`,追踪起点以输入中的 `entry_file` + `entry_symbol` + `trace_from` 为准,不要求与 URI 对应。 |
| 31 | |
| 32 | ## 单路由报告模板(强制) |
| 33 | ```markdown |
| 34 | # Route Call Trace |
| 35 | |
| 36 | 追踪路由: {HTTP_METHOD} {route_rule} |
| 37 | 生成时间: {timestamp} |
| 38 | 项目路径: {source_path} |
| 39 | |
| 40 | --- |
| 41 | ## 1) 完整请求模板(来自 route-mapper) |
| 42 | ```http |
| 43 | {完整请求模板} |
| 44 | ``` |
| 45 | |
| 46 | --- |
| 47 | ## 2) 参数进入点 |
| 48 | | 参数 | HTTP 来源 | 进入 handler 的变量/字段 | 位置 | |
| 49 | |------|----------|-----------------------------|------| |
| 50 | | | | | | |
| 51 | |
| 52 | --- |
| 53 | ## 3) 调用链层级证据(逐层,不省略) |
| 54 | Level-1: {file}:{line} {Function/Class}.{method}({args}) |
| 55 | 关键代码: |
| 56 | ```php |
| 57 | // 展示将参数传入下一层的关键片段 |
| 58 | ``` |
| 59 | |
| 60 | Level-2: {file}:{line} {Function/Class}.{method}({args}) |
| 61 | |
| 62 | --- |
| 63 | ## 4) 分支路径追踪(Branch Execution Proof,必须输出) |
| 64 | path A: |
| 65 | 条件: {if/switch/try/catch/return/throw 的条件摘要} |
| 66 | 执行: {在该分支下参数如何继续流转到 Sink 的摘要} |
| 67 | Sink:是否执行 = 是/否 |
| 68 | |
| 69 | path B: |
| 70 | 条件: {另一条分支条件摘要} |
| 71 | 执行: {另一条分支下参数的处理/提前退出摘要} |
| 72 | |
| 73 | --- |
| 74 | ## 5) 参数可控性矩阵(Controllability Matrix,强制字段名与列必须一致) |
| 75 | | 参数 | HTTP/Body 字段 | 预处理/归一化 | Sink类型 | 覆盖类型 | 覆盖条件 | BlockReason(如有) | 可控性结论(✅/⚠️/❌) | 实际使用(是/否) | 可控场景 | |
| 76 | |------|------------------|------------------|-----------|-----------|-----------|--------------------|----------------------|------------------|----------| |
| 77 | |
| 78 | --- |
| 79 | ## 6) Sink 定位(Sink Parameter Mapping,强制字段名与列必须一致) |
| 80 | | Sink类型 | 函数/方法 | 调用点(file:line) | Sink参数名/位置 | 参数映射(Sink参数 <- 可控参数) | 证据(关键代码片段) | |
| 81 | |----------|-----------|-------------------|-------------------|----------------------------------------------|----------------------| |
| 82 | ``` |
| 83 | |
| 84 | ## 7) Sink Summary(强制:用于 pipeline 的硬门槛校验) |
| 85 | 必须输出一个汇总表(不允许省略): |
| 86 | | route_id | Sink类型 | Sink函数/语句 | 是否执行(是/否) | 触发分支(条件摘要) | 关联参数(来自可控性矩阵) | 证据(代码片段) | |
| 87 | |----------|---------|---------------|----------------|--------------------|------------------------------|----------------------| |
| 88 | |
| 89 | --- |
| 90 | ## 8) Trace 完整性声明(强制) |
| 91 | | trace_status | 含义 | |
| 92 | |-------------|------| |
| 93 | | COMPLETE | 调用链与 sink 证据齐全,参数可控性可判断 | |
| 94 | | PARTIAL | 只有局部链路证据或分支证据不完整,但 sink 存在或参数流可证明一部分 | |
| 95 | | UNRESOLVED | 无法定位到明确 sink 或可控性证据不足 | |
| 96 | |
| 97 | 并给出: |
| 98 | - 缺失项列表(必须逐条列出缺失:调用链层级/分支/映射/证据) |
| 99 | - 回退建议(允许的回退:重新 tracer 或进入对应子 skill 的 ⚠️待验证模式) |
| 100 | |
| 101 | ## 必做的“禁止项” |
| 102 | - 禁止用省略符省略调用链层级 |
| 103 | - 禁止保留未替换模板变量(如 `${route}` 未替换为真实 route_id) |
| 104 | - 禁止将“不可控”与“无风险”混为一谈:本 skill 只输出可控性,不输出漏洞结论 |
| 105 | |
| 106 | ## 9) Sink Evidence Type Checklist(强制:用于 pipeline 硬门槛) |
| 107 | 要求在每条 trace 报告中输出本检查清单(允许内容为空,但必须存在标题与表头;并对实际命中的 sink 写出证据来源与证据片段)。 |
| 108 | |
| 109 | | Sink类型 | 必须包含的证据要点(来自代码/配置的可证据片段) | 证据位置 | |
| 110 | |----------|----------------------------------------------------|----------| |
| 111 | | FILE | `EVID_FILE_WRAPPER_PREFIX`: wrapper/流包装前缀(如 `php://`/`phar://`/`zip://`)的使用方式;`EVID_FILE_RESOLVED_TARGET`: 包含/读取的最终解析结果(resolved target);`EVID_FILE_INCLUDE_REQUIRE_EXEC_BOUNDARY`: include/require 的执行面边界(是否真的执行 PHP 代码还是仅读取报错) | file:line | |
| 112 | | WRITE | `EVID_WRITE_WRITE_CALLSITE`: 写入/落点变更调用点证据(如 `file_put_contents`/`fwrite`/`fopen(...,'w')`/`rename`/`copy` 等);`EVID_WRITE_DESTPATH_JOIN_AND_NORMALIZATION`: 写入目的路径拼接与归一化证据(base join、净化/拒绝穿越片段、realpath 前缀校验等);`EVID_WRITE_DESTPATH_RESOLVED_TARGET`: 最终解析落点 resolved target 以及 base 约束逃逸判定证据;`EVID_WRITE_CONTENT_SOURCE_INTO_WRITE`: 写入内容参数与用户可控输入的映射证据;`EVID_WRITE_TRUNCATE_OR_OVERWRITE_MODE`: 覆盖/截断/追加模式证据(写入模式或覆盖策略);`EVID_WRITE_EXECUTION_ACCESSIBILITY_PROOF`: 写完后的可执行性/可触达性证据(web 根/可包含目录/执行禁用策略等) | file:line | |
| 113 | | UPLOAD | `EVID_UPLOAD_DESTPATH`: 保存目录最终落点(destPath);`EVID_UPLOAD_FILENAME_EXTENSION_PARSING_SANITIZE`: 文件名/扩展名解析与净化逻辑;`EVID_UPLOAD_ACCESSIBILITY_PROOF`: 写入后是否形成可访问面(静态直连证据/映射证据);`EVID_UPLOAD_EXEC_DISABLE_STRATEGY`: 服务端执行禁用策略(如有) | file:line | |
| 114 | | ARCHIVE | `EVID_ARCHIVE_EXTRACT_CALLSITE`: 归档解压/提取调用点位置(如 `ZipArchive->extrac |