@brunosps00/dev-workflow 0.0.5 → 0.0.7
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/bin/dev-workflow.js +6 -4
- package/lib/constants.js +11 -0
- package/lib/init.js +36 -12
- package/lib/wrappers.js +8 -2
- package/package.json +1 -1
- package/scaffold/pt-br/commands/dw-analyze-project.md +3 -3
- package/scaffold/pt-br/commands/dw-bugfix.md +6 -6
- package/scaffold/pt-br/commands/dw-code-review.md +2 -2
- package/scaffold/pt-br/commands/dw-create-tasks.md +4 -4
- package/scaffold/pt-br/commands/dw-generate-pr.md +3 -3
- package/scaffold/pt-br/commands/dw-help.md +50 -50
- package/scaffold/pt-br/commands/dw-review-implementation.md +3 -3
- package/scaffold/pt-br/commands/dw-run-plan.md +8 -8
- package/scaffold/pt-br/commands/dw-run-task.md +3 -3
- package/scaffold/pt-br/templates/tasks-template.md +2 -2
- package/scaffold/skills/agent-browser/SKILL.md +750 -0
- package/scaffold/skills/agent-browser/references/authentication.md +303 -0
- package/scaffold/skills/agent-browser/references/commands.md +295 -0
- package/scaffold/skills/agent-browser/references/profiling.md +120 -0
- package/scaffold/skills/agent-browser/references/proxy-support.md +194 -0
- package/scaffold/skills/agent-browser/references/session-management.md +193 -0
- package/scaffold/skills/agent-browser/references/snapshot-refs.md +219 -0
- package/scaffold/skills/agent-browser/references/video-recording.md +173 -0
- package/scaffold/skills/agent-browser/templates/authenticated-session.sh +105 -0
- package/scaffold/skills/agent-browser/templates/capture-workflow.sh +69 -0
- package/scaffold/skills/agent-browser/templates/form-automation.sh +62 -0
- package/scaffold/skills/humanizer/README.md +143 -0
- package/scaffold/skills/humanizer/SKILL.md +488 -0
- package/scaffold/skills/humanizer/WARP.md +53 -0
- package/scaffold/skills/remotion-best-practices/SKILL.md +61 -0
- package/scaffold/skills/remotion-best-practices/rules/3d.md +86 -0
- package/scaffold/skills/remotion-best-practices/rules/animations.md +27 -0
- package/scaffold/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
- package/scaffold/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
- package/scaffold/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +103 -0
- package/scaffold/skills/remotion-best-practices/rules/assets.md +78 -0
- package/scaffold/skills/remotion-best-practices/rules/audio-visualization.md +198 -0
- package/scaffold/skills/remotion-best-practices/rules/audio.md +169 -0
- package/scaffold/skills/remotion-best-practices/rules/calculate-metadata.md +134 -0
- package/scaffold/skills/remotion-best-practices/rules/can-decode.md +75 -0
- package/scaffold/skills/remotion-best-practices/rules/charts.md +120 -0
- package/scaffold/skills/remotion-best-practices/rules/compositions.md +154 -0
- package/scaffold/skills/remotion-best-practices/rules/display-captions.md +184 -0
- package/scaffold/skills/remotion-best-practices/rules/extract-frames.md +229 -0
- package/scaffold/skills/remotion-best-practices/rules/ffmpeg.md +38 -0
- package/scaffold/skills/remotion-best-practices/rules/fonts.md +152 -0
- package/scaffold/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
- package/scaffold/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
- package/scaffold/skills/remotion-best-practices/rules/get-video-duration.md +60 -0
- package/scaffold/skills/remotion-best-practices/rules/gifs.md +141 -0
- package/scaffold/skills/remotion-best-practices/rules/images.md +134 -0
- package/scaffold/skills/remotion-best-practices/rules/import-srt-captions.md +69 -0
- package/scaffold/skills/remotion-best-practices/rules/light-leaks.md +73 -0
- package/scaffold/skills/remotion-best-practices/rules/lottie.md +70 -0
- package/scaffold/skills/remotion-best-practices/rules/maps.md +412 -0
- package/scaffold/skills/remotion-best-practices/rules/measuring-dom-nodes.md +34 -0
- package/scaffold/skills/remotion-best-practices/rules/measuring-text.md +140 -0
- package/scaffold/skills/remotion-best-practices/rules/parameters.md +109 -0
- package/scaffold/skills/remotion-best-practices/rules/sequencing.md +118 -0
- package/scaffold/skills/remotion-best-practices/rules/sfx.md +26 -0
- package/scaffold/skills/remotion-best-practices/rules/subtitles.md +36 -0
- package/scaffold/skills/remotion-best-practices/rules/tailwind.md +11 -0
- package/scaffold/skills/remotion-best-practices/rules/text-animations.md +20 -0
- package/scaffold/skills/remotion-best-practices/rules/timing.md +179 -0
- package/scaffold/skills/remotion-best-practices/rules/transcribe-captions.md +70 -0
- package/scaffold/skills/remotion-best-practices/rules/transitions.md +197 -0
- package/scaffold/skills/remotion-best-practices/rules/transparent-videos.md +106 -0
- package/scaffold/skills/remotion-best-practices/rules/trimming.md +51 -0
- package/scaffold/skills/remotion-best-practices/rules/videos.md +171 -0
- package/scaffold/skills/remotion-best-practices/rules/voiceover.md +99 -0
- package/scaffold/skills/security-review/LICENSE +22 -0
- package/scaffold/skills/security-review/SKILL.md +312 -0
- package/scaffold/skills/security-review/infrastructure/docker.md +432 -0
- package/scaffold/skills/security-review/languages/javascript.md +388 -0
- package/scaffold/skills/security-review/languages/python.md +363 -0
- package/scaffold/skills/security-review/references/api-security.md +519 -0
- package/scaffold/skills/security-review/references/authentication.md +353 -0
- package/scaffold/skills/security-review/references/authorization.md +372 -0
- package/scaffold/skills/security-review/references/business-logic.md +443 -0
- package/scaffold/skills/security-review/references/cryptography.md +329 -0
- package/scaffold/skills/security-review/references/csrf.md +398 -0
- package/scaffold/skills/security-review/references/data-protection.md +378 -0
- package/scaffold/skills/security-review/references/deserialization.md +410 -0
- package/scaffold/skills/security-review/references/error-handling.md +436 -0
- package/scaffold/skills/security-review/references/file-security.md +457 -0
- package/scaffold/skills/security-review/references/injection.md +259 -0
- package/scaffold/skills/security-review/references/logging.md +433 -0
- package/scaffold/skills/security-review/references/misconfiguration.md +435 -0
- package/scaffold/skills/security-review/references/modern-threats.md +475 -0
- package/scaffold/skills/security-review/references/ssrf.md +415 -0
- package/scaffold/skills/security-review/references/supply-chain.md +405 -0
- package/scaffold/skills/security-review/references/xss.md +336 -0
- package/scaffold/skills/vercel-react-best-practices/AGENTS.md +3648 -0
- package/scaffold/skills/vercel-react-best-practices/README.md +123 -0
- package/scaffold/skills/vercel-react-best-practices/SKILL.md +146 -0
- package/scaffold/skills/vercel-react-best-practices/rules/_sections.md +46 -0
- package/scaffold/skills/vercel-react-best-practices/rules/_template.md +28 -0
- package/scaffold/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/scaffold/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/scaffold/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/scaffold/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/scaffold/skills/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/scaffold/skills/vercel-react-best-practices/rules/async-defer-await.md +82 -0
- package/scaffold/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/scaffold/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/scaffold/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/scaffold/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +60 -0
- package/scaffold/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/scaffold/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/scaffold/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/scaffold/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/scaffold/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/scaffold/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/scaffold/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/scaffold/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-request-idle-callback.md +105 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/scaffold/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/scaffold/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/scaffold/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/scaffold/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/scaffold/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/scaffold/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/scaffold/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/scaffold/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +149 -0
- package/scaffold/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/scaffold/skills/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
- package/scaffold/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/scaffold/skills/webapp-testing/SKILL.md +133 -0
- package/scaffold/skills/webapp-testing/assets/test-helper.js +56 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# JavaScript/TypeScript Security Patterns
|
|
2
|
+
|
|
3
|
+
## Framework Detection
|
|
4
|
+
|
|
5
|
+
| Indicator | Framework |
|
|
6
|
+
|-----------|-----------|
|
|
7
|
+
| `import React`, `jsx`, `tsx`, `useState` | React |
|
|
8
|
+
| `import Vue`, `.vue` files, `v-bind`, `v-model` | Vue |
|
|
9
|
+
| `import express`, `app.get`, `app.post` | Express |
|
|
10
|
+
| `import { Controller }`, `@nestjs` | NestJS |
|
|
11
|
+
| `import next`, `getServerSideProps` | Next.js |
|
|
12
|
+
| `import angular`, `@Component` | Angular |
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## React
|
|
17
|
+
|
|
18
|
+
### Auto-Escaped (Do Not Flag)
|
|
19
|
+
|
|
20
|
+
```jsx
|
|
21
|
+
// SAFE: JSX auto-escapes interpolated values
|
|
22
|
+
<div>{userInput}</div>
|
|
23
|
+
<span>{user.name}</span>
|
|
24
|
+
<p>{data.description}</p>
|
|
25
|
+
|
|
26
|
+
// SAFE: Setting attributes (except href/src)
|
|
27
|
+
<div className={userInput}>
|
|
28
|
+
<input value={userInput} />
|
|
29
|
+
<div data-value={userInput}>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Flag These (React-Specific)
|
|
33
|
+
|
|
34
|
+
```jsx
|
|
35
|
+
// XSS - Explicit unsafe rendering
|
|
36
|
+
<div dangerouslySetInnerHTML={{__html: userInput}} /> // FLAG: Critical
|
|
37
|
+
// Only safe if userInput is sanitized with DOMPurify or similar
|
|
38
|
+
|
|
39
|
+
// URL-based XSS
|
|
40
|
+
<a href={userInput}>Link</a> // FLAG: Check for javascript: protocol
|
|
41
|
+
<iframe src={userInput} /> // FLAG: Check for javascript: protocol
|
|
42
|
+
<script src={userInput} /> // FLAG
|
|
43
|
+
|
|
44
|
+
// eval patterns
|
|
45
|
+
eval(userInput) // FLAG: Critical
|
|
46
|
+
new Function(userInput) // FLAG: Critical
|
|
47
|
+
setTimeout(userInput, 1000) // FLAG: If string argument
|
|
48
|
+
setInterval(userInput, 1000) // FLAG: If string argument
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### React Security Checklist
|
|
52
|
+
|
|
53
|
+
```jsx
|
|
54
|
+
// CHECK: URL validation for href/src
|
|
55
|
+
const SafeLink = ({url, children}) => {
|
|
56
|
+
const isValid = url.startsWith('https://') || url.startsWith('/');
|
|
57
|
+
if (!isValid) return null;
|
|
58
|
+
return <a href={url}>{children}</a>;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// CHECK: Sanitize before dangerouslySetInnerHTML
|
|
62
|
+
import DOMPurify from 'dompurify';
|
|
63
|
+
<div dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(html)}} />
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Vue
|
|
69
|
+
|
|
70
|
+
### Auto-Escaped (Do Not Flag)
|
|
71
|
+
|
|
72
|
+
```vue
|
|
73
|
+
<!-- SAFE: Vue auto-escapes interpolation -->
|
|
74
|
+
<div>{{ userInput }}</div>
|
|
75
|
+
<span>{{ user.name }}</span>
|
|
76
|
+
|
|
77
|
+
<!-- SAFE: v-bind for attributes -->
|
|
78
|
+
<div :class="userInput">
|
|
79
|
+
<input :value="userInput" />
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Flag These (Vue-Specific)
|
|
83
|
+
|
|
84
|
+
```vue
|
|
85
|
+
<!-- XSS - Renders raw HTML -->
|
|
86
|
+
<div v-html="userInput"></div> <!-- FLAG: Critical -->
|
|
87
|
+
|
|
88
|
+
<!-- URL-based XSS -->
|
|
89
|
+
<a :href="userInput"> <!-- FLAG: Check protocol -->
|
|
90
|
+
<iframe :src="userInput" /> <!-- FLAG: Check protocol -->
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Vue Security Patterns
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
// FLAG: Dynamic component with user input
|
|
97
|
+
<component :is="userInput" /> // Could load arbitrary component
|
|
98
|
+
|
|
99
|
+
// FLAG: Template compilation with user input
|
|
100
|
+
Vue.compile(userTemplate) // Server-side template injection
|
|
101
|
+
new Vue({ template: userInput })
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Express / Node.js
|
|
107
|
+
|
|
108
|
+
### Safe Patterns (Do Not Flag)
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
// SAFE: Parameterized queries (most ORMs)
|
|
112
|
+
User.findOne({ where: { id: userId } }); // Sequelize
|
|
113
|
+
db.collection('users').findOne({ _id: userId }); // MongoDB with proper driver
|
|
114
|
+
|
|
115
|
+
// SAFE: res.json auto-serializes
|
|
116
|
+
res.json({ data: userInput });
|
|
117
|
+
|
|
118
|
+
// SAFE: Template engines escape by default
|
|
119
|
+
res.render('template', { name: userInput }); // EJS, Pug, Handlebars
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Flag These (Express-Specific)
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
// SQL Injection
|
|
126
|
+
db.query(`SELECT * FROM users WHERE id = ${userId}`); // FLAG
|
|
127
|
+
connection.query('SELECT * FROM users WHERE name = "' + name + '"'); // FLAG
|
|
128
|
+
|
|
129
|
+
// NoSQL Injection
|
|
130
|
+
db.collection('users').find({ $where: userInput }); // FLAG: Code execution
|
|
131
|
+
db.collection('users').find({ name: { $regex: userInput } }); // FLAG: ReDoS
|
|
132
|
+
|
|
133
|
+
// Command Injection
|
|
134
|
+
exec(userInput); // FLAG: Critical
|
|
135
|
+
execSync(userInput); // FLAG: Critical
|
|
136
|
+
spawn(cmd, { shell: true }); // FLAG: If cmd has user input
|
|
137
|
+
child_process.exec(userCmd); // FLAG: Critical
|
|
138
|
+
|
|
139
|
+
// Path Traversal
|
|
140
|
+
res.sendFile(userPath); // FLAG: Check path validation
|
|
141
|
+
fs.readFile(userPath); // FLAG: Check path validation
|
|
142
|
+
path.join(base, userInput); // FLAG: ../../../ possible
|
|
143
|
+
|
|
144
|
+
// SSRF
|
|
145
|
+
fetch(userUrl); // FLAG: Check URL validation
|
|
146
|
+
axios.get(userUrl); // FLAG: Check URL validation
|
|
147
|
+
http.get(userUrl); // FLAG: Check URL validation
|
|
148
|
+
|
|
149
|
+
// Prototype Pollution
|
|
150
|
+
Object.assign(target, userObject); // FLAG: If userObject from request
|
|
151
|
+
_.merge(target, userObject); // FLAG: Check lodash version
|
|
152
|
+
$.extend(true, target, userObject); // FLAG
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### MongoDB Injection
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
// VULNERABLE: Operator injection
|
|
159
|
+
db.users.find({
|
|
160
|
+
username: req.body.username, // Could be { $gt: '' }
|
|
161
|
+
password: req.body.password // Could be { $gt: '' }
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// SAFE: Type coercion
|
|
165
|
+
db.users.find({
|
|
166
|
+
username: String(req.body.username),
|
|
167
|
+
password: String(req.body.password)
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// SAFE: Schema validation (Mongoose)
|
|
171
|
+
const userSchema = new Schema({
|
|
172
|
+
username: { type: String, required: true },
|
|
173
|
+
password: { type: String, required: true }
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Next.js
|
|
180
|
+
|
|
181
|
+
### Safe Patterns
|
|
182
|
+
|
|
183
|
+
```jsx
|
|
184
|
+
// SAFE: getServerSideProps data is serialized
|
|
185
|
+
export async function getServerSideProps() {
|
|
186
|
+
const data = await fetchData();
|
|
187
|
+
return { props: { data } }; // Safe serialization
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// SAFE: API routes with proper validation
|
|
191
|
+
export default function handler(req, res) {
|
|
192
|
+
const { id } = req.query;
|
|
193
|
+
// Validate id before use
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Flag These (Next.js-Specific)
|
|
198
|
+
|
|
199
|
+
```jsx
|
|
200
|
+
// SSRF in getServerSideProps
|
|
201
|
+
export async function getServerSideProps({ query }) {
|
|
202
|
+
const data = await fetch(query.url); // FLAG: SSRF
|
|
203
|
+
return { props: { data } };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Exposed API keys
|
|
207
|
+
const data = await fetch(process.env.API_KEY); // CHECK: Client-side exposure
|
|
208
|
+
// NEXT_PUBLIC_ env vars are exposed to client
|
|
209
|
+
|
|
210
|
+
// dangerouslySetInnerHTML
|
|
211
|
+
<div dangerouslySetInnerHTML={{__html: props.content}} /> // FLAG
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Angular
|
|
217
|
+
|
|
218
|
+
### Auto-Escaped (Do Not Flag)
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
// SAFE: Angular auto-escapes interpolation
|
|
222
|
+
<div>{{ userInput }}</div>
|
|
223
|
+
<span>{{ user.name }}</span>
|
|
224
|
+
|
|
225
|
+
// SAFE: Property binding
|
|
226
|
+
<div [innerHTML]="trustedHtml"> // Sanitized by DomSanitizer
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Flag These (Angular-Specific)
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
// XSS - Bypassing sanitization
|
|
233
|
+
this.sanitizer.bypassSecurityTrustHtml(userInput); // FLAG
|
|
234
|
+
this.sanitizer.bypassSecurityTrustScript(userInput); // FLAG
|
|
235
|
+
this.sanitizer.bypassSecurityTrustUrl(userInput); // FLAG
|
|
236
|
+
this.sanitizer.bypassSecurityTrustResourceUrl(userInput); // FLAG
|
|
237
|
+
|
|
238
|
+
// Only safe with server-validated content, never user input
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## General JavaScript
|
|
244
|
+
|
|
245
|
+
### Always Flag
|
|
246
|
+
|
|
247
|
+
```javascript
|
|
248
|
+
// Code Execution - Critical
|
|
249
|
+
eval(userInput);
|
|
250
|
+
new Function(userInput)();
|
|
251
|
+
setTimeout(userInput, ms); // String form
|
|
252
|
+
setInterval(userInput, ms); // String form
|
|
253
|
+
script.innerHTML = userInput;
|
|
254
|
+
document.write(userInput);
|
|
255
|
+
|
|
256
|
+
// DOM XSS Sinks - Critical with user input
|
|
257
|
+
element.innerHTML = userInput;
|
|
258
|
+
element.outerHTML = userInput;
|
|
259
|
+
element.insertAdjacentHTML('beforeend', userInput);
|
|
260
|
+
document.write(userInput);
|
|
261
|
+
document.writeln(userInput);
|
|
262
|
+
|
|
263
|
+
// URL-based XSS
|
|
264
|
+
location = userInput; // Open redirect / javascript:
|
|
265
|
+
location.href = userInput;
|
|
266
|
+
window.open(userInput);
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Check Context
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
// Safe DOM APIs (no XSS)
|
|
273
|
+
element.textContent = userInput; // SAFE: Text only
|
|
274
|
+
element.innerText = userInput; // SAFE: Text only
|
|
275
|
+
element.setAttribute('data-x', userInput); // SAFE: Non-event attrs
|
|
276
|
+
document.createTextNode(userInput); // SAFE
|
|
277
|
+
|
|
278
|
+
// Dangerous DOM APIs (check if user-controlled)
|
|
279
|
+
element.innerHTML = content; // CHECK: Is content user-controlled?
|
|
280
|
+
element.src = url; // CHECK: Is url user-controlled?
|
|
281
|
+
element.href = url; // CHECK: javascript: protocol?
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Prototype Pollution
|
|
287
|
+
|
|
288
|
+
### Vulnerable Patterns
|
|
289
|
+
|
|
290
|
+
```javascript
|
|
291
|
+
// FLAG: Object merge with user input
|
|
292
|
+
function merge(target, source) {
|
|
293
|
+
for (let key in source) {
|
|
294
|
+
target[key] = source[key]; // __proto__ can be set
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
merge({}, JSON.parse(userInput)); // FLAG
|
|
298
|
+
|
|
299
|
+
// FLAG: Common vulnerable libraries (check versions)
|
|
300
|
+
_.merge(target, userInput); // lodash < 4.17.12
|
|
301
|
+
$.extend(true, target, userInput); // jQuery deep extend
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Safe Patterns
|
|
305
|
+
|
|
306
|
+
```javascript
|
|
307
|
+
// SAFE: Prototype pollution prevention
|
|
308
|
+
function safeMerge(target, source) {
|
|
309
|
+
for (let key in source) {
|
|
310
|
+
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
target[key] = source[key];
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// SAFE: Object.create(null)
|
|
318
|
+
const obj = Object.create(null); // No prototype chain
|
|
319
|
+
|
|
320
|
+
// SAFE: Map instead of Object
|
|
321
|
+
const map = new Map();
|
|
322
|
+
map.set(userKey, userValue); // Keys don't affect prototype
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## TypeScript-Specific
|
|
328
|
+
|
|
329
|
+
### Type Safety Doesn't Prevent Runtime Attacks
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
// TypeScript types don't validate at runtime
|
|
333
|
+
interface UserInput {
|
|
334
|
+
id: number;
|
|
335
|
+
name: string;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// VULNERABLE: Runtime value could be anything
|
|
339
|
+
const input: UserInput = req.body as UserInput; // No actual validation
|
|
340
|
+
db.query(`SELECT * FROM users WHERE id = ${input.id}`); // Still SQL injection
|
|
341
|
+
|
|
342
|
+
// SAFE: Runtime validation
|
|
343
|
+
import { z } from 'zod';
|
|
344
|
+
const UserInput = z.object({
|
|
345
|
+
id: z.number(),
|
|
346
|
+
name: z.string()
|
|
347
|
+
});
|
|
348
|
+
const input = UserInput.parse(req.body); // Throws if invalid
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Any Type Warnings
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
// CHECK: 'any' type bypasses type safety
|
|
355
|
+
function process(data: any) { // No type checking
|
|
356
|
+
eval(data.code); // Could be anything
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## Grep Patterns
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
# DOM XSS
|
|
366
|
+
grep -rn "innerHTML\|outerHTML\|document\.write" --include="*.js" --include="*.jsx" --include="*.ts" --include="*.tsx"
|
|
367
|
+
|
|
368
|
+
# React dangerous patterns
|
|
369
|
+
grep -rn "dangerouslySetInnerHTML" --include="*.jsx" --include="*.tsx"
|
|
370
|
+
|
|
371
|
+
# Vue dangerous patterns
|
|
372
|
+
grep -rn "v-html" --include="*.vue"
|
|
373
|
+
|
|
374
|
+
# eval and Function
|
|
375
|
+
grep -rn "eval(\|new Function(\|setTimeout.*string\|setInterval.*string" --include="*.js" --include="*.ts"
|
|
376
|
+
|
|
377
|
+
# Command injection
|
|
378
|
+
grep -rn "child_process\|exec(\|execSync(\|spawn(" --include="*.js" --include="*.ts"
|
|
379
|
+
|
|
380
|
+
# Prototype pollution
|
|
381
|
+
grep -rn "__proto__\|constructor\[" --include="*.js" --include="*.ts"
|
|
382
|
+
|
|
383
|
+
# SQL/NoSQL injection
|
|
384
|
+
grep -rn "\\\`SELECT.*\\\${\|\$where\|\.find({.*:.*req\." --include="*.js" --include="*.ts"
|
|
385
|
+
|
|
386
|
+
# Angular bypass
|
|
387
|
+
grep -rn "bypassSecurityTrust" --include="*.ts"
|
|
388
|
+
```
|