@humanbased/crosscheck 1.2.0-beta.81 → 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 (314) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +375 -182
  3. package/README.zh.md +1 -1
  4. package/crosscheck.config.example.yml +9 -101
  5. package/dist/__tests__/board.test.js +0 -11
  6. package/dist/__tests__/board.test.js.map +1 -1
  7. package/dist/__tests__/codex.test.js +27 -14
  8. package/dist/__tests__/codex.test.js.map +1 -1
  9. package/dist/__tests__/comment-bodies.test.js +1 -49
  10. package/dist/__tests__/comment-bodies.test.js.map +1 -1
  11. package/dist/__tests__/conflict-resolve.test.js +1 -44
  12. package/dist/__tests__/conflict-resolve.test.js.map +1 -1
  13. package/dist/__tests__/fix.test.js +0 -33
  14. package/dist/__tests__/fix.test.js.map +1 -1
  15. package/dist/__tests__/onboard-preservation.test.js +3 -59
  16. package/dist/__tests__/onboard-preservation.test.js.map +1 -1
  17. package/dist/__tests__/optimize.test.js +0 -2
  18. package/dist/__tests__/optimize.test.js.map +1 -1
  19. package/dist/__tests__/repo-picker.test.js +1 -7
  20. package/dist/__tests__/repo-picker.test.js.map +1 -1
  21. package/dist/__tests__/review-comment-body.test.js +0 -35
  22. package/dist/__tests__/review-comment-body.test.js.map +1 -1
  23. package/dist/__tests__/review-models.test.js +3 -19
  24. package/dist/__tests__/review-models.test.js.map +1 -1
  25. package/dist/__tests__/runner.test.js +1 -29
  26. package/dist/__tests__/runner.test.js.map +1 -1
  27. package/dist/cli.js +0 -29
  28. package/dist/cli.js.map +1 -1
  29. package/dist/commands/onboard.d.ts +3 -36
  30. package/dist/commands/onboard.d.ts.map +1 -1
  31. package/dist/commands/onboard.js +42 -233
  32. package/dist/commands/onboard.js.map +1 -1
  33. package/dist/commands/review.d.ts.map +1 -1
  34. package/dist/commands/review.js +6 -65
  35. package/dist/commands/review.js.map +1 -1
  36. package/dist/commands/run.d.ts.map +1 -1
  37. package/dist/commands/run.js +7 -45
  38. package/dist/commands/run.js.map +1 -1
  39. package/dist/commands/status.d.ts.map +1 -1
  40. package/dist/commands/status.js +1 -53
  41. package/dist/commands/status.js.map +1 -1
  42. package/dist/commands/watch.d.ts.map +1 -1
  43. package/dist/commands/watch.js +12 -90
  44. package/dist/commands/watch.js.map +1 -1
  45. package/dist/config/loader.d.ts +1 -3
  46. package/dist/config/loader.d.ts.map +1 -1
  47. package/dist/config/loader.js +0 -13
  48. package/dist/config/loader.js.map +1 -1
  49. package/dist/config/review-model-tiers.json +3 -3
  50. package/dist/config/schema.d.ts +15 -261
  51. package/dist/config/schema.d.ts.map +1 -1
  52. package/dist/config/schema.js +8 -90
  53. package/dist/config/schema.js.map +1 -1
  54. package/dist/github/client.d.ts +1 -21
  55. package/dist/github/client.d.ts.map +1 -1
  56. package/dist/github/client.js +7 -46
  57. package/dist/github/client.js.map +1 -1
  58. package/dist/github/webhook.d.ts +0 -4
  59. package/dist/github/webhook.d.ts.map +1 -1
  60. package/dist/github/webhook.js.map +1 -1
  61. package/dist/issues/ticket-ref.d.ts.map +1 -1
  62. package/dist/issues/ticket-ref.js +5 -6
  63. package/dist/issues/ticket-ref.js.map +1 -1
  64. package/dist/lib/annotation.d.ts +0 -7
  65. package/dist/lib/annotation.d.ts.map +1 -1
  66. package/dist/lib/annotation.js +1 -11
  67. package/dist/lib/annotation.js.map +1 -1
  68. package/dist/lib/board.d.ts +0 -3
  69. package/dist/lib/board.d.ts.map +1 -1
  70. package/dist/lib/board.js +2 -4
  71. package/dist/lib/board.js.map +1 -1
  72. package/dist/lib/clone.d.ts +0 -1
  73. package/dist/lib/clone.d.ts.map +1 -1
  74. package/dist/lib/clone.js +10 -32
  75. package/dist/lib/clone.js.map +1 -1
  76. package/dist/lib/comment-bodies.d.ts +0 -37
  77. package/dist/lib/comment-bodies.d.ts.map +1 -1
  78. package/dist/lib/comment-bodies.js +9 -47
  79. package/dist/lib/comment-bodies.js.map +1 -1
  80. package/dist/lib/repo-picker.d.ts +0 -3
  81. package/dist/lib/repo-picker.d.ts.map +1 -1
  82. package/dist/lib/repo-picker.js +9 -45
  83. package/dist/lib/repo-picker.js.map +1 -1
  84. package/dist/lib/review-models.d.ts +2 -15
  85. package/dist/lib/review-models.d.ts.map +1 -1
  86. package/dist/lib/review-models.js +6 -26
  87. package/dist/lib/review-models.js.map +1 -1
  88. package/dist/lib/runner.d.ts +0 -92
  89. package/dist/lib/runner.d.ts.map +1 -1
  90. package/dist/lib/runner.js +54 -470
  91. package/dist/lib/runner.js.map +1 -1
  92. package/dist/lib/workflow.d.ts +0 -9
  93. package/dist/lib/workflow.d.ts.map +1 -1
  94. package/dist/lib/workflow.js +0 -20
  95. package/dist/lib/workflow.js.map +1 -1
  96. package/dist/reviewers/claude.d.ts +1 -4
  97. package/dist/reviewers/claude.d.ts.map +1 -1
  98. package/dist/reviewers/claude.js +7 -39
  99. package/dist/reviewers/claude.js.map +1 -1
  100. package/dist/reviewers/codex.d.ts +1 -3
  101. package/dist/reviewers/codex.d.ts.map +1 -1
  102. package/dist/reviewers/codex.js +70 -76
  103. package/dist/reviewers/codex.js.map +1 -1
  104. package/dist/reviewers/conflict-resolve.d.ts +1 -3
  105. package/dist/reviewers/conflict-resolve.d.ts.map +1 -1
  106. package/dist/reviewers/conflict-resolve.js +6 -21
  107. package/dist/reviewers/conflict-resolve.js.map +1 -1
  108. package/dist/reviewers/fix.d.ts +2 -5
  109. package/dist/reviewers/fix.d.ts.map +1 -1
  110. package/dist/reviewers/fix.js +10 -26
  111. package/dist/reviewers/fix.js.map +1 -1
  112. package/get-started.md +11 -207
  113. package/package.json +3 -4
  114. package/assets/icon-256.png +0 -0
  115. package/assets/linear-comment.svg +0 -18
  116. package/assets/linear-onboard.svg +0 -30
  117. package/assets/linear-status.svg +0 -23
  118. package/assets/linear-test.svg +0 -34
  119. package/assets/skills/code-review/.crosscheck-skill.json +0 -9
  120. package/assets/skills/code-review/LICENSE +0 -21
  121. package/assets/skills/code-review/SKILL.md +0 -89
  122. package/assets/skills/code-review/agents/openai.yaml +0 -3
  123. package/assets/skills/code-review-skill/.crosscheck-skill.json +0 -9
  124. package/assets/skills/code-review-skill/LICENSE +0 -21
  125. package/assets/skills/code-review-skill/SKILL.md +0 -231
  126. package/assets/skills/code-review-skill/assets/pr-review-template.md +0 -137
  127. package/assets/skills/code-review-skill/assets/review-checklist.md +0 -123
  128. package/assets/skills/code-review-skill/reference/angular.md +0 -768
  129. package/assets/skills/code-review-skill/reference/architecture-review-guide.md +0 -472
  130. package/assets/skills/code-review-skill/reference/c.md +0 -890
  131. package/assets/skills/code-review-skill/reference/code-quality-universal.md +0 -488
  132. package/assets/skills/code-review-skill/reference/code-review-best-practices.md +0 -136
  133. package/assets/skills/code-review-skill/reference/common-bugs-checklist.md +0 -286
  134. package/assets/skills/code-review-skill/reference/cpp.md +0 -893
  135. package/assets/skills/code-review-skill/reference/cross-cutting/async-concurrency-patterns.md +0 -515
  136. package/assets/skills/code-review-skill/reference/cross-cutting/error-handling-principles.md +0 -492
  137. package/assets/skills/code-review-skill/reference/cross-cutting/n-plus-one-queries.md +0 -309
  138. package/assets/skills/code-review-skill/reference/cross-cutting/sql-injection-prevention.md +0 -308
  139. package/assets/skills/code-review-skill/reference/cross-cutting/xss-prevention.md +0 -264
  140. package/assets/skills/code-review-skill/reference/csharp.md +0 -525
  141. package/assets/skills/code-review-skill/reference/css-less-sass.md +0 -661
  142. package/assets/skills/code-review-skill/reference/django.md +0 -985
  143. package/assets/skills/code-review-skill/reference/fastapi.md +0 -580
  144. package/assets/skills/code-review-skill/reference/go.md +0 -993
  145. package/assets/skills/code-review-skill/reference/java.md +0 -409
  146. package/assets/skills/code-review-skill/reference/java8.md +0 -586
  147. package/assets/skills/code-review-skill/reference/kotlin.md +0 -1018
  148. package/assets/skills/code-review-skill/reference/nestjs.md +0 -593
  149. package/assets/skills/code-review-skill/reference/performance-review-guide.md +0 -816
  150. package/assets/skills/code-review-skill/reference/php.md +0 -684
  151. package/assets/skills/code-review-skill/reference/python.md +0 -1073
  152. package/assets/skills/code-review-skill/reference/qt.md +0 -757
  153. package/assets/skills/code-review-skill/reference/react.md +0 -871
  154. package/assets/skills/code-review-skill/reference/ruby.md +0 -964
  155. package/assets/skills/code-review-skill/reference/rust.md +0 -846
  156. package/assets/skills/code-review-skill/reference/security-review-guide.md +0 -494
  157. package/assets/skills/code-review-skill/reference/svelte.md +0 -1064
  158. package/assets/skills/code-review-skill/reference/swift.md +0 -936
  159. package/assets/skills/code-review-skill/reference/typescript.md +0 -1016
  160. package/assets/skills/code-review-skill/reference/vue.md +0 -924
  161. package/assets/skills/code-review-skill/reference/zig.md +0 -440
  162. package/assets/skills/code-review-skill/scripts/pr-analyzer.py +0 -435
  163. package/assets/skills/code-review-skill/scripts/test_pr_analyzer.py +0 -380
  164. package/assets/skills/codebase-design/.crosscheck-skill.json +0 -9
  165. package/assets/skills/codebase-design/DEEPENING.md +0 -37
  166. package/assets/skills/codebase-design/DESIGN-IT-TWICE.md +0 -44
  167. package/assets/skills/codebase-design/LICENSE +0 -21
  168. package/assets/skills/codebase-design/SKILL.md +0 -114
  169. package/assets/skills/codebase-design/agents/openai.yaml +0 -3
  170. package/assets/skills/diagnosing-bugs/.crosscheck-skill.json +0 -9
  171. package/assets/skills/diagnosing-bugs/LICENSE +0 -21
  172. package/assets/skills/diagnosing-bugs/SKILL.md +0 -134
  173. package/assets/skills/diagnosing-bugs/agents/openai.yaml +0 -3
  174. package/assets/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
  175. package/dist/__tests__/can-write-verdict.test.d.ts +0 -2
  176. package/dist/__tests__/can-write-verdict.test.d.ts.map +0 -1
  177. package/dist/__tests__/can-write-verdict.test.js +0 -31
  178. package/dist/__tests__/can-write-verdict.test.js.map +0 -1
  179. package/dist/__tests__/linear-branding.test.d.ts +0 -2
  180. package/dist/__tests__/linear-branding.test.d.ts.map +0 -1
  181. package/dist/__tests__/linear-branding.test.js +0 -156
  182. package/dist/__tests__/linear-branding.test.js.map +0 -1
  183. package/dist/__tests__/linear-client.test.d.ts +0 -2
  184. package/dist/__tests__/linear-client.test.d.ts.map +0 -1
  185. package/dist/__tests__/linear-client.test.js +0 -120
  186. package/dist/__tests__/linear-client.test.js.map +0 -1
  187. package/dist/__tests__/linear-comment.test.d.ts +0 -2
  188. package/dist/__tests__/linear-comment.test.d.ts.map +0 -1
  189. package/dist/__tests__/linear-comment.test.js +0 -151
  190. package/dist/__tests__/linear-comment.test.js.map +0 -1
  191. package/dist/__tests__/linear-identity.test.d.ts +0 -2
  192. package/dist/__tests__/linear-identity.test.d.ts.map +0 -1
  193. package/dist/__tests__/linear-identity.test.js +0 -253
  194. package/dist/__tests__/linear-identity.test.js.map +0 -1
  195. package/dist/__tests__/linear-notify.test.d.ts +0 -2
  196. package/dist/__tests__/linear-notify.test.d.ts.map +0 -1
  197. package/dist/__tests__/linear-notify.test.js +0 -144
  198. package/dist/__tests__/linear-notify.test.js.map +0 -1
  199. package/dist/__tests__/linear-ref.test.d.ts +0 -2
  200. package/dist/__tests__/linear-ref.test.d.ts.map +0 -1
  201. package/dist/__tests__/linear-ref.test.js +0 -261
  202. package/dist/__tests__/linear-ref.test.js.map +0 -1
  203. package/dist/__tests__/linear-test-ref.test.d.ts +0 -2
  204. package/dist/__tests__/linear-test-ref.test.d.ts.map +0 -1
  205. package/dist/__tests__/linear-test-ref.test.js +0 -81
  206. package/dist/__tests__/linear-test-ref.test.js.map +0 -1
  207. package/dist/__tests__/linear-verify.test.d.ts +0 -2
  208. package/dist/__tests__/linear-verify.test.d.ts.map +0 -1
  209. package/dist/__tests__/linear-verify.test.js +0 -132
  210. package/dist/__tests__/linear-verify.test.js.map +0 -1
  211. package/dist/__tests__/linear-worker.test.d.ts +0 -2
  212. package/dist/__tests__/linear-worker.test.d.ts.map +0 -1
  213. package/dist/__tests__/linear-worker.test.js +0 -83
  214. package/dist/__tests__/linear-worker.test.js.map +0 -1
  215. package/dist/__tests__/linear-write-possible.test.d.ts +0 -2
  216. package/dist/__tests__/linear-write-possible.test.d.ts.map +0 -1
  217. package/dist/__tests__/linear-write-possible.test.js +0 -30
  218. package/dist/__tests__/linear-write-possible.test.js.map +0 -1
  219. package/dist/__tests__/repository-guidance.test.d.ts +0 -2
  220. package/dist/__tests__/repository-guidance.test.d.ts.map +0 -1
  221. package/dist/__tests__/repository-guidance.test.js +0 -107
  222. package/dist/__tests__/repository-guidance.test.js.map +0 -1
  223. package/dist/__tests__/review-strategy.test.d.ts +0 -2
  224. package/dist/__tests__/review-strategy.test.d.ts.map +0 -1
  225. package/dist/__tests__/review-strategy.test.js +0 -397
  226. package/dist/__tests__/review-strategy.test.js.map +0 -1
  227. package/dist/__tests__/skill-attribution.test.d.ts +0 -2
  228. package/dist/__tests__/skill-attribution.test.d.ts.map +0 -1
  229. package/dist/__tests__/skill-attribution.test.js +0 -53
  230. package/dist/__tests__/skill-attribution.test.js.map +0 -1
  231. package/dist/__tests__/skill-broker.test.d.ts +0 -2
  232. package/dist/__tests__/skill-broker.test.d.ts.map +0 -1
  233. package/dist/__tests__/skill-broker.test.js +0 -144
  234. package/dist/__tests__/skill-broker.test.js.map +0 -1
  235. package/dist/__tests__/skill-catalog.test.d.ts +0 -2
  236. package/dist/__tests__/skill-catalog.test.d.ts.map +0 -1
  237. package/dist/__tests__/skill-catalog.test.js +0 -40
  238. package/dist/__tests__/skill-catalog.test.js.map +0 -1
  239. package/dist/__tests__/skill-installer.test.d.ts +0 -2
  240. package/dist/__tests__/skill-installer.test.d.ts.map +0 -1
  241. package/dist/__tests__/skill-installer.test.js +0 -96
  242. package/dist/__tests__/skill-installer.test.js.map +0 -1
  243. package/dist/__tests__/skills-config.test.d.ts +0 -2
  244. package/dist/__tests__/skills-config.test.d.ts.map +0 -1
  245. package/dist/__tests__/skills-config.test.js +0 -12
  246. package/dist/__tests__/skills-config.test.js.map +0 -1
  247. package/dist/commands/linear-test.d.ts +0 -18
  248. package/dist/commands/linear-test.d.ts.map +0 -1
  249. package/dist/commands/linear-test.js +0 -130
  250. package/dist/commands/linear-test.js.map +0 -1
  251. package/dist/commands/skill.d.ts +0 -2
  252. package/dist/commands/skill.d.ts.map +0 -1
  253. package/dist/commands/skill.js +0 -16
  254. package/dist/commands/skill.js.map +0 -1
  255. package/dist/config/review-strategy.json +0 -204
  256. package/dist/lib/repository-guidance.d.ts +0 -2
  257. package/dist/lib/repository-guidance.d.ts.map +0 -1
  258. package/dist/lib/repository-guidance.js +0 -55
  259. package/dist/lib/repository-guidance.js.map +0 -1
  260. package/dist/lib/review-strategy.d.ts +0 -92
  261. package/dist/lib/review-strategy.d.ts.map +0 -1
  262. package/dist/lib/review-strategy.js +0 -282
  263. package/dist/lib/review-strategy.js.map +0 -1
  264. package/dist/linear/client.d.ts +0 -18
  265. package/dist/linear/client.d.ts.map +0 -1
  266. package/dist/linear/client.js +0 -67
  267. package/dist/linear/client.js.map +0 -1
  268. package/dist/linear/comment.d.ts +0 -20
  269. package/dist/linear/comment.d.ts.map +0 -1
  270. package/dist/linear/comment.js +0 -57
  271. package/dist/linear/comment.js.map +0 -1
  272. package/dist/linear/identity.d.ts +0 -59
  273. package/dist/linear/identity.d.ts.map +0 -1
  274. package/dist/linear/identity.js +0 -187
  275. package/dist/linear/identity.js.map +0 -1
  276. package/dist/linear/notify.d.ts +0 -35
  277. package/dist/linear/notify.d.ts.map +0 -1
  278. package/dist/linear/notify.js +0 -76
  279. package/dist/linear/notify.js.map +0 -1
  280. package/dist/linear/ref.d.ts +0 -13
  281. package/dist/linear/ref.d.ts.map +0 -1
  282. package/dist/linear/ref.js +0 -90
  283. package/dist/linear/ref.js.map +0 -1
  284. package/dist/linear/verify.d.ts +0 -26
  285. package/dist/linear/verify.d.ts.map +0 -1
  286. package/dist/linear/verify.js +0 -67
  287. package/dist/linear/verify.js.map +0 -1
  288. package/dist/skills/attribution.d.ts +0 -4
  289. package/dist/skills/attribution.d.ts.map +0 -1
  290. package/dist/skills/attribution.js +0 -14
  291. package/dist/skills/attribution.js.map +0 -1
  292. package/dist/skills/broker-server.d.ts +0 -2
  293. package/dist/skills/broker-server.d.ts.map +0 -1
  294. package/dist/skills/broker-server.js +0 -17
  295. package/dist/skills/broker-server.js.map +0 -1
  296. package/dist/skills/broker.d.ts +0 -42
  297. package/dist/skills/broker.d.ts.map +0 -1
  298. package/dist/skills/broker.js +0 -285
  299. package/dist/skills/broker.js.map +0 -1
  300. package/dist/skills/catalog.d.ts +0 -28
  301. package/dist/skills/catalog.d.ts.map +0 -1
  302. package/dist/skills/catalog.js +0 -104
  303. package/dist/skills/catalog.js.map +0 -1
  304. package/dist/skills/installer.d.ts +0 -10
  305. package/dist/skills/installer.d.ts.map +0 -1
  306. package/dist/skills/installer.js +0 -138
  307. package/dist/skills/installer.js.map +0 -1
  308. package/dist/skills/integrity.d.ts +0 -4
  309. package/dist/skills/integrity.d.ts.map +0 -1
  310. package/dist/skills/integrity.js +0 -36
  311. package/dist/skills/integrity.js.map +0 -1
  312. package/docs/dynamic-thoroughness.md +0 -738
  313. package/docs/linear-identity-contract.md +0 -139
  314. 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`)