ai-developer-skill-os 8.1.7 → 8.1.9
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.
- package/.agents/README.md +3 -3
- package/.agents/skills/qk-code-review/SKILL.md +189 -0
- package/.agents/skills/qk-code-review/references/ai/ai-anti-patterns.md +28 -0
- package/.agents/skills/qk-code-review/references/ai/v8-schema-validation.md +65 -0
- package/.agents/skills/qk-code-review/references/cross-cutting/architecture-review-guide.md +212 -0
- package/.agents/skills/qk-code-review/references/cross-cutting/async-concurrency-patterns.md +515 -0
- package/.agents/skills/qk-code-review/references/cross-cutting/code-quality-universal.md +358 -0
- package/.agents/skills/qk-code-review/references/cross-cutting/code-review-best-practices.md +136 -0
- package/.agents/skills/qk-code-review/references/cross-cutting/common-bugs-checklist.md +124 -0
- package/.agents/skills/qk-code-review/references/cross-cutting/error-handling-principles.md +492 -0
- package/.agents/skills/qk-code-review/references/cross-cutting/n-plus-one-queries.md +309 -0
- package/.agents/skills/qk-code-review/references/cross-cutting/performance-review-guide.md +387 -0
- package/.agents/skills/qk-code-review/references/cross-cutting/security-review-guide.md +318 -0
- package/.agents/skills/qk-code-review/references/cross-cutting/sql-injection-prevention.md +308 -0
- package/.agents/skills/qk-code-review/references/cross-cutting/xss-prevention.md +264 -0
- package/.agents/skills/qk-code-review/references/languages/angular.md +768 -0
- package/.agents/skills/qk-code-review/references/languages/c.md +890 -0
- package/.agents/skills/qk-code-review/references/languages/cpp.md +893 -0
- package/.agents/skills/qk-code-review/references/languages/csharp.md +519 -0
- package/.agents/skills/qk-code-review/references/languages/css-less-sass.md +661 -0
- package/.agents/skills/qk-code-review/references/languages/django.md +985 -0
- package/.agents/skills/qk-code-review/references/languages/fastapi.md +580 -0
- package/.agents/skills/qk-code-review/references/languages/go.md +993 -0
- package/.agents/skills/qk-code-review/references/languages/java.md +409 -0
- package/.agents/skills/qk-code-review/references/languages/java8.md +586 -0
- package/.agents/skills/qk-code-review/references/languages/kotlin.md +1018 -0
- package/.agents/skills/qk-code-review/references/languages/nestjs.md +593 -0
- package/.agents/skills/qk-code-review/references/languages/php.md +684 -0
- package/.agents/skills/qk-code-review/references/languages/python.md +1073 -0
- package/.agents/skills/qk-code-review/references/languages/qt.md +757 -0
- package/.agents/skills/qk-code-review/references/languages/react.md +871 -0
- package/.agents/skills/qk-code-review/references/languages/ruby.md +964 -0
- package/.agents/skills/qk-code-review/references/languages/rust.md +846 -0
- package/.agents/skills/qk-code-review/references/languages/svelte.md +1064 -0
- package/.agents/skills/qk-code-review/references/languages/swift.md +936 -0
- package/.agents/skills/qk-code-review/references/languages/typescript.md +1016 -0
- package/.agents/skills/qk-code-review/references/languages/vue.md +924 -0
- package/.agents/skills/qk-code-review/references/languages/zig.md +440 -0
- package/README.md +3 -3
- package/bin/install.js +5 -2
- package/package.json +1 -1
|
@@ -0,0 +1,264 @@
|
|
|
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 | `<script>` 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`)
|