@brunosps00/dev-workflow 0.0.3 → 0.0.6

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 (221) hide show
  1. package/README.md +42 -42
  2. package/bin/dev-workflow.js +6 -4
  3. package/lib/constants.js +42 -40
  4. package/lib/init.js +66 -19
  5. package/package.json +1 -1
  6. package/scaffold/en/commands/{analyze-project.md → dw-analyze-project.md} +69 -40
  7. package/scaffold/en/commands/{brainstorm.md → dw-brainstorm.md} +31 -4
  8. package/scaffold/en/commands/{bugfix.md → dw-bugfix.md} +63 -19
  9. package/scaffold/en/commands/{code-review.md → dw-code-review.md} +38 -15
  10. package/scaffold/en/commands/{commit.md → dw-commit.md} +25 -0
  11. package/scaffold/en/commands/{create-prd.md → dw-create-prd.md} +24 -10
  12. package/scaffold/en/commands/{create-tasks.md → dw-create-tasks.md} +11 -4
  13. package/scaffold/en/commands/{create-techspec.md → dw-create-techspec.md} +38 -11
  14. package/scaffold/en/commands/{deep-research.md → dw-deep-research.md} +18 -17
  15. package/scaffold/en/commands/{fix-qa.md → dw-fix-qa.md} +20 -3
  16. package/scaffold/en/commands/dw-functional-doc.md +276 -0
  17. package/scaffold/en/commands/{generate-pr.md → dw-generate-pr.md} +20 -5
  18. package/scaffold/en/commands/dw-help.md +309 -0
  19. package/scaffold/en/commands/{refactoring-analysis.md → dw-refactoring-analysis.md} +50 -26
  20. package/scaffold/en/commands/{review-implementation.md → dw-review-implementation.md} +25 -6
  21. package/scaffold/en/commands/{run-plan.md → dw-run-plan.md} +21 -6
  22. package/scaffold/en/commands/{run-qa.md → dw-run-qa.md} +32 -13
  23. package/scaffold/en/commands/{run-task.md → dw-run-task.md} +17 -7
  24. package/scaffold/en/references/playwright-patterns.md +136 -0
  25. package/scaffold/en/references/refactoring-catalog.md +167 -0
  26. package/scaffold/en/templates/brainstorm-matrix.md +44 -0
  27. package/scaffold/en/templates/functional-doc/case-matrix.md +5 -0
  28. package/scaffold/en/templates/functional-doc/e2e-runbook.md +3 -0
  29. package/scaffold/en/templates/functional-doc/features.md +3 -0
  30. package/scaffold/en/templates/functional-doc/overview.md +21 -0
  31. package/scaffold/en/templates/functional-doc/playwright.spec.ts.tpl +19 -0
  32. package/scaffold/en/templates/pr-bugfix-template.md +28 -0
  33. package/scaffold/en/templates/qa-test-credentials.md +37 -0
  34. package/scaffold/en/templates/tasks-template.md +1 -1
  35. package/scaffold/en/templates/techspec-template.md +1 -1
  36. package/scaffold/pt-br/commands/{analyze-project.md → dw-analyze-project.md} +94 -44
  37. package/scaffold/pt-br/commands/{brainstorm.md → dw-brainstorm.md} +32 -5
  38. package/scaffold/pt-br/commands/{bugfix.md → dw-bugfix.md} +73 -16
  39. package/scaffold/pt-br/commands/{code-review.md → dw-code-review.md} +80 -17
  40. package/scaffold/pt-br/commands/{commit.md → dw-commit.md} +45 -1
  41. package/scaffold/pt-br/commands/{create-prd.md → dw-create-prd.md} +25 -10
  42. package/scaffold/pt-br/commands/{create-tasks.md → dw-create-tasks.md} +24 -17
  43. package/scaffold/pt-br/commands/{create-techspec.md → dw-create-techspec.md} +40 -13
  44. package/scaffold/pt-br/commands/{deep-research.md → dw-deep-research.md} +19 -11
  45. package/scaffold/pt-br/commands/{fix-qa.md → dw-fix-qa.md} +30 -1
  46. package/scaffold/pt-br/commands/dw-functional-doc.md +276 -0
  47. package/scaffold/pt-br/commands/{generate-pr.md → dw-generate-pr.md} +61 -6
  48. package/scaffold/pt-br/commands/dw-help.md +248 -0
  49. package/scaffold/pt-br/commands/{refactoring-analysis.md → dw-refactoring-analysis.md} +49 -25
  50. package/scaffold/pt-br/commands/{review-implementation.md → dw-review-implementation.md} +53 -5
  51. package/scaffold/pt-br/commands/{run-plan.md → dw-run-plan.md} +100 -12
  52. package/scaffold/pt-br/commands/{run-qa.md → dw-run-qa.md} +93 -18
  53. package/scaffold/pt-br/commands/{run-task.md → dw-run-task.md} +35 -10
  54. package/scaffold/pt-br/references/playwright-patterns.md +133 -0
  55. package/scaffold/pt-br/references/refactoring-catalog.md +166 -0
  56. package/scaffold/pt-br/templates/brainstorm-matrix.md +44 -0
  57. package/scaffold/pt-br/templates/functional-doc/case-matrix.md +5 -0
  58. package/scaffold/pt-br/templates/functional-doc/e2e-runbook.md +3 -0
  59. package/scaffold/pt-br/templates/functional-doc/features.md +3 -0
  60. package/scaffold/pt-br/templates/functional-doc/overview.md +21 -0
  61. package/scaffold/pt-br/templates/functional-doc/playwright.spec.ts.tpl +19 -0
  62. package/scaffold/pt-br/templates/pr-bugfix-template.md +28 -0
  63. package/scaffold/pt-br/templates/qa-test-credentials.md +37 -0
  64. package/scaffold/pt-br/templates/tasks-template.md +2 -2
  65. package/scaffold/pt-br/templates/techspec-template.md +1 -1
  66. package/scaffold/rules-readme.md +3 -3
  67. package/scaffold/scripts/functional-doc/generate-dossier.mjs +821 -0
  68. package/scaffold/scripts/functional-doc/run-playwright-flow.mjs +275 -0
  69. package/scaffold/skills/agent-browser/SKILL.md +750 -0
  70. package/scaffold/skills/agent-browser/references/authentication.md +303 -0
  71. package/scaffold/skills/agent-browser/references/commands.md +295 -0
  72. package/scaffold/skills/agent-browser/references/profiling.md +120 -0
  73. package/scaffold/skills/agent-browser/references/proxy-support.md +194 -0
  74. package/scaffold/skills/agent-browser/references/session-management.md +193 -0
  75. package/scaffold/skills/agent-browser/references/snapshot-refs.md +219 -0
  76. package/scaffold/skills/agent-browser/references/video-recording.md +173 -0
  77. package/scaffold/skills/agent-browser/templates/authenticated-session.sh +105 -0
  78. package/scaffold/skills/agent-browser/templates/capture-workflow.sh +69 -0
  79. package/scaffold/skills/agent-browser/templates/form-automation.sh +62 -0
  80. package/scaffold/skills/humanizer/README.md +143 -0
  81. package/scaffold/skills/humanizer/SKILL.md +488 -0
  82. package/scaffold/skills/humanizer/WARP.md +53 -0
  83. package/scaffold/skills/remotion-best-practices/SKILL.md +61 -0
  84. package/scaffold/skills/remotion-best-practices/rules/3d.md +86 -0
  85. package/scaffold/skills/remotion-best-practices/rules/animations.md +27 -0
  86. package/scaffold/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
  87. package/scaffold/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
  88. package/scaffold/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +103 -0
  89. package/scaffold/skills/remotion-best-practices/rules/assets.md +78 -0
  90. package/scaffold/skills/remotion-best-practices/rules/audio-visualization.md +198 -0
  91. package/scaffold/skills/remotion-best-practices/rules/audio.md +169 -0
  92. package/scaffold/skills/remotion-best-practices/rules/calculate-metadata.md +134 -0
  93. package/scaffold/skills/remotion-best-practices/rules/can-decode.md +75 -0
  94. package/scaffold/skills/remotion-best-practices/rules/charts.md +120 -0
  95. package/scaffold/skills/remotion-best-practices/rules/compositions.md +154 -0
  96. package/scaffold/skills/remotion-best-practices/rules/display-captions.md +184 -0
  97. package/scaffold/skills/remotion-best-practices/rules/extract-frames.md +229 -0
  98. package/scaffold/skills/remotion-best-practices/rules/ffmpeg.md +38 -0
  99. package/scaffold/skills/remotion-best-practices/rules/fonts.md +152 -0
  100. package/scaffold/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
  101. package/scaffold/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
  102. package/scaffold/skills/remotion-best-practices/rules/get-video-duration.md +60 -0
  103. package/scaffold/skills/remotion-best-practices/rules/gifs.md +141 -0
  104. package/scaffold/skills/remotion-best-practices/rules/images.md +134 -0
  105. package/scaffold/skills/remotion-best-practices/rules/import-srt-captions.md +69 -0
  106. package/scaffold/skills/remotion-best-practices/rules/light-leaks.md +73 -0
  107. package/scaffold/skills/remotion-best-practices/rules/lottie.md +70 -0
  108. package/scaffold/skills/remotion-best-practices/rules/maps.md +412 -0
  109. package/scaffold/skills/remotion-best-practices/rules/measuring-dom-nodes.md +34 -0
  110. package/scaffold/skills/remotion-best-practices/rules/measuring-text.md +140 -0
  111. package/scaffold/skills/remotion-best-practices/rules/parameters.md +109 -0
  112. package/scaffold/skills/remotion-best-practices/rules/sequencing.md +118 -0
  113. package/scaffold/skills/remotion-best-practices/rules/sfx.md +26 -0
  114. package/scaffold/skills/remotion-best-practices/rules/subtitles.md +36 -0
  115. package/scaffold/skills/remotion-best-practices/rules/tailwind.md +11 -0
  116. package/scaffold/skills/remotion-best-practices/rules/text-animations.md +20 -0
  117. package/scaffold/skills/remotion-best-practices/rules/timing.md +179 -0
  118. package/scaffold/skills/remotion-best-practices/rules/transcribe-captions.md +70 -0
  119. package/scaffold/skills/remotion-best-practices/rules/transitions.md +197 -0
  120. package/scaffold/skills/remotion-best-practices/rules/transparent-videos.md +106 -0
  121. package/scaffold/skills/remotion-best-practices/rules/trimming.md +51 -0
  122. package/scaffold/skills/remotion-best-practices/rules/videos.md +171 -0
  123. package/scaffold/skills/remotion-best-practices/rules/voiceover.md +99 -0
  124. package/scaffold/skills/security-review/LICENSE +22 -0
  125. package/scaffold/skills/security-review/SKILL.md +312 -0
  126. package/scaffold/skills/security-review/infrastructure/docker.md +432 -0
  127. package/scaffold/skills/security-review/languages/javascript.md +388 -0
  128. package/scaffold/skills/security-review/languages/python.md +363 -0
  129. package/scaffold/skills/security-review/references/api-security.md +519 -0
  130. package/scaffold/skills/security-review/references/authentication.md +353 -0
  131. package/scaffold/skills/security-review/references/authorization.md +372 -0
  132. package/scaffold/skills/security-review/references/business-logic.md +443 -0
  133. package/scaffold/skills/security-review/references/cryptography.md +329 -0
  134. package/scaffold/skills/security-review/references/csrf.md +398 -0
  135. package/scaffold/skills/security-review/references/data-protection.md +378 -0
  136. package/scaffold/skills/security-review/references/deserialization.md +410 -0
  137. package/scaffold/skills/security-review/references/error-handling.md +436 -0
  138. package/scaffold/skills/security-review/references/file-security.md +457 -0
  139. package/scaffold/skills/security-review/references/injection.md +259 -0
  140. package/scaffold/skills/security-review/references/logging.md +433 -0
  141. package/scaffold/skills/security-review/references/misconfiguration.md +435 -0
  142. package/scaffold/skills/security-review/references/modern-threats.md +475 -0
  143. package/scaffold/skills/security-review/references/ssrf.md +415 -0
  144. package/scaffold/skills/security-review/references/supply-chain.md +405 -0
  145. package/scaffold/skills/security-review/references/xss.md +336 -0
  146. package/scaffold/skills/vercel-react-best-practices/AGENTS.md +3648 -0
  147. package/scaffold/skills/vercel-react-best-practices/README.md +123 -0
  148. package/scaffold/skills/vercel-react-best-practices/SKILL.md +146 -0
  149. package/scaffold/skills/vercel-react-best-practices/rules/_sections.md +46 -0
  150. package/scaffold/skills/vercel-react-best-practices/rules/_template.md +28 -0
  151. package/scaffold/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  152. package/scaffold/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
  153. package/scaffold/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
  154. package/scaffold/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  155. package/scaffold/skills/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
  156. package/scaffold/skills/vercel-react-best-practices/rules/async-defer-await.md +82 -0
  157. package/scaffold/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
  158. package/scaffold/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
  159. package/scaffold/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  160. package/scaffold/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +60 -0
  161. package/scaffold/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  162. package/scaffold/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  163. package/scaffold/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  164. package/scaffold/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  165. package/scaffold/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  166. package/scaffold/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
  167. package/scaffold/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
  168. package/scaffold/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  169. package/scaffold/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
  170. package/scaffold/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  171. package/scaffold/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  172. package/scaffold/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  173. package/scaffold/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  174. package/scaffold/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  175. package/scaffold/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
  176. package/scaffold/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  177. package/scaffold/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  178. package/scaffold/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  179. package/scaffold/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  180. package/scaffold/skills/vercel-react-best-practices/rules/js-request-idle-callback.md +105 -0
  181. package/scaffold/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  182. package/scaffold/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  183. package/scaffold/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  184. package/scaffold/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  185. package/scaffold/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  186. package/scaffold/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  187. package/scaffold/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  188. package/scaffold/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  189. package/scaffold/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
  190. package/scaffold/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
  191. package/scaffold/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
  192. package/scaffold/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  193. package/scaffold/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  194. package/scaffold/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  195. package/scaffold/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  196. package/scaffold/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  197. package/scaffold/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  198. package/scaffold/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  199. package/scaffold/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  200. package/scaffold/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
  201. package/scaffold/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  202. package/scaffold/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  203. package/scaffold/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
  204. package/scaffold/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  205. package/scaffold/skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
  206. package/scaffold/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  207. package/scaffold/skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +59 -0
  208. package/scaffold/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  209. package/scaffold/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  210. package/scaffold/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
  211. package/scaffold/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  212. package/scaffold/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
  213. package/scaffold/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
  214. package/scaffold/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +149 -0
  215. package/scaffold/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
  216. package/scaffold/skills/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
  217. package/scaffold/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
  218. package/scaffold/skills/webapp-testing/SKILL.md +133 -0
  219. package/scaffold/skills/webapp-testing/assets/test-helper.js +56 -0
  220. package/scaffold/en/commands/help.md +0 -289
  221. package/scaffold/pt-br/commands/help.md +0 -226
@@ -0,0 +1,519 @@
1
+ # API Security Reference
2
+
3
+ ## Overview
4
+
5
+ APIs expose application functionality and data, making them prime targets for attackers. This reference covers security for REST APIs, GraphQL, and general API patterns.
6
+
7
+ ## Authentication
8
+
9
+ ### Token-Based Authentication
10
+
11
+ ```python
12
+ # JWT Best Practices
13
+ # 1. Use strong signing algorithms
14
+ # VULNERABLE: None algorithm
15
+ jwt.decode(token, algorithms=['none'])
16
+
17
+ # SAFE: Explicit algorithm
18
+ jwt.decode(token, secret_key, algorithms=['HS256'])
19
+
20
+ # 2. Validate standard claims
21
+ def validate_jwt(token):
22
+ payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
23
+
24
+ # Validate issuer
25
+ if payload.get('iss') != EXPECTED_ISSUER:
26
+ raise ValueError("Invalid issuer")
27
+
28
+ # Validate audience
29
+ if payload.get('aud') != EXPECTED_AUDIENCE:
30
+ raise ValueError("Invalid audience")
31
+
32
+ # Validate expiration (jwt library does this automatically)
33
+ # Validate not-before (jwt library does this automatically)
34
+
35
+ return payload
36
+ ```
37
+
38
+ ### API Key Security
39
+
40
+ ```python
41
+ # VULNERABLE: API key in URL (logged, cached, visible)
42
+ GET /api/users?api_key=secret123
43
+
44
+ # SAFE: API key in header
45
+ GET /api/users
46
+ Authorization: Bearer api_key_here
47
+ # Or
48
+ X-API-Key: api_key_here
49
+
50
+ # Server-side validation
51
+ def require_api_key(f):
52
+ @wraps(f)
53
+ def decorated(*args, **kwargs):
54
+ api_key = request.headers.get('X-API-Key')
55
+ if not api_key or not validate_api_key(api_key):
56
+ return jsonify({'error': 'Invalid API key'}), 401
57
+
58
+ # Rate limit by API key
59
+ if is_rate_limited(api_key):
60
+ return jsonify({'error': 'Rate limit exceeded'}), 429
61
+
62
+ return f(*args, **kwargs)
63
+ return decorated
64
+ ```
65
+
66
+ ---
67
+
68
+ ## Authorization
69
+
70
+ ### Endpoint-Level Authorization
71
+
72
+ ```python
73
+ # VULNERABLE: No authorization check
74
+ @app.route('/api/users/<user_id>', methods=['GET'])
75
+ def get_user(user_id):
76
+ return User.query.get(user_id).to_dict()
77
+
78
+ # SAFE: Authorization check
79
+ @app.route('/api/users/<user_id>', methods=['GET'])
80
+ @require_auth
81
+ def get_user(user_id):
82
+ if not current_user.can_access_user(user_id):
83
+ return jsonify({'error': 'Forbidden'}), 403
84
+ return User.query.get(user_id).to_dict()
85
+ ```
86
+
87
+ ### Field-Level Authorization
88
+
89
+ ```python
90
+ # VULNERABLE: All fields returned
91
+ @app.route('/api/users/<user_id>')
92
+ def get_user(user_id):
93
+ user = User.query.get(user_id)
94
+ return jsonify({
95
+ 'id': user.id,
96
+ 'email': user.email,
97
+ 'ssn': user.ssn, # Sensitive!
98
+ 'is_admin': user.is_admin, # Internal!
99
+ 'password_hash': user.password_hash # NEVER expose!
100
+ })
101
+
102
+ # SAFE: Filtered response based on permissions
103
+ @app.route('/api/users/<user_id>')
104
+ @require_auth
105
+ def get_user(user_id):
106
+ user = User.query.get(user_id)
107
+
108
+ response = {
109
+ 'id': user.id,
110
+ 'name': user.name,
111
+ }
112
+
113
+ # Add fields based on permissions
114
+ if current_user.id == user_id or current_user.is_admin:
115
+ response['email'] = user.email
116
+
117
+ if current_user.is_admin:
118
+ response['is_admin'] = user.is_admin
119
+
120
+ return jsonify(response)
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Input Validation
126
+
127
+ ### Request Validation
128
+
129
+ ```python
130
+ from pydantic import BaseModel, validator, Field
131
+ from typing import Optional
132
+
133
+ class CreateUserRequest(BaseModel):
134
+ name: str = Field(..., min_length=1, max_length=100)
135
+ email: str = Field(..., regex=r'^[\w\.-]+@[\w\.-]+\.\w+$')
136
+ age: Optional[int] = Field(None, ge=0, le=150)
137
+
138
+ @validator('name')
139
+ def name_must_not_be_empty(cls, v):
140
+ if not v.strip():
141
+ raise ValueError('Name cannot be empty')
142
+ return v.strip()
143
+
144
+ @app.route('/api/users', methods=['POST'])
145
+ def create_user():
146
+ try:
147
+ data = CreateUserRequest(**request.json)
148
+ except ValidationError as e:
149
+ return jsonify({'error': e.errors()}), 400
150
+
151
+ # Process validated data
152
+ return create_user_from_data(data)
153
+ ```
154
+
155
+ ### Content-Type Validation
156
+
157
+ ```python
158
+ # VULNERABLE: Accept any content type
159
+ @app.route('/api/data', methods=['POST'])
160
+ def process_data():
161
+ data = request.get_json() # May fail silently
162
+
163
+ # SAFE: Validate content type
164
+ @app.route('/api/data', methods=['POST'])
165
+ def process_data():
166
+ if request.content_type != 'application/json':
167
+ return jsonify({'error': 'Content-Type must be application/json'}), 415
168
+
169
+ data = request.get_json()
170
+ if data is None:
171
+ return jsonify({'error': 'Invalid JSON'}), 400
172
+
173
+ return process(data)
174
+ ```
175
+
176
+ ### Request Size Limits
177
+
178
+ ```python
179
+ # Flask
180
+ app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max
181
+
182
+ # Express
183
+ app.use(express.json({ limit: '10mb' }))
184
+
185
+ # Handle large request errors
186
+ @app.errorhandler(413)
187
+ def request_too_large(e):
188
+ return jsonify({'error': 'Request too large'}), 413
189
+ ```
190
+
191
+ ---
192
+
193
+ ## Rate Limiting
194
+
195
+ ### Implementation
196
+
197
+ ```python
198
+ from flask_limiter import Limiter
199
+ from flask_limiter.util import get_remote_address
200
+
201
+ limiter = Limiter(
202
+ app,
203
+ key_func=get_remote_address,
204
+ default_limits=["200 per day", "50 per hour"]
205
+ )
206
+
207
+ # Endpoint-specific limits
208
+ @app.route('/api/login', methods=['POST'])
209
+ @limiter.limit("5 per minute") # Prevent brute force
210
+ def login():
211
+ pass
212
+
213
+ @app.route('/api/password-reset', methods=['POST'])
214
+ @limiter.limit("3 per hour") # Prevent enumeration
215
+ def password_reset():
216
+ pass
217
+
218
+ # Return proper headers
219
+ # X-RateLimit-Limit: 50
220
+ # X-RateLimit-Remaining: 45
221
+ # X-RateLimit-Reset: 1623456789
222
+ # Retry-After: 3600 (when limited)
223
+ ```
224
+
225
+ ### Rate Limit by API Key
226
+
227
+ ```python
228
+ def get_rate_limit_key():
229
+ # Prefer API key over IP for authenticated requests
230
+ api_key = request.headers.get('X-API-Key')
231
+ if api_key:
232
+ return f"api_key:{api_key}"
233
+ return f"ip:{get_remote_address()}"
234
+
235
+ limiter = Limiter(key_func=get_rate_limit_key)
236
+ ```
237
+
238
+ ---
239
+
240
+ ## Mass Assignment Prevention
241
+
242
+ ```python
243
+ # VULNERABLE: Accepting all fields
244
+ @app.route('/api/users/<id>', methods=['PATCH'])
245
+ def update_user(id):
246
+ user = User.query.get(id)
247
+ user.update(**request.json) # Attacker sets is_admin=True
248
+ return user.to_dict()
249
+
250
+ # SAFE: Allowlist of fields
251
+ ALLOWED_USER_FIELDS = {'name', 'email', 'bio'}
252
+
253
+ @app.route('/api/users/<id>', methods=['PATCH'])
254
+ def update_user(id):
255
+ user = User.query.get(id)
256
+ data = {k: v for k, v in request.json.items() if k in ALLOWED_USER_FIELDS}
257
+ user.update(**data)
258
+ return user.to_dict()
259
+
260
+ # BETTER: Use DTOs
261
+ class UserUpdateDTO(BaseModel):
262
+ name: Optional[str]
263
+ email: Optional[str]
264
+ bio: Optional[str]
265
+ # is_admin NOT included - can't be set
266
+
267
+ @app.route('/api/users/<id>', methods=['PATCH'])
268
+ def update_user(id):
269
+ dto = UserUpdateDTO(**request.json)
270
+ user = User.query.get(id)
271
+ user.update(**dto.dict(exclude_unset=True))
272
+ return user.to_dict()
273
+ ```
274
+
275
+ ---
276
+
277
+ ## GraphQL Security
278
+
279
+ ### Query Depth Limiting
280
+
281
+ ```python
282
+ # VULNERABLE: Unbounded depth
283
+ # query { user { friends { friends { friends { ... } } } } }
284
+
285
+ # SAFE: Limit query depth
286
+ from graphql import validate
287
+ from graphql_core import depth_limit_validator
288
+
289
+ schema = build_schema(...)
290
+
291
+ def execute_query(query):
292
+ errors = validate(
293
+ schema,
294
+ parse(query),
295
+ [depth_limit_validator(max_depth=5)]
296
+ )
297
+ if errors:
298
+ return {'errors': [str(e) for e in errors]}
299
+ return graphql_sync(schema, query)
300
+ ```
301
+
302
+ ### Query Cost Analysis
303
+
304
+ ```python
305
+ # Assign costs to fields and limit total cost
306
+ from graphene import ObjectType, Field, Int
307
+
308
+ class Query(ObjectType):
309
+ user = Field(User, cost=1)
310
+ users = Field(List(User), cost=lambda info, **args: args.get('limit', 10))
311
+ expensive_query = Field(Report, cost=100)
312
+
313
+ # Reject queries exceeding cost threshold
314
+ MAX_QUERY_COST = 1000
315
+ ```
316
+
317
+ ### Disable Introspection in Production
318
+
319
+ ```python
320
+ # VULNERABLE: Introspection enabled
321
+ # Attackers can discover entire schema
322
+
323
+ # SAFE: Disable introspection
324
+ from graphql import GraphQLSchema
325
+
326
+ class NoIntrospectionMiddleware:
327
+ def resolve(self, next, root, info, **args):
328
+ if info.field_name in ('__schema', '__type'):
329
+ return None
330
+ return next(root, info, **args)
331
+
332
+ # Or in configuration
333
+ app.config['GRAPHQL_INTROSPECTION'] = False
334
+ ```
335
+
336
+ ### Batching Attack Prevention
337
+
338
+ ```python
339
+ # VULNERABLE: Allows unlimited batched mutations
340
+ # [
341
+ # { "query": "mutation { login(user: 'a', pass: 'a') }" },
342
+ # { "query": "mutation { login(user: 'a', pass: 'b') }" },
343
+ # ...
344
+ # ]
345
+
346
+ # SAFE: Limit batch size
347
+ MAX_BATCH_SIZE = 10
348
+
349
+ @app.route('/graphql', methods=['POST'])
350
+ def graphql_endpoint():
351
+ data = request.json
352
+
353
+ if isinstance(data, list):
354
+ if len(data) > MAX_BATCH_SIZE:
355
+ return jsonify({'error': 'Batch size exceeded'}), 400
356
+ ```
357
+
358
+ ---
359
+
360
+ ## Error Handling
361
+
362
+ ### Generic Error Responses
363
+
364
+ ```python
365
+ # VULNERABLE: Detailed errors
366
+ @app.errorhandler(Exception)
367
+ def handle_error(e):
368
+ return jsonify({
369
+ 'error': str(e),
370
+ 'traceback': traceback.format_exc(),
371
+ 'query': last_query
372
+ }), 500
373
+
374
+ # SAFE: Generic errors
375
+ @app.errorhandler(Exception)
376
+ def handle_error(e):
377
+ # Log full details server-side
378
+ app.logger.error(f"Error: {e}", exc_info=True)
379
+
380
+ # Return generic message
381
+ return jsonify({'error': 'An unexpected error occurred'}), 500
382
+
383
+ # Use RFC 7807 Problem Details
384
+ @app.errorhandler(404)
385
+ def not_found(e):
386
+ return jsonify({
387
+ 'type': 'https://example.com/problems/not-found',
388
+ 'title': 'Resource Not Found',
389
+ 'status': 404,
390
+ 'detail': 'The requested resource was not found'
391
+ }), 404
392
+ ```
393
+
394
+ ---
395
+
396
+ ## Security Headers
397
+
398
+ ```python
399
+ @app.after_request
400
+ def add_security_headers(response):
401
+ # Prevent caching of sensitive data
402
+ if request.endpoint in SENSITIVE_ENDPOINTS:
403
+ response.headers['Cache-Control'] = 'no-store'
404
+
405
+ response.headers['X-Content-Type-Options'] = 'nosniff'
406
+ response.headers['X-Frame-Options'] = 'DENY'
407
+ response.headers['Content-Security-Policy'] = "default-src 'none'"
408
+
409
+ return response
410
+ ```
411
+
412
+ ---
413
+
414
+ ## CORS Configuration
415
+
416
+ ```python
417
+ # VULNERABLE: Allow all origins
418
+ CORS(app, origins='*')
419
+
420
+ # VULNERABLE: Reflect origin header
421
+ @app.after_request
422
+ def add_cors(response):
423
+ response.headers['Access-Control-Allow-Origin'] = request.headers.get('Origin')
424
+ return response
425
+
426
+ # SAFE: Explicit allowlist
427
+ CORS(app, origins=[
428
+ 'https://app.example.com',
429
+ 'https://admin.example.com'
430
+ ], supports_credentials=True)
431
+
432
+ # SAFE: Dynamic with validation
433
+ ALLOWED_ORIGINS = {'https://app.example.com', 'https://admin.example.com'}
434
+
435
+ @app.after_request
436
+ def add_cors(response):
437
+ origin = request.headers.get('Origin')
438
+ if origin in ALLOWED_ORIGINS:
439
+ response.headers['Access-Control-Allow-Origin'] = origin
440
+ response.headers['Access-Control-Allow-Credentials'] = 'true'
441
+ return response
442
+ ```
443
+
444
+ ---
445
+
446
+ ## HTTP Methods
447
+
448
+ ```python
449
+ # VULNERABLE: Method not enforced
450
+ @app.route('/api/users', methods=['GET', 'POST', 'PUT', 'DELETE'])
451
+ def users():
452
+ pass
453
+
454
+ # SAFE: Explicit method handling
455
+ @app.route('/api/users', methods=['GET'])
456
+ def list_users():
457
+ pass
458
+
459
+ @app.route('/api/users', methods=['POST'])
460
+ @require_auth
461
+ def create_user():
462
+ pass
463
+
464
+ # Return 405 for unsupported methods
465
+ @app.errorhandler(405)
466
+ def method_not_allowed(e):
467
+ return jsonify({'error': 'Method not allowed'}), 405
468
+ ```
469
+
470
+ ---
471
+
472
+ ## Grep Patterns for Detection
473
+
474
+ ```bash
475
+ # Missing authentication
476
+ grep -rn "@app\.route\|@router\." --include="*.py" | grep -v "@require_auth\|@login_required"
477
+
478
+ # Returning all fields
479
+ grep -rn "to_dict()\|__dict__\|serialize" --include="*.py"
480
+
481
+ # Mass assignment
482
+ grep -rn "\*\*request\.\|update(\*\*\|create(\*\*" --include="*.py"
483
+
484
+ # Missing rate limiting
485
+ grep -rn "login\|password\|reset" --include="*.py" | grep "route" | grep -v "limiter\|rate"
486
+
487
+ # GraphQL introspection
488
+ grep -rn "__schema\|introspection" --include="*.py"
489
+
490
+ # CORS wildcards
491
+ grep -rn "origins.*\*\|Access-Control-Allow-Origin.*\*" --include="*.py"
492
+ ```
493
+
494
+ ---
495
+
496
+ ## Testing Checklist
497
+
498
+ - [ ] All endpoints require authentication (except public ones)
499
+ - [ ] Authorization checked for every request
500
+ - [ ] Input validation on all parameters
501
+ - [ ] Response filtering (no sensitive data exposure)
502
+ - [ ] Rate limiting on authentication endpoints
503
+ - [ ] Rate limiting on resource-intensive endpoints
504
+ - [ ] Mass assignment prevented (field allowlists)
505
+ - [ ] Proper error handling (no information leakage)
506
+ - [ ] Security headers configured
507
+ - [ ] CORS properly configured
508
+ - [ ] HTTP methods restricted
509
+ - [ ] GraphQL depth/cost limiting (if applicable)
510
+ - [ ] GraphQL introspection disabled in production
511
+
512
+ ---
513
+
514
+ ## References
515
+
516
+ - [OWASP REST Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html)
517
+ - [OWASP GraphQL Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/GraphQL_Cheat_Sheet.html)
518
+ - [OWASP API Security Top 10](https://owasp.org/www-project-api-security/)
519
+ - [CWE-285: Improper Authorization](https://cwe.mitre.org/data/definitions/285.html)