dsh-standards 1.4.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/40-checker/fixtures/security/sec15-clean/index.mjs +3 -0
  2. package/40-checker/fixtures/security/sec15-clean/package.json +19 -0
  3. package/40-checker/fixtures/security/sec15-missing-ref/index.mjs +3 -0
  4. package/40-checker/fixtures/security/sec15-missing-ref/package.json +22 -0
  5. package/40-checker/fixtures/security/sec15-node/index.mjs +3 -0
  6. package/40-checker/fixtures/security/sec15-node/package.json +22 -0
  7. package/40-checker/fixtures/security/sec15-node/scripts/build.mjs +1 -0
  8. package/40-checker/fixtures/security/sec15-pipe/index.mjs +3 -0
  9. package/40-checker/fixtures/security/sec15-pipe/package.json +22 -0
  10. package/40-checker/fixtures/security/sec16-client/index.mjs +3 -0
  11. package/40-checker/fixtures/security/sec16-client/lib/client.js +3 -0
  12. package/40-checker/fixtures/security/sec16-client/package.json +21 -0
  13. package/40-checker/fixtures/security/sec16-declared/index.mjs +3 -0
  14. package/40-checker/fixtures/security/sec16-declared/package.json +19 -0
  15. package/40-checker/fixtures/security/sec16-eval/index.mjs +3 -0
  16. package/40-checker/fixtures/security/sec16-eval/package.json +19 -0
  17. package/40-checker/fixtures/security/sec16-require/index.mjs +4 -0
  18. package/40-checker/fixtures/security/sec16-require/package.json +19 -0
  19. package/40-checker/fixtures/security/sec17-env/index.mjs +5 -0
  20. package/40-checker/fixtures/security/sec17-env/package.json +19 -0
  21. package/40-checker/fixtures/security/sec17-seam/index.mjs +3 -0
  22. package/40-checker/fixtures/security/sec17-seam/package.json +19 -0
  23. package/40-checker/fixtures/security/sec17-ssh/index.mjs +6 -0
  24. package/40-checker/fixtures/security/sec17-ssh/package.json +19 -0
  25. package/40-checker/fixtures/security/sec18-bad/index.mjs +3 -0
  26. package/40-checker/fixtures/security/sec18-bad/package.json +21 -0
  27. package/40-checker/fixtures/security/sec18-good/index.mjs +3 -0
  28. package/40-checker/fixtures/security/sec18-good/package.json +26 -0
  29. package/40-checker/fixtures/security/sec18-undeclared/index.mjs +3 -0
  30. package/40-checker/fixtures/security/sec18-undeclared/package.json +26 -0
  31. package/40-checker/fixtures/security/sec19-blob/index.mjs +2 -0
  32. package/40-checker/fixtures/security/sec19-blob/package.json +19 -0
  33. package/40-checker/fixtures/security/sec19-clean/index.mjs +2 -0
  34. package/40-checker/fixtures/security/sec19-clean/package.json +19 -0
  35. package/40-checker/fixtures/security/sec19-wasm/blob.wasm +0 -0
  36. package/40-checker/fixtures/security/sec19-wasm/index.mjs +3 -0
  37. package/40-checker/fixtures/security/sec19-wasm/package.json +19 -0
  38. package/40-checker/fixtures/security/sec20-unwrapped/index.mjs +4 -0
  39. package/40-checker/fixtures/security/sec20-unwrapped/package.json +23 -0
  40. package/40-checker/fixtures/security/sec20-wrapped/index.mjs +3 -0
  41. package/40-checker/fixtures/security/sec20-wrapped/package.json +23 -0
  42. package/40-checker/fixtures/security/sec21-known/index.mjs +3 -0
  43. package/40-checker/fixtures/security/sec21-known/package.json +23 -0
  44. package/40-checker/fixtures/security/sec21-typosquat/index.mjs +3 -0
  45. package/40-checker/fixtures/security/sec21-typosquat/package.json +22 -0
  46. package/40-checker/fixtures/security/sec22-attested/index.mjs +3 -0
  47. package/40-checker/fixtures/security/sec22-attested/package.json +22 -0
  48. package/40-checker/fixtures/security/sec22-none/index.mjs +3 -0
  49. package/40-checker/fixtures/security/sec22-none/package.json +19 -0
  50. package/40-checker/scripts/sign-evidence.mjs +169 -0
  51. package/40-checker/src/cli.mjs +402 -73
  52. package/40-checker/src/declarations.mjs +10 -10
  53. package/40-checker/src/flow-evidence.mjs +21 -0
  54. package/40-checker/src/index.mjs +2 -1
  55. package/40-checker/src/report.mjs +116 -4
  56. package/40-checker/src/runtime-child.mjs +68 -0
  57. package/40-checker/src/runtime.mjs +3 -1
  58. package/40-checker/src/sandbox-run.mjs +406 -35
  59. package/40-checker/src/security.mjs +1065 -0
  60. package/40-checker/src/signature.mjs +249 -0
  61. package/40-checker/src/util.mjs +53 -0
  62. package/CHANGELOG.md +34 -0
  63. package/docs/SIGNING.md +137 -0
  64. package/docs/coverage.md +39 -6
  65. package/package.json +1 -1
  66. package/spec/coverage-contract.md +33 -11
  67. package/spec/dsc-clauses.json +410 -9
  68. package/spec/remediation.json +196 -0
  69. package/spec/schemas/conformance.schema.json +80 -2
@@ -4,19 +4,22 @@
4
4
  "id": "DS-C",
5
5
  "version": "1.0.0"
6
6
  },
7
- "generatedAt": "2026-11-06",
7
+ "generatedAt": "2026-11-07",
8
8
  "source": [
9
9
  "31-DS-C条款.md",
10
10
  "31-DSH-ENTRY入门规范.md",
11
11
  "40-checker/src/cli.mjs",
12
- "40-checker/src/permissions.mjs"
12
+ "40-checker/src/permissions.mjs",
13
+ "40-checker/src/report.mjs",
14
+ "40-checker/src/security.mjs",
15
+ "34-三层分级模型-GB-GBT-GBZ类比.md"
13
16
  ],
14
- "note": "Stable list of DS-C parent clauses C-1..C-14 and every C-x.y sub-clause. `mandatory` means a violation can produce FAIL in an applicable profile; `advisory` means the checker reports it as advisory (check.advisory=true) and it never moves the verdict. C-3 is mandatory in listing only; C-14 is mandatory in entry scope only. Docs anchors point at the clause section that owns the sub-clause. The repository has no clauses.js; this list is derived from the 31-DS-C条款.md §2 tables plus the checker sources that emit DSC-01..DSC-14 (cli.mjs, permissions.mjs).",
17
+ "note": "Stable list of DS-C parent clauses C-1..C-22 and every C-x.y sub-clause. `mandatory` means a violation can produce FAIL in an applicable profile (or, for C-21, that the check is required for security coverage while findings cap at WARN); `advisory` means the checker reports it as advisory (check.advisory=true) and it never moves the verdict. C-1..C-14 are the baseline/entry set; C-15..C-22 are the 2026-11-07 security-scope extension and are NOT part of the DS-C package/listing mandatory set, so they never change the DS-C badge. In --scope security, C-15/C-16/C-17 can FAIL; C-21 is mandatory but WARN-only; C-18/C-19/C-20/C-22 are advisory; DSC-16 has no declaration-based exemption. Docs anchors point at the clause section that owns the sub-clause. The repository has no clauses.js; this list is derived from the 31-DS-C条款.md §2 tables plus the checker sources that emit DSC-01..DSC-22.",
15
18
  "counts": {
16
- "clauses": 14,
17
- "subclauses": 60,
18
- "entries": 74,
19
- "dscChecks": 14
19
+ "clauses": 22,
20
+ "subclauses": 91,
21
+ "entries": 113,
22
+ "dscChecks": 22
20
23
  },
21
24
  "clauses": [
22
25
  {
@@ -158,9 +161,97 @@
158
161
  "layer": "L1",
159
162
  "mandatory": true,
160
163
  "advisory": false,
161
- "docs": "31-DSH-ENTRY入门规范.md#21-run-set",
164
+ "docs": "31-DSH-ENTRY入门规范.md#二entry-profile",
162
165
  "parent": null,
163
- "note": "entry scope only (--scope entry); not part of the DS-C package/listing gate"
166
+ "note": "entry scope only (--scope entry); not part of the DS-C package/listing gate; docs anchor points at the entry-profile section (C-14 has no section in 31)"
167
+ },
168
+ {
169
+ "dsc": "DSC-15",
170
+ "clause": "C-15",
171
+ "title": "生命周期脚本",
172
+ "layer": "L0",
173
+ "mandatory": true,
174
+ "advisory": false,
175
+ "docs": "31-DS-C条款.md#c-15-生命周期脚本",
176
+ "parent": null,
177
+ "note": "security scope only; install-time preinstall/install/postinstall/prepare scripts; prepack/postpack not scanned in v1"
178
+ },
179
+ {
180
+ "dsc": "DSC-16",
181
+ "clause": "C-16",
182
+ "title": "动态执行",
183
+ "layer": "L0",
184
+ "mandatory": true,
185
+ "advisory": false,
186
+ "docs": "31-DS-C条款.md#c-16-动态执行",
187
+ "parent": null,
188
+ "note": "security scope only; eval/Function/vm/_compile/process.binding can FAIL; bare child_process is WARN"
189
+ },
190
+ {
191
+ "dsc": "DSC-17",
192
+ "clause": "C-17",
193
+ "title": "敏感文件",
194
+ "layer": "L0",
195
+ "mandatory": true,
196
+ "advisory": false,
197
+ "docs": "31-DS-C条款.md#c-17-敏感文件",
198
+ "parent": null,
199
+ "note": "security scope only; direct reads of system credentials or backing files can FAIL; .env is WARN"
200
+ },
201
+ {
202
+ "dsc": "DSC-18",
203
+ "clause": "C-18",
204
+ "title": "外联端点",
205
+ "layer": "L0",
206
+ "mandatory": false,
207
+ "advisory": true,
208
+ "docs": "31-DS-C条款.md#c-18-外联端点",
209
+ "parent": null,
210
+ "note": "security scope advisory (advisory:true); warn at most, never FAIL; missing egress capability is C-11.2"
211
+ },
212
+ {
213
+ "dsc": "DSC-19",
214
+ "clause": "C-19",
215
+ "title": "混淆与二进制",
216
+ "layer": "L0",
217
+ "mandatory": false,
218
+ "advisory": true,
219
+ "docs": "31-DS-C条款.md#c-19-混淆与二进制",
220
+ "parent": null,
221
+ "note": "security scope only; advisory, records opaque artifacts and sha256, never FAIL"
222
+ },
223
+ {
224
+ "dsc": "DSC-20",
225
+ "clause": "C-20",
226
+ "title": "提示词注入",
227
+ "layer": "L0",
228
+ "mandatory": false,
229
+ "advisory": true,
230
+ "docs": "31-DS-C条款.md#c-20-提示词注入",
231
+ "parent": null,
232
+ "note": "security scope only; advisory; v1 static heuristics, v2 FLOW runtime hook"
233
+ },
234
+ {
235
+ "dsc": "DSC-21",
236
+ "clause": "C-21",
237
+ "title": "供应链",
238
+ "layer": "L0",
239
+ "mandatory": true,
240
+ "advisory": false,
241
+ "docs": "31-DS-C条款.md#c-21-供应链",
242
+ "parent": null,
243
+ "note": "security scope mandatory (not-run => incomplete); name/scope findings cap at WARN, never FAIL; lockfile consistency not judged in v1"
244
+ },
245
+ {
246
+ "dsc": "DSC-22",
247
+ "clause": "C-22",
248
+ "title": "来源与完整性",
249
+ "layer": "L0",
250
+ "mandatory": false,
251
+ "advisory": true,
252
+ "docs": "31-DS-C条款.md#c-22-来源与完整性",
253
+ "parent": null,
254
+ "note": "security scope advisory; v1 records presence of dist.integrity / dsh.attestation / dsh.signature only; no signature or digest verification"
164
255
  },
165
256
  {
166
257
  "dsc": "DSC-01",
@@ -761,6 +852,316 @@
761
852
  "advisory": false,
762
853
  "docs": "31-DS-C条款.md#c-13-高风险类别强制标注",
763
854
  "parent": "C-13"
855
+ },
856
+ {
857
+ "dsc": "DSC-15",
858
+ "clause": "C-15.1",
859
+ "title": "危险命令形态(prepare 仅 WARN)",
860
+ "layer": "L0",
861
+ "mandatory": false,
862
+ "advisory": false,
863
+ "docs": "31-DS-C条款.md#c-15-生命周期脚本",
864
+ "parent": "C-15"
865
+ },
866
+ {
867
+ "dsc": "DSC-15",
868
+ "clause": "C-15.2",
869
+ "title": "普通生命周期脚本(WARN)/无脚本 PASS",
870
+ "layer": "L0",
871
+ "mandatory": true,
872
+ "advisory": false,
873
+ "docs": "31-DS-C条款.md#c-15-生命周期脚本",
874
+ "parent": "C-15"
875
+ },
876
+ {
877
+ "dsc": "DSC-15",
878
+ "clause": "C-15.3",
879
+ "title": "引用缺失脚本(prepare 仅 WARN)",
880
+ "layer": "L0",
881
+ "mandatory": true,
882
+ "advisory": false,
883
+ "docs": "31-DS-C条款.md#c-15-生命周期脚本",
884
+ "parent": "C-15"
885
+ },
886
+ {
887
+ "dsc": "DSC-15",
888
+ "clause": "C-15.4",
889
+ "title": "prepack/postpack 打包期脚本(v1 不扫)",
890
+ "layer": "L0",
891
+ "mandatory": false,
892
+ "advisory": false,
893
+ "docs": "31-DS-C条款.md#c-15-生命周期脚本",
894
+ "parent": "C-15"
895
+ },
896
+ {
897
+ "dsc": "DSC-16",
898
+ "clause": "C-16.1",
899
+ "title": "eval/Function/_compile/process.binding",
900
+ "layer": "L0",
901
+ "mandatory": true,
902
+ "advisory": false,
903
+ "docs": "31-DS-C条款.md#c-16-动态执行",
904
+ "parent": "C-16"
905
+ },
906
+ {
907
+ "dsc": "DSC-16",
908
+ "clause": "C-16.2",
909
+ "title": "vm.runIn*/Script/createContext",
910
+ "layer": "L0",
911
+ "mandatory": false,
912
+ "advisory": false,
913
+ "docs": "31-DS-C条款.md#c-16-动态执行",
914
+ "parent": "C-16"
915
+ },
916
+ {
917
+ "dsc": "DSC-16",
918
+ "clause": "C-16.3",
919
+ "title": "裸 child_process(WARN)/空参豁免",
920
+ "layer": "L0",
921
+ "mandatory": false,
922
+ "advisory": false,
923
+ "docs": "31-DS-C条款.md#c-16-动态执行",
924
+ "parent": "C-16"
925
+ },
926
+ {
927
+ "dsc": "DSC-16",
928
+ "clause": "C-16.4",
929
+ "title": "运行时拼代码/package import(not-run)",
930
+ "layer": "L0",
931
+ "mandatory": false,
932
+ "advisory": false,
933
+ "docs": "31-DS-C条款.md#c-16-动态执行",
934
+ "parent": "C-16"
935
+ },
936
+ {
937
+ "dsc": "DSC-17",
938
+ "clause": "C-17.1",
939
+ "title": "系统凭据/backing file 直接读",
940
+ "layer": "L0",
941
+ "mandatory": true,
942
+ "advisory": false,
943
+ "docs": "31-DS-C条款.md#c-17-敏感文件",
944
+ "parent": "C-17"
945
+ },
946
+ {
947
+ "dsc": "DSC-17",
948
+ "clause": "C-17.2",
949
+ "title": ".env / process.env 枚举(WARN)",
950
+ "layer": "L0",
951
+ "mandatory": true,
952
+ "advisory": false,
953
+ "docs": "31-DS-C条款.md#c-17-敏感文件",
954
+ "parent": "C-17"
955
+ },
956
+ {
957
+ "dsc": "DSC-17",
958
+ "clause": "C-17.3",
959
+ "title": "AST 解析失败 -> partial/not-run",
960
+ "layer": "L0",
961
+ "mandatory": false,
962
+ "advisory": false,
963
+ "docs": "31-DS-C条款.md#c-17-敏感文件",
964
+ "parent": "C-17"
965
+ },
966
+ {
967
+ "dsc": "DSC-17",
968
+ "clause": "C-17.4",
969
+ "title": "动态路径/readdir 前缀(not-run)",
970
+ "layer": "L0",
971
+ "mandatory": false,
972
+ "advisory": false,
973
+ "docs": "31-DS-C条款.md#c-17-敏感文件",
974
+ "parent": "C-17"
975
+ },
976
+ {
977
+ "dsc": "DSC-18",
978
+ "clause": "C-18.1",
979
+ "title": "可疑端点形态(WARN)",
980
+ "layer": "L0",
981
+ "mandatory": false,
982
+ "advisory": true,
983
+ "docs": "31-DS-C条款.md#c-18-外联端点",
984
+ "parent": "C-18"
985
+ },
986
+ {
987
+ "dsc": "DSC-18",
988
+ "clause": "C-18.2",
989
+ "title": "未披露端点差集(WARN)",
990
+ "layer": "L0",
991
+ "mandatory": false,
992
+ "advisory": true,
993
+ "docs": "31-DS-C条款.md#c-18-外联端点",
994
+ "parent": "C-18"
995
+ },
996
+ {
997
+ "dsc": "DSC-18",
998
+ "clause": "C-18.3",
999
+ "title": "调网点解析/动态(not-run)",
1000
+ "layer": "L0",
1001
+ "mandatory": false,
1002
+ "advisory": true,
1003
+ "docs": "31-DS-C条款.md#c-18-外联端点",
1004
+ "parent": "C-18"
1005
+ },
1006
+ {
1007
+ "dsc": "DSC-19",
1008
+ "clause": "C-19.1",
1009
+ "title": "文本不透明线索(长行/base64/熵)",
1010
+ "layer": "L0",
1011
+ "mandatory": false,
1012
+ "advisory": true,
1013
+ "docs": "31-DS-C条款.md#c-19-混淆与二进制",
1014
+ "parent": "C-19"
1015
+ },
1016
+ {
1017
+ "dsc": "DSC-19",
1018
+ "clause": "C-19.2",
1019
+ "title": "二进制清单与 sha256",
1020
+ "layer": "L0",
1021
+ "mandatory": false,
1022
+ "advisory": true,
1023
+ "docs": "31-DS-C条款.md#c-19-混淆与二进制",
1024
+ "parent": "C-19"
1025
+ },
1026
+ {
1027
+ "dsc": "DSC-19",
1028
+ "clause": "C-19.3",
1029
+ "title": "文件清单截断 -> partial/not-run",
1030
+ "layer": "L0",
1031
+ "mandatory": false,
1032
+ "advisory": true,
1033
+ "docs": "31-DS-C条款.md#c-19-混淆与二进制",
1034
+ "parent": "C-19"
1035
+ },
1036
+ {
1037
+ "dsc": "DSC-19",
1038
+ "clause": "C-19.4",
1039
+ "title": "只登记不判恶",
1040
+ "layer": "L0",
1041
+ "mandatory": false,
1042
+ "advisory": true,
1043
+ "docs": "31-DS-C条款.md#c-19-混淆与二进制",
1044
+ "parent": "C-19"
1045
+ },
1046
+ {
1047
+ "dsc": "DSC-20",
1048
+ "clause": "C-20.1",
1049
+ "title": "外部文本进入 systemPrompt(WARN)",
1050
+ "layer": "L0",
1051
+ "mandatory": false,
1052
+ "advisory": true,
1053
+ "docs": "31-DS-C条款.md#c-20-提示词注入",
1054
+ "parent": "C-20"
1055
+ },
1056
+ {
1057
+ "dsc": "DSC-20",
1058
+ "clause": "C-20.2",
1059
+ "title": "指令样字面量(英文,WARN)",
1060
+ "layer": "L0",
1061
+ "mandatory": false,
1062
+ "advisory": true,
1063
+ "docs": "31-DS-C条款.md#c-20-提示词注入",
1064
+ "parent": "C-20"
1065
+ },
1066
+ {
1067
+ "dsc": "DSC-20",
1068
+ "clause": "C-20.3",
1069
+ "title": "untrusted 包裹(v1 不判,not-run)",
1070
+ "layer": "L0",
1071
+ "mandatory": false,
1072
+ "advisory": true,
1073
+ "docs": "31-DS-C条款.md#c-20-提示词注入",
1074
+ "parent": "C-20"
1075
+ },
1076
+ {
1077
+ "dsc": "DSC-20",
1078
+ "clause": "C-20.4",
1079
+ "title": "运行时 hook(not-run)",
1080
+ "layer": "L0",
1081
+ "mandatory": false,
1082
+ "advisory": true,
1083
+ "docs": "31-DS-C条款.md#c-20-提示词注入",
1084
+ "parent": "C-20"
1085
+ },
1086
+ {
1087
+ "dsc": "DSC-21",
1088
+ "clause": "C-21.1",
1089
+ "title": "种子名编辑距离 <=1(WARN)",
1090
+ "layer": "L0",
1091
+ "mandatory": false,
1092
+ "advisory": false,
1093
+ "docs": "31-DS-C条款.md#c-21-供应链",
1094
+ "parent": "C-21"
1095
+ },
1096
+ {
1097
+ "dsc": "DSC-21",
1098
+ "clause": "C-21.2",
1099
+ "title": "scope 同形字/近似(listing FAIL)",
1100
+ "layer": "L0",
1101
+ "mandatory": false,
1102
+ "advisory": false,
1103
+ "docs": "31-DS-C条款.md#c-21-供应链",
1104
+ "parent": "C-21"
1105
+ },
1106
+ {
1107
+ "dsc": "DSC-21",
1108
+ "clause": "C-21.3",
1109
+ "title": "依赖 install 脚本/元数据缺失 -> not-run",
1110
+ "layer": "L0",
1111
+ "mandatory": false,
1112
+ "advisory": false,
1113
+ "docs": "31-DS-C条款.md#c-21-供应链",
1114
+ "parent": "C-21"
1115
+ },
1116
+ {
1117
+ "dsc": "DSC-21",
1118
+ "clause": "C-21.4",
1119
+ "title": "lockfile 一致性(v1 不判)",
1120
+ "layer": "L0",
1121
+ "mandatory": false,
1122
+ "advisory": false,
1123
+ "docs": "31-DS-C条款.md#c-21-供应链",
1124
+ "parent": "C-21"
1125
+ },
1126
+ {
1127
+ "dsc": "DSC-22",
1128
+ "clause": "C-22.1",
1129
+ "title": "dist.integrity 存在(integrity-only)",
1130
+ "layer": "L0",
1131
+ "mandatory": false,
1132
+ "advisory": true,
1133
+ "docs": "31-DS-C条款.md#c-22-来源与完整性",
1134
+ "parent": "C-22"
1135
+ },
1136
+ {
1137
+ "dsc": "DSC-22",
1138
+ "clause": "C-22.2",
1139
+ "title": "dsh.attestation / dsh.signature 存在(self-declared)",
1140
+ "layer": "L0",
1141
+ "mandatory": false,
1142
+ "advisory": true,
1143
+ "docs": "31-DS-C条款.md#c-22-来源与完整性",
1144
+ "parent": "C-22"
1145
+ },
1146
+ {
1147
+ "dsc": "DSC-22",
1148
+ "clause": "C-22.3",
1149
+ "title": "digest 比对/验签/registry metadata(v2,not-run)",
1150
+ "layer": "L0",
1151
+ "mandatory": false,
1152
+ "advisory": true,
1153
+ "docs": "31-DS-C条款.md#c-22-来源与完整性",
1154
+ "parent": "C-22"
1155
+ },
1156
+ {
1157
+ "dsc": "DSC-22",
1158
+ "clause": "C-22.4",
1159
+ "title": "无来源字段 -> NA/not-run",
1160
+ "layer": "L0",
1161
+ "mandatory": false,
1162
+ "advisory": true,
1163
+ "docs": "31-DS-C条款.md#c-22-来源与完整性",
1164
+ "parent": "C-22"
764
1165
  }
765
1166
  ]
766
1167
  }
@@ -474,5 +474,201 @@
474
474
  "fix": "补 dsh.client 的 package-root 行与 client 导出;确认构建产物在 files 里;用 --entry-runtime server-entry/client probe 复跑。",
475
475
  "docs": "docs/entry.md#client-files",
476
476
  "severityHint": "fail"
477
+ },
478
+ "C-15": {
479
+ "title": "安装生命周期脚本必须可审计",
480
+ "why": "preinstall/install/postinstall/prepare 在用户权限下执行,是安装期唯一的静态可见面。",
481
+ "fix": "读 package.json#scripts 的四个生命周期字段;危险形态(下载并管道执行、base64 解码、node -e、shell -c、引用 $HOME/~/etc、引用缺失脚本)必须修掉。",
482
+ "docs": "docs/security.md#6-dependencies-build-and-publish-dsc-15-dsc-21-dsc-22",
483
+ "severityHint": "fail"
484
+ },
485
+ "C-15.1": {
486
+ "title": "不得在安装脚本里下载并执行远程代码",
487
+ "why": "curl|sh、base64 -d、node -e、sh -c、powershell -enc 等形态无法审计且直接执行安装者权限。",
488
+ "fix": "删除这些形态,改用随包发布的构建脚本或显式脚本文件;prepare 的同类形态按 WARN 处理。",
489
+ "docs": "docs/security.md#6-dependencies-build-and-publish-dsc-15-dsc-21-dsc-22",
490
+ "severityHint": "fail"
491
+ },
492
+ "C-15.2": {
493
+ "title": "生命周期脚本本身按 WARN/证据处理",
494
+ "why": "存在安装脚本不等于恶意,但它决定安装期会执行什么,需要被记录。",
495
+ "fix": "把命令写成可审阅的脚本文件(如 node scripts/build.mjs)并在包内提供该文件;不执行下载或内联代码。",
496
+ "docs": "docs/security.md#6-dependencies-build-and-publish-dsc-15-dsc-21-dsc-22",
497
+ "severityHint": "warn"
498
+ },
499
+ "C-15.3": {
500
+ "title": "脚本引用必须存在",
501
+ "why": "引用不存在的脚本文件会让安装直接失败,或掩盖真正要执行的命令。",
502
+ "fix": "核对 node 脚本路径与 npm run 目标都在 package.json#scripts 和包内存在。",
503
+ "docs": "docs/security.md#6-dependencies-build-and-publish-dsc-15-dsc-21-dsc-22",
504
+ "severityHint": "fail"
505
+ },
506
+ "C-16": {
507
+ "title": "服务端入口不得包含不可审计的动态执行",
508
+ "why": "eval/new Function/vm 可把外部字符串变成代码,静态检查与能力声明都无法覆盖。",
509
+ "fix": "移除动态执行;如确实需要,改成显式、可审阅的模块加载,并在评审中说明数据来源。",
510
+ "docs": "docs/security.md#4-files-subprocesses-and-dynamic-execution-dsc-15-dsc-16-dsc-17-dsc-19",
511
+ "severityHint": "fail"
512
+ },
513
+ "C-16.1": {
514
+ "title": "eval / new Function 属于 code:dynamic",
515
+ "why": "它们绕过静态审阅,常与解码/混淆载荷组合出现。",
516
+ "fix": "不要用 eval/new Function;把需要的行为写成静态函数。空参 new Function(\"\") 探针不判定。",
517
+ "docs": "docs/security.md#4-files-subprocesses-and-dynamic-execution-dsc-15-dsc-16-dsc-17-dsc-19",
518
+ "severityHint": "fail"
519
+ },
520
+ "C-16.2": {
521
+ "title": "vm / module._compile / process.binding 同样不可审计",
522
+ "why": "这些接口能加载任意代码或绕过模块系统。",
523
+ "fix": "移除 vm.runIn*、Module._compile、process.binding;改用普通 ESM import。",
524
+ "docs": "docs/security.md#4-files-subprocesses-and-dynamic-execution-dsc-15-dsc-16-dsc-17-dsc-19",
525
+ "severityHint": "fail"
526
+ },
527
+ "C-16.3": {
528
+ "title": "child_process 是需要声明的子进程能力",
529
+ "why": "子进程可执行任意命令并绕过进程内 seam。",
530
+ "fix": "如确需子进程,声明 subprocess 能力并在评审中说明命令与输入边界。",
531
+ "docs": "docs/security.md#4-files-subprocesses-and-dynamic-execution-dsc-15-dsc-16-dsc-17-dsc-19",
532
+ "severityHint": "warn"
533
+ },
534
+ "C-16.4": {
535
+ "title": "包依赖/不可解析导入使闭包不完整",
536
+ "why": "闭包外的 package 导入与解析失败意味着本检查没有看到全部服务端代码。",
537
+ "fix": "把入口与本地依赖放进扫描预算;无法解析的本地导入要修正。",
538
+ "docs": "docs/security.md#4-files-subprocesses-and-dynamic-execution-dsc-15-dsc-16-dsc-17-dsc-19",
539
+ "severityHint": "advisory"
540
+ },
541
+ "C-17": {
542
+ "title": "不得读取系统凭据文件",
543
+ "why": "~/.ssh、~/.dsh 凭据、.aws/.npmrc/.netrc/.pypi、tokens* 属于系统凭据,插件不应直接读取。",
544
+ "fix": "改用 ctx.credentials 的受控接口;文件读取只针对包内或用户显式提供的路径。",
545
+ "docs": "docs/security.md#2-credentials-and-sensitive-files-dsc-17",
546
+ "severityHint": "fail"
547
+ },
548
+ "C-17.1": {
549
+ "title": "敏感路径不能作为文件读取 API 的实参",
550
+ "why": "实参回溯命中说明代码确实在读取凭据路径,注释或普通字符串不算。",
551
+ "fix": "删除该读取;凭据通过 ctx.credentials.resolve 等 seam 获取。",
552
+ "docs": "docs/security.md#2-credentials-and-sensitive-files-dsc-17",
553
+ "severityHint": "fail"
554
+ },
555
+ "C-17.2": {
556
+ "title": "读取 .env 只是 WARN 但需要理由",
557
+ "why": ".env 可能合法,但它常含令牌且不应被插件默认读取。",
558
+ "fix": "确认 .env 是用户显式提供的输入;不要把 .env 读取当作凭据 seam。",
559
+ "docs": "docs/security.md#2-credentials-and-sensitive-files-dsc-17",
560
+ "severityHint": "warn"
561
+ },
562
+ "C-17.3": {
563
+ "title": "枚举 process.env 并与外联同现需要审查",
564
+ "why": "Object.keys(process.env) 加 fetch 是常见的外泄形态。",
565
+ "fix": "只读取具名环境变量;不要枚举全部环境并与网络调用组合。",
566
+ "docs": "docs/security.md#2-credentials-and-sensitive-files-dsc-17",
567
+ "severityHint": "warn"
568
+ },
569
+ "C-18": {
570
+ "title": "外联端点应可披露",
571
+ "why": "端点本身不判恶意,但非 https、webhook/paste/ngrok/onion、公网裸 IP 与未披露端点值得人工复核。",
572
+ "fix": "在 dsh.disclosure.endpoints 列出 https 端点;移除可疑主机与非 https 调用。",
573
+ "docs": "docs/security.md#3-egress-endpoints-dsc-18",
574
+ "severityHint": "warn"
575
+ },
576
+ "C-18.1": {
577
+ "title": "可疑外联端点",
578
+ "why": "webhook/paste/ngrok/onion、非 https、URL userinfo、公网裸 IP 会削弱来源与传输可信度。",
579
+ "fix": "改用已披露的 https API;确需回调时在 disclosure 中说明用途与保留策略。",
580
+ "docs": "docs/security.md#3-egress-endpoints-dsc-18",
581
+ "severityHint": "warn"
582
+ },
583
+ "C-18.2": {
584
+ "title": "端点未列入 dsh.disclosure.endpoints",
585
+ "why": "声明了 disclosure 却漏列实际调用点,用户无法核对出站流量。",
586
+ "fix": "把 fetch/http(s).request 的 https 端点补进 disclosure.endpoints。",
587
+ "docs": "docs/security.md#3-egress-endpoints-dsc-18",
588
+ "severityHint": "warn"
589
+ },
590
+ "C-18.3": {
591
+ "title": "端点解析只登记,不因 URL 字面量判定",
592
+ "why": "动态拼接 URL 无法静态确定;本检查不会仅凭 URL 字面量下结论。",
593
+ "fix": "运行时用抓包/网络策略核对;静态侧保持端点可读。",
594
+ "docs": "docs/security.md#3-egress-endpoints-dsc-18",
595
+ "severityHint": "advisory"
596
+ },
597
+ "C-19": {
598
+ "title": "混淆文本与二进制只登记不判恶",
599
+ "why": "长行、base64、高熵与 .wasm/.node/.so 可能是合法产物,也可能是隐藏载荷。",
600
+ "fix": "保留 sourcemap 与可读源码;二进制给出构建来源与 sha256。",
601
+ "docs": "docs/security.md#4-files-subprocesses-and-dynamic-execution-dsc-15-dsc-16-dsc-17-dsc-19",
602
+ "severityHint": "advisory"
603
+ },
604
+ "C-19.1": {
605
+ "title": "混淆文本线索",
606
+ "why": "单行 >20k、base64 ≥4k、熵 >7.5 只是线索,不是恶意判定。",
607
+ "fix": "发布可读构建产物并附 sourcemap;解释必须保留的生成代码。",
608
+ "docs": "docs/security.md#4-files-subprocesses-and-dynamic-execution-dsc-15-dsc-16-dsc-17-dsc-19",
609
+ "severityHint": "advisory"
610
+ },
611
+ "C-19.2": {
612
+ "title": "二进制产物记录 sha256",
613
+ "why": "二进制无法静态审阅,只能记录摘要供人工比对。",
614
+ "fix": "在发布说明中给出二进制的构建来源与 sha256;优先发布源码。",
615
+ "docs": "docs/security.md#4-files-subprocesses-and-dynamic-execution-dsc-15-dsc-16-dsc-17-dsc-19",
616
+ "severityHint": "advisory"
617
+ },
618
+ "C-20": {
619
+ "title": "提示词注入只做线索",
620
+ "why": "静态无法判断语义是防护规则还是注入指令,故只登记不判恶意。",
621
+ "fix": "把外部文本显式包裹为不可信数据;systemPrompt 使用静态指令,不从工具结果直接拼接。",
622
+ "docs": "docs/security.md#5-tool-output-and-prompt-injection-dsc-20",
623
+ "severityHint": "advisory"
624
+ },
625
+ "C-20.1": {
626
+ "title": "systemPrompt 出现指令样文本或外部实参",
627
+ "why": "指令样字面量、来自 fetch/工具结果的实参值得人工复核。",
628
+ "fix": "用边界标记包裹外部文本;systemPrompt 保持静态,测试/规则表应排除在扫描之外。",
629
+ "docs": "docs/security.md#5-tool-output-and-prompt-injection-dsc-20",
630
+ "severityHint": "advisory"
631
+ },
632
+ "C-21": {
633
+ "title": "依赖名与官方/常见名过于相似",
634
+ "why": "编辑距离 ≤1、scope 同形字是 typosquat 的典型形态,但相似不等于恶意。",
635
+ "fix": "核对依赖来源;优先使用精确的官方包名与 lockfile 校验。",
636
+ "docs": "docs/security.md#6-dependencies-build-and-publish-dsc-15-dsc-21-dsc-22",
637
+ "severityHint": "warn"
638
+ },
639
+ "C-21.1": {
640
+ "title": "依赖名与已知包名相差一个编辑距离",
641
+ "why": "dsh-toools 之类的名字会误导安装者。",
642
+ "fix": "改成正确的包名;确认 registry 上的发布者与仓库。",
643
+ "docs": "docs/security.md#6-dependencies-build-and-publish-dsc-15-dsc-21-dsc-22",
644
+ "severityHint": "warn"
645
+ },
646
+ "C-21.2": {
647
+ "title": "依赖 scope 与官方 scope 同形",
648
+ "why": "@deepseek-aii 等 scope 会伪装成官方命名空间。",
649
+ "fix": "只使用真实的 @deepseek-ai scope,或改用你自己的 scope。",
650
+ "docs": "docs/security.md#6-dependencies-build-and-publish-dsc-15-dsc-21-dsc-22",
651
+ "severityHint": "warn"
652
+ },
653
+ "C-21.3": {
654
+ "title": "依赖安装脚本与传递元数据 not-run",
655
+ "why": "包内没有依赖树/registry 元数据,不能假装检查过;无 lockfile 不作为缺陷。",
656
+ "fix": "需要时提供 lockfile 与 registry 元数据;本检查不因缺 lockfile 扣分。",
657
+ "docs": "docs/security.md#6-dependencies-build-and-publish-dsc-15-dsc-21-dsc-22",
658
+ "severityHint": "advisory"
659
+ },
660
+ "C-22": {
661
+ "title": "来源/完整性只做 advisory",
662
+ "why": "dist.integrity 只证 tarball 与 registry 一致;attestation/签名存在也不等于可信。",
663
+ "fix": "提供 integrity 或 attestation;人工核对发布者与构建链,本检查不写“已验证”。",
664
+ "docs": "docs/security.md#6-dependencies-build-and-publish-dsc-15-dsc-21-dsc-22",
665
+ "severityHint": "advisory"
666
+ },
667
+ "C-22.1": {
668
+ "title": "完整性/来源输入缺失即 not-run",
669
+ "why": "没有 registry 元数据或 attestation 时无法判断,缺失不等于失败。",
670
+ "fix": "在发布流程中生成 provenance/attestation,并把 dist.integrity 一并保留。",
671
+ "docs": "docs/security.md#6-dependencies-build-and-publish-dsc-15-dsc-21-dsc-22",
672
+ "severityHint": "advisory"
477
673
  }
478
674
  }