@humanbased/crosscheck 1.2.0-beta.80 → 1.2.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 (301) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +388 -149
  3. package/README.zh.md +1 -1
  4. package/crosscheck.config.example.yml +2 -63
  5. package/dist/__tests__/codex.test.js +27 -14
  6. package/dist/__tests__/codex.test.js.map +1 -1
  7. package/dist/__tests__/comment-bodies.test.js +1 -49
  8. package/dist/__tests__/comment-bodies.test.js.map +1 -1
  9. package/dist/__tests__/conflict-resolve.test.js +1 -44
  10. package/dist/__tests__/conflict-resolve.test.js.map +1 -1
  11. package/dist/__tests__/fix.test.js +0 -33
  12. package/dist/__tests__/fix.test.js.map +1 -1
  13. package/dist/__tests__/onboard-preservation.test.js +0 -5
  14. package/dist/__tests__/onboard-preservation.test.js.map +1 -1
  15. package/dist/__tests__/optimize.test.js +0 -2
  16. package/dist/__tests__/optimize.test.js.map +1 -1
  17. package/dist/__tests__/repo-picker.test.js +1 -7
  18. package/dist/__tests__/repo-picker.test.js.map +1 -1
  19. package/dist/__tests__/review-comment-body.test.js +0 -35
  20. package/dist/__tests__/review-comment-body.test.js.map +1 -1
  21. package/dist/__tests__/review-models.test.js +3 -19
  22. package/dist/__tests__/review-models.test.js.map +1 -1
  23. package/dist/__tests__/runner.test.js +1 -29
  24. package/dist/__tests__/runner.test.js.map +1 -1
  25. package/dist/cli.js +0 -29
  26. package/dist/cli.js.map +1 -1
  27. package/dist/commands/onboard.d.ts +0 -11
  28. package/dist/commands/onboard.d.ts.map +1 -1
  29. package/dist/commands/onboard.js +2 -88
  30. package/dist/commands/onboard.js.map +1 -1
  31. package/dist/commands/review.d.ts.map +1 -1
  32. package/dist/commands/review.js +6 -65
  33. package/dist/commands/review.js.map +1 -1
  34. package/dist/commands/run.d.ts.map +1 -1
  35. package/dist/commands/run.js +3 -23
  36. package/dist/commands/run.js.map +1 -1
  37. package/dist/commands/status.d.ts.map +1 -1
  38. package/dist/commands/status.js +1 -53
  39. package/dist/commands/status.js.map +1 -1
  40. package/dist/commands/watch.d.ts.map +1 -1
  41. package/dist/commands/watch.js +6 -52
  42. package/dist/commands/watch.js.map +1 -1
  43. package/dist/config/loader.d.ts +1 -3
  44. package/dist/config/loader.d.ts.map +1 -1
  45. package/dist/config/loader.js +0 -13
  46. package/dist/config/loader.js.map +1 -1
  47. package/dist/config/review-model-tiers.json +3 -3
  48. package/dist/config/schema.d.ts +10 -254
  49. package/dist/config/schema.d.ts.map +1 -1
  50. package/dist/config/schema.js +2 -62
  51. package/dist/config/schema.js.map +1 -1
  52. package/dist/github/client.d.ts +1 -6
  53. package/dist/github/client.d.ts.map +1 -1
  54. package/dist/github/client.js +7 -15
  55. package/dist/github/client.js.map +1 -1
  56. package/dist/issues/ticket-ref.d.ts.map +1 -1
  57. package/dist/issues/ticket-ref.js +5 -6
  58. package/dist/issues/ticket-ref.js.map +1 -1
  59. package/dist/lib/clone.d.ts +0 -1
  60. package/dist/lib/clone.d.ts.map +1 -1
  61. package/dist/lib/clone.js +10 -32
  62. package/dist/lib/clone.js.map +1 -1
  63. package/dist/lib/comment-bodies.d.ts +0 -35
  64. package/dist/lib/comment-bodies.d.ts.map +1 -1
  65. package/dist/lib/comment-bodies.js +9 -43
  66. package/dist/lib/comment-bodies.js.map +1 -1
  67. package/dist/lib/repo-picker.d.ts +0 -3
  68. package/dist/lib/repo-picker.d.ts.map +1 -1
  69. package/dist/lib/repo-picker.js +9 -45
  70. package/dist/lib/repo-picker.js.map +1 -1
  71. package/dist/lib/review-models.d.ts +2 -15
  72. package/dist/lib/review-models.d.ts.map +1 -1
  73. package/dist/lib/review-models.js +6 -26
  74. package/dist/lib/review-models.js.map +1 -1
  75. package/dist/lib/runner.d.ts +0 -12
  76. package/dist/lib/runner.d.ts.map +1 -1
  77. package/dist/lib/runner.js +42 -186
  78. package/dist/lib/runner.js.map +1 -1
  79. package/dist/lib/workflow.d.ts +0 -9
  80. package/dist/lib/workflow.d.ts.map +1 -1
  81. package/dist/lib/workflow.js +0 -20
  82. package/dist/lib/workflow.js.map +1 -1
  83. package/dist/reviewers/claude.d.ts +1 -4
  84. package/dist/reviewers/claude.d.ts.map +1 -1
  85. package/dist/reviewers/claude.js +7 -39
  86. package/dist/reviewers/claude.js.map +1 -1
  87. package/dist/reviewers/codex.d.ts +1 -3
  88. package/dist/reviewers/codex.d.ts.map +1 -1
  89. package/dist/reviewers/codex.js +70 -76
  90. package/dist/reviewers/codex.js.map +1 -1
  91. package/dist/reviewers/conflict-resolve.d.ts +1 -3
  92. package/dist/reviewers/conflict-resolve.d.ts.map +1 -1
  93. package/dist/reviewers/conflict-resolve.js +6 -21
  94. package/dist/reviewers/conflict-resolve.js.map +1 -1
  95. package/dist/reviewers/fix.d.ts +2 -5
  96. package/dist/reviewers/fix.d.ts.map +1 -1
  97. package/dist/reviewers/fix.js +10 -26
  98. package/dist/reviewers/fix.js.map +1 -1
  99. package/get-started.md +4 -139
  100. package/package.json +3 -4
  101. package/assets/icon-256.png +0 -0
  102. package/assets/linear-comment.svg +0 -18
  103. package/assets/linear-onboard.svg +0 -30
  104. package/assets/linear-status.svg +0 -23
  105. package/assets/linear-test.svg +0 -34
  106. package/assets/skills/code-review/.crosscheck-skill.json +0 -9
  107. package/assets/skills/code-review/LICENSE +0 -21
  108. package/assets/skills/code-review/SKILL.md +0 -89
  109. package/assets/skills/code-review/agents/openai.yaml +0 -3
  110. package/assets/skills/code-review-skill/.crosscheck-skill.json +0 -9
  111. package/assets/skills/code-review-skill/LICENSE +0 -21
  112. package/assets/skills/code-review-skill/SKILL.md +0 -231
  113. package/assets/skills/code-review-skill/assets/pr-review-template.md +0 -137
  114. package/assets/skills/code-review-skill/assets/review-checklist.md +0 -123
  115. package/assets/skills/code-review-skill/reference/angular.md +0 -768
  116. package/assets/skills/code-review-skill/reference/architecture-review-guide.md +0 -472
  117. package/assets/skills/code-review-skill/reference/c.md +0 -890
  118. package/assets/skills/code-review-skill/reference/code-quality-universal.md +0 -488
  119. package/assets/skills/code-review-skill/reference/code-review-best-practices.md +0 -136
  120. package/assets/skills/code-review-skill/reference/common-bugs-checklist.md +0 -286
  121. package/assets/skills/code-review-skill/reference/cpp.md +0 -893
  122. package/assets/skills/code-review-skill/reference/cross-cutting/async-concurrency-patterns.md +0 -515
  123. package/assets/skills/code-review-skill/reference/cross-cutting/error-handling-principles.md +0 -492
  124. package/assets/skills/code-review-skill/reference/cross-cutting/n-plus-one-queries.md +0 -309
  125. package/assets/skills/code-review-skill/reference/cross-cutting/sql-injection-prevention.md +0 -308
  126. package/assets/skills/code-review-skill/reference/cross-cutting/xss-prevention.md +0 -264
  127. package/assets/skills/code-review-skill/reference/csharp.md +0 -525
  128. package/assets/skills/code-review-skill/reference/css-less-sass.md +0 -661
  129. package/assets/skills/code-review-skill/reference/django.md +0 -985
  130. package/assets/skills/code-review-skill/reference/fastapi.md +0 -580
  131. package/assets/skills/code-review-skill/reference/go.md +0 -993
  132. package/assets/skills/code-review-skill/reference/java.md +0 -409
  133. package/assets/skills/code-review-skill/reference/java8.md +0 -586
  134. package/assets/skills/code-review-skill/reference/kotlin.md +0 -1018
  135. package/assets/skills/code-review-skill/reference/nestjs.md +0 -593
  136. package/assets/skills/code-review-skill/reference/performance-review-guide.md +0 -816
  137. package/assets/skills/code-review-skill/reference/php.md +0 -684
  138. package/assets/skills/code-review-skill/reference/python.md +0 -1073
  139. package/assets/skills/code-review-skill/reference/qt.md +0 -757
  140. package/assets/skills/code-review-skill/reference/react.md +0 -871
  141. package/assets/skills/code-review-skill/reference/ruby.md +0 -964
  142. package/assets/skills/code-review-skill/reference/rust.md +0 -846
  143. package/assets/skills/code-review-skill/reference/security-review-guide.md +0 -494
  144. package/assets/skills/code-review-skill/reference/svelte.md +0 -1064
  145. package/assets/skills/code-review-skill/reference/swift.md +0 -936
  146. package/assets/skills/code-review-skill/reference/typescript.md +0 -1016
  147. package/assets/skills/code-review-skill/reference/vue.md +0 -924
  148. package/assets/skills/code-review-skill/reference/zig.md +0 -440
  149. package/assets/skills/code-review-skill/scripts/pr-analyzer.py +0 -435
  150. package/assets/skills/code-review-skill/scripts/test_pr_analyzer.py +0 -380
  151. package/assets/skills/codebase-design/.crosscheck-skill.json +0 -9
  152. package/assets/skills/codebase-design/DEEPENING.md +0 -37
  153. package/assets/skills/codebase-design/DESIGN-IT-TWICE.md +0 -44
  154. package/assets/skills/codebase-design/LICENSE +0 -21
  155. package/assets/skills/codebase-design/SKILL.md +0 -114
  156. package/assets/skills/codebase-design/agents/openai.yaml +0 -3
  157. package/assets/skills/diagnosing-bugs/.crosscheck-skill.json +0 -9
  158. package/assets/skills/diagnosing-bugs/LICENSE +0 -21
  159. package/assets/skills/diagnosing-bugs/SKILL.md +0 -134
  160. package/assets/skills/diagnosing-bugs/agents/openai.yaml +0 -3
  161. package/assets/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
  162. package/dist/__tests__/can-write-verdict.test.d.ts +0 -2
  163. package/dist/__tests__/can-write-verdict.test.d.ts.map +0 -1
  164. package/dist/__tests__/can-write-verdict.test.js +0 -31
  165. package/dist/__tests__/can-write-verdict.test.js.map +0 -1
  166. package/dist/__tests__/linear-branding.test.d.ts +0 -2
  167. package/dist/__tests__/linear-branding.test.d.ts.map +0 -1
  168. package/dist/__tests__/linear-branding.test.js +0 -156
  169. package/dist/__tests__/linear-branding.test.js.map +0 -1
  170. package/dist/__tests__/linear-client.test.d.ts +0 -2
  171. package/dist/__tests__/linear-client.test.d.ts.map +0 -1
  172. package/dist/__tests__/linear-client.test.js +0 -120
  173. package/dist/__tests__/linear-client.test.js.map +0 -1
  174. package/dist/__tests__/linear-comment.test.d.ts +0 -2
  175. package/dist/__tests__/linear-comment.test.d.ts.map +0 -1
  176. package/dist/__tests__/linear-comment.test.js +0 -151
  177. package/dist/__tests__/linear-comment.test.js.map +0 -1
  178. package/dist/__tests__/linear-identity.test.d.ts +0 -2
  179. package/dist/__tests__/linear-identity.test.d.ts.map +0 -1
  180. package/dist/__tests__/linear-identity.test.js +0 -253
  181. package/dist/__tests__/linear-identity.test.js.map +0 -1
  182. package/dist/__tests__/linear-notify.test.d.ts +0 -2
  183. package/dist/__tests__/linear-notify.test.d.ts.map +0 -1
  184. package/dist/__tests__/linear-notify.test.js +0 -144
  185. package/dist/__tests__/linear-notify.test.js.map +0 -1
  186. package/dist/__tests__/linear-ref.test.d.ts +0 -2
  187. package/dist/__tests__/linear-ref.test.d.ts.map +0 -1
  188. package/dist/__tests__/linear-ref.test.js +0 -261
  189. package/dist/__tests__/linear-ref.test.js.map +0 -1
  190. package/dist/__tests__/linear-test-ref.test.d.ts +0 -2
  191. package/dist/__tests__/linear-test-ref.test.d.ts.map +0 -1
  192. package/dist/__tests__/linear-test-ref.test.js +0 -81
  193. package/dist/__tests__/linear-test-ref.test.js.map +0 -1
  194. package/dist/__tests__/linear-verify.test.d.ts +0 -2
  195. package/dist/__tests__/linear-verify.test.d.ts.map +0 -1
  196. package/dist/__tests__/linear-verify.test.js +0 -132
  197. package/dist/__tests__/linear-verify.test.js.map +0 -1
  198. package/dist/__tests__/linear-worker.test.d.ts +0 -2
  199. package/dist/__tests__/linear-worker.test.d.ts.map +0 -1
  200. package/dist/__tests__/linear-worker.test.js +0 -83
  201. package/dist/__tests__/linear-worker.test.js.map +0 -1
  202. package/dist/__tests__/linear-write-possible.test.d.ts +0 -2
  203. package/dist/__tests__/linear-write-possible.test.d.ts.map +0 -1
  204. package/dist/__tests__/linear-write-possible.test.js +0 -30
  205. package/dist/__tests__/linear-write-possible.test.js.map +0 -1
  206. package/dist/__tests__/repository-guidance.test.d.ts +0 -2
  207. package/dist/__tests__/repository-guidance.test.d.ts.map +0 -1
  208. package/dist/__tests__/repository-guidance.test.js +0 -107
  209. package/dist/__tests__/repository-guidance.test.js.map +0 -1
  210. package/dist/__tests__/review-strategy.test.d.ts +0 -2
  211. package/dist/__tests__/review-strategy.test.d.ts.map +0 -1
  212. package/dist/__tests__/review-strategy.test.js +0 -195
  213. package/dist/__tests__/review-strategy.test.js.map +0 -1
  214. package/dist/__tests__/skill-attribution.test.d.ts +0 -2
  215. package/dist/__tests__/skill-attribution.test.d.ts.map +0 -1
  216. package/dist/__tests__/skill-attribution.test.js +0 -53
  217. package/dist/__tests__/skill-attribution.test.js.map +0 -1
  218. package/dist/__tests__/skill-broker.test.d.ts +0 -2
  219. package/dist/__tests__/skill-broker.test.d.ts.map +0 -1
  220. package/dist/__tests__/skill-broker.test.js +0 -144
  221. package/dist/__tests__/skill-broker.test.js.map +0 -1
  222. package/dist/__tests__/skill-catalog.test.d.ts +0 -2
  223. package/dist/__tests__/skill-catalog.test.d.ts.map +0 -1
  224. package/dist/__tests__/skill-catalog.test.js +0 -40
  225. package/dist/__tests__/skill-catalog.test.js.map +0 -1
  226. package/dist/__tests__/skill-installer.test.d.ts +0 -2
  227. package/dist/__tests__/skill-installer.test.d.ts.map +0 -1
  228. package/dist/__tests__/skill-installer.test.js +0 -96
  229. package/dist/__tests__/skill-installer.test.js.map +0 -1
  230. package/dist/__tests__/skills-config.test.d.ts +0 -2
  231. package/dist/__tests__/skills-config.test.d.ts.map +0 -1
  232. package/dist/__tests__/skills-config.test.js +0 -12
  233. package/dist/__tests__/skills-config.test.js.map +0 -1
  234. package/dist/commands/linear-test.d.ts +0 -18
  235. package/dist/commands/linear-test.d.ts.map +0 -1
  236. package/dist/commands/linear-test.js +0 -130
  237. package/dist/commands/linear-test.js.map +0 -1
  238. package/dist/commands/skill.d.ts +0 -2
  239. package/dist/commands/skill.d.ts.map +0 -1
  240. package/dist/commands/skill.js +0 -16
  241. package/dist/commands/skill.js.map +0 -1
  242. package/dist/config/review-strategy.json +0 -202
  243. package/dist/lib/repository-guidance.d.ts +0 -2
  244. package/dist/lib/repository-guidance.d.ts.map +0 -1
  245. package/dist/lib/repository-guidance.js +0 -55
  246. package/dist/lib/repository-guidance.js.map +0 -1
  247. package/dist/lib/review-strategy.d.ts +0 -62
  248. package/dist/lib/review-strategy.d.ts.map +0 -1
  249. package/dist/lib/review-strategy.js +0 -235
  250. package/dist/lib/review-strategy.js.map +0 -1
  251. package/dist/linear/client.d.ts +0 -18
  252. package/dist/linear/client.d.ts.map +0 -1
  253. package/dist/linear/client.js +0 -67
  254. package/dist/linear/client.js.map +0 -1
  255. package/dist/linear/comment.d.ts +0 -20
  256. package/dist/linear/comment.d.ts.map +0 -1
  257. package/dist/linear/comment.js +0 -57
  258. package/dist/linear/comment.js.map +0 -1
  259. package/dist/linear/identity.d.ts +0 -59
  260. package/dist/linear/identity.d.ts.map +0 -1
  261. package/dist/linear/identity.js +0 -187
  262. package/dist/linear/identity.js.map +0 -1
  263. package/dist/linear/notify.d.ts +0 -35
  264. package/dist/linear/notify.d.ts.map +0 -1
  265. package/dist/linear/notify.js +0 -76
  266. package/dist/linear/notify.js.map +0 -1
  267. package/dist/linear/ref.d.ts +0 -13
  268. package/dist/linear/ref.d.ts.map +0 -1
  269. package/dist/linear/ref.js +0 -90
  270. package/dist/linear/ref.js.map +0 -1
  271. package/dist/linear/verify.d.ts +0 -26
  272. package/dist/linear/verify.d.ts.map +0 -1
  273. package/dist/linear/verify.js +0 -67
  274. package/dist/linear/verify.js.map +0 -1
  275. package/dist/skills/attribution.d.ts +0 -4
  276. package/dist/skills/attribution.d.ts.map +0 -1
  277. package/dist/skills/attribution.js +0 -14
  278. package/dist/skills/attribution.js.map +0 -1
  279. package/dist/skills/broker-server.d.ts +0 -2
  280. package/dist/skills/broker-server.d.ts.map +0 -1
  281. package/dist/skills/broker-server.js +0 -17
  282. package/dist/skills/broker-server.js.map +0 -1
  283. package/dist/skills/broker.d.ts +0 -42
  284. package/dist/skills/broker.d.ts.map +0 -1
  285. package/dist/skills/broker.js +0 -285
  286. package/dist/skills/broker.js.map +0 -1
  287. package/dist/skills/catalog.d.ts +0 -28
  288. package/dist/skills/catalog.d.ts.map +0 -1
  289. package/dist/skills/catalog.js +0 -104
  290. package/dist/skills/catalog.js.map +0 -1
  291. package/dist/skills/installer.d.ts +0 -10
  292. package/dist/skills/installer.d.ts.map +0 -1
  293. package/dist/skills/installer.js +0 -138
  294. package/dist/skills/installer.js.map +0 -1
  295. package/dist/skills/integrity.d.ts +0 -4
  296. package/dist/skills/integrity.d.ts.map +0 -1
  297. package/dist/skills/integrity.js +0 -36
  298. package/dist/skills/integrity.js.map +0 -1
  299. package/docs/dynamic-thoroughness.md +0 -286
  300. package/docs/linear-identity-contract.md +0 -139
  301. package/docs/linear-identity.md +0 -293
@@ -1,264 +0,0 @@
1
- # XSS Prevention Guide
2
-
3
- Language-agnostic Cross-Site Scripting prevention strategies with cross-framework code examples.
4
-
5
- > **Related**: [Security Review Guide](../security-review-guide.md) for comprehensive security checklist and decision framework.
6
-
7
- ## XSS Types
8
-
9
- XSS is ranked #3 in the OWASP Top 10 (2021, merged with Injection). Three variants:
10
-
11
- | Type | Description | Attack Vector |
12
- |------|-------------|---------------|
13
- | **Reflected** | Malicious script reflected off the server in the response | URL parameters, form submissions |
14
- | **Stored (Persistent)** | Malicious script stored in the database and served to users | Comments, profiles, messages |
15
- | **DOM-based** | Client-side JavaScript modifies the DOM unsafely | `innerHTML`, `document.write()`, `eval()` |
16
-
17
- ## Universal Prevention Strategy
18
-
19
- 1. **Output encoding** — encode data for the context it's rendered in (HTML, JS, URL, CSS)
20
- 2. **Content Security Policy (CSP)** — restrict which scripts can execute
21
- 3. **Input sanitization** — only when rich text is required (DOMPurify)
22
- 4. **Framework auto-escaping** — rely on framework defaults, audit escape hatches
23
-
24
- > **Key distinction**: Input validation prevents bad data from entering the system. Output encoding prevents bad data from being rendered as code. Both are necessary; neither alone is sufficient.
25
-
26
- ---
27
-
28
- ## Cross-Framework Examples
29
-
30
- ### React
31
-
32
- ```typescript
33
- // ✅ React auto-escapes JSX expressions (default safe)
34
- return <div>{userInput}</div>;
35
-
36
- // ❌ dangerouslySetInnerHTML bypasses escaping
37
- return <div dangerouslySetInnerHTML={{ __html: userInput }} />;
38
-
39
- // ✅ If HTML is required, sanitize first
40
- import DOMPurify from 'dompurify';
41
- return <div dangerouslySetInnerHTML={{
42
- __html: DOMPurify.sanitize(userInput)
43
- }} />;
44
-
45
- // ❌ href with javascript: protocol
46
- return <a href={`javascript:void(${userInput})`}>Click</a>;
47
-
48
- // ✅ Validate URL protocol
49
- const safeUrl = userInput.startsWith('https://') ? userInput : '#';
50
- return <a href={safeUrl}>Click</a>;
51
-
52
- // ❌ eval / new Function with user input
53
- const result = eval(userInput);
54
-
55
- // ❌ innerHTML in refs / effects
56
- useEffect(() => {
57
- ref.current.innerHTML = userInput;
58
- }, [userInput]);
59
- ```
60
-
61
- ### Vue
62
-
63
- ```html
64
- <!-- ✅ Vue auto-escapes text interpolation -->
65
- <div>{{ userInput }}</div>
66
-
67
- <!-- ❌ v-html bypasses escaping -->
68
- <div v-html="userInput"></div>
69
-
70
- <!-- ✅ Sanitize before v-html -->
71
- <div v-html="sanitized(userInput)"></div>
72
- ```
73
-
74
- ```typescript
75
- import DOMPurify from 'dompurify';
76
-
77
- export default {
78
- methods: {
79
- sanitized(input: string): string {
80
- return DOMPurify.sanitize(input);
81
- }
82
- }
83
- };
84
-
85
- // ❌ v-bind:href with javascript: protocol
86
- // <a :href="userInput">Click</a> — userInput could be "javascript:alert(1)"
87
- ```
88
-
89
- ### Angular
90
-
91
- ```typescript
92
- // ✅ Angular auto-escapes interpolation (default safe)
93
- template: `<div>{{ userInput }}</div>`
94
-
95
- // ❌ bypassSecurityTrustHtml disables sanitization
96
- import { DomSanitizer } from '@angular/platform-browser';
97
-
98
- constructor(private sanitizer: DomSanitizer) {
99
- this.unsafe = this.sanitizer.bypassSecurityTrustHtml(userInput);
100
- }
101
-
102
- // ❌ bypassSecurityTrustUrl with javascript: protocol
103
- this.unsafeUrl = this.sanitizer.bypassSecurityTrustUrl(userInput);
104
-
105
- // ✅ Only use bypassSecurityTrust* with server-validated content
106
- // and document the reason
107
- ```
108
-
109
- ### Svelte
110
-
111
- ```svelte
112
- <!-- ✅ Svelte auto-escapes expressions -->
113
- <div>{userInput}</div>
114
-
115
- <!-- ❌ {@html} bypasses escaping -->
116
- <div>{@html userInput}</div>
117
-
118
- <!-- ✅ Sanitize before {@html} -->
119
- <script>
120
- import DOMPurify from 'dompurify';
121
- const sanitized = DOMPurify.sanitize(userInput);
122
- </script>
123
- <div>{@html sanitized}</div>
124
- ```
125
-
126
- ### Django (Server-Side)
127
-
128
- ```python
129
- # ✅ Django auto-escapes template variables
130
- # template: <p>{{ user_bio }}</p>
131
-
132
- # ❌ mark_safe bypasses auto-escaping
133
- from django.utils.safestring import mark_safe
134
- return HttpResponse(mark_safe(f"<p>{user_bio}</p>"))
135
-
136
- # ❌ autoescape off in template
137
- # {% autoescape off %}{{ user_bio }}{% endautoescape %}
138
-
139
- # ✅ If mark_safe is necessary, escape first
140
- from django.utils.html import escape
141
- return HttpResponse(mark_safe(f"<p>{escape(user_bio)}</p>"))
142
- ```
143
-
144
- ### Server-Side Rendering
145
-
146
- ```typescript
147
- // ❌ SSR: injecting raw user data into HTML
148
- const html = `<div>${userInput}</div>`;
149
-
150
- // ✅ Always escape server-side rendered content
151
- import escapeHtml from 'escape-html';
152
- const html = `<div>${escapeHtml(userInput)}</div>`;
153
-
154
- // ❌ JSON serialization without escaping
155
- const json = JSON.stringify({ name: userInput });
156
- // userInput could contain </script> to break out of script tags
157
-
158
- // ✅ JSON in HTML: escape < and >
159
- const safe = JSON.stringify({ name: userInput })
160
- .replace(/</g, '\\u003c')
161
- .replace(/>/g, '\\u003e');
162
- ```
163
-
164
- ---
165
-
166
- ## Content Security Policy (CSP)
167
-
168
- CSP is defense-in-depth. Even if XSS escapes output encoding, CSP limits what an attacker can do.
169
-
170
- ```nginx
171
- # ✅ Recommended CSP (strict)
172
- Content-Security-Policy:
173
- default-src 'self';
174
- script-src 'self' 'nonce-{random}' 'strict-dynamic';
175
- style-src 'self' 'unsafe-inline';
176
- img-src 'self' data: https:;
177
- object-src 'none';
178
- base-uri 'self';
179
- form-action 'self';
180
- frame-ancestors 'none';
181
- ```
182
-
183
- ```typescript
184
- // ✅ Express middleware
185
- import helmet from 'helmet';
186
-
187
- app.use(helmet.contentSecurityPolicy({
188
- directives: {
189
- defaultSrc: ["'self'"],
190
- scriptSrc: ["'self'", "'nonce-{random}'"],
191
- styleSrc: ["'self'", "'unsafe-inline'"],
192
- objectSrc: ["'none'"],
193
- baseUri: ["'self'"],
194
- formAction: ["'self'"],
195
- frameAncestors: ["'none'"],
196
- },
197
- }));
198
- ```
199
-
200
- ```html
201
- <!-- ✅ CSP nonce in script tags -->
202
- <script nonce="{random}">
203
- // Allowed by CSP
204
- </script>
205
-
206
- <!-- ❌ Inline event handlers (blocked by CSP without 'unsafe-inline') -->
207
- <button onclick="doSomething()">Click</button>
208
-
209
- <!-- ✅ Event listeners in JS with nonce -->
210
- <script nonce="{random}">
211
- document.getElementById('btn').addEventListener('click', doSomething);
212
- </script>
213
- ```
214
-
215
- **CSP anti-patterns to avoid:**
216
- - `script-src 'unsafe-inline'` without nonce/hash
217
- - `script-src 'unsafe-eval'` (enables `eval()`)
218
- - `default-src *` (allows loading from any origin)
219
- - `script-src https:` (allows any HTTPS origin, including attacker-controlled)
220
-
221
- ---
222
-
223
- ## Input Validation vs Output Encoding
224
-
225
- | Layer | What | When | Example |
226
- |-------|------|------|---------|
227
- | **Input validation** | Reject/clean data on entry | At API boundary | Reject `<script>` in a name field |
228
- | **Output encoding** | Encode data for render context | At render time | `&lt;script&gt;` in HTML |
229
-
230
- **Rule**: Input validation is a convenience (reject obviously bad data). Output encoding is the security boundary. Never rely on input validation alone.
231
-
232
- ---
233
-
234
- ## Detection & Testing
235
-
236
- ```bash
237
- # Automated scanning
238
- # OWASP ZAP
239
- zap-cli quick-scan --spider https://example.com
240
-
241
- # Manual testing payloads
242
- <script>alert(1)</script>
243
- <img src=x onerror=alert(1)>
244
- " onmouseover="alert(1)
245
- javascript:alert(1)
246
- '-alert(1)-'
247
-
248
- # Static analysis (code review)
249
- grep -rn "innerHTML\|dangerouslySetInnerHTML\|v-html\|bypassSecurityTrust\|mark_safe\|@html\|{@html" src/
250
- grep -rn "eval(\|new Function\|document.write\|setTimeout.*string\|setInterval.*string" src/
251
- ```
252
-
253
- ---
254
-
255
- ## Review Checklist
256
-
257
- - [ ] Framework auto-escaping is relied upon by default (no manual escaping)
258
- - [ ] `dangerouslySetInnerHTML` / `v-html` / `bypassSecurityTrust` / `{@html}` / `mark_safe` are audited
259
- - [ ] All HTML rendering escape hatches are preceded by `DOMPurify.sanitize()` or equivalent
260
- - [ ] CSP is configured with nonce-based or hash-based script-src
261
- - [ ] No `eval()`, `new Function()`, or `javascript:` URLs with user input
262
- - [ ] No inline event handlers (`onclick="..."`) when CSP is enabled
263
- - [ ] Server-side rendered content is escaped before injection
264
- - [ ] JSON in HTML is properly escaped (`</script>` → `\u003c/script\u003e`)