@brunosps00/dev-workflow 0.0.5 → 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.
- package/bin/dev-workflow.js +6 -4
- package/lib/init.js +28 -11
- 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,363 @@
|
|
|
1
|
+
# Python Security Patterns
|
|
2
|
+
|
|
3
|
+
## Framework Detection
|
|
4
|
+
|
|
5
|
+
| Indicator | Framework |
|
|
6
|
+
|-----------|-----------|
|
|
7
|
+
| `from django`, `settings.py`, `urls.py`, `views.py` | Django |
|
|
8
|
+
| `from flask`, `@app.route` | Flask |
|
|
9
|
+
| `from fastapi`, `@app.get`, `@app.post` | FastAPI |
|
|
10
|
+
| `import tornado` | Tornado |
|
|
11
|
+
| `from pyramid` | Pyramid |
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Django
|
|
16
|
+
|
|
17
|
+
### Server-Controlled Values (NEVER Flag)
|
|
18
|
+
|
|
19
|
+
Django settings are **deployment configuration**, not attacker input:
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
# SAFE: All django.conf.settings values are server-controlled
|
|
23
|
+
from django.conf import settings
|
|
24
|
+
|
|
25
|
+
requests.get(settings.EXTERNAL_API_URL) # NOT SSRF - configured at deployment
|
|
26
|
+
requests.get(f"{settings.SEER_URL}{path}") # NOT SSRF - base URL is server-controlled
|
|
27
|
+
open(settings.LOG_FILE_PATH) # NOT path traversal
|
|
28
|
+
db.connect(settings.DATABASE_URL) # NOT injection
|
|
29
|
+
|
|
30
|
+
# SAFE: Environment-based configuration
|
|
31
|
+
API_URL = os.environ.get('API_URL')
|
|
32
|
+
requests.get(API_URL) # Server operator controls this
|
|
33
|
+
|
|
34
|
+
# SAFE: Settings from Django's settings.py
|
|
35
|
+
DEBUG = settings.DEBUG
|
|
36
|
+
ALLOWED_HOSTS = settings.ALLOWED_HOSTS
|
|
37
|
+
SECRET_KEY = settings.SECRET_KEY # (check it's not hardcoded in repo though)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Only flag settings-based code if:**
|
|
41
|
+
- The setting value itself is hardcoded in committed code (secrets exposure)
|
|
42
|
+
- The setting value is somehow derived from user input (rare, investigate)
|
|
43
|
+
|
|
44
|
+
### Auto-Escaped (Do Not Flag)
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
# SAFE: Django auto-escapes template variables
|
|
48
|
+
{{ variable }}
|
|
49
|
+
{{ user.name }}
|
|
50
|
+
{{ form.field }}
|
|
51
|
+
|
|
52
|
+
# SAFE: ORM methods are parameterized
|
|
53
|
+
User.objects.filter(username=user_input)
|
|
54
|
+
User.objects.get(id=user_id)
|
|
55
|
+
User.objects.exclude(status=status)
|
|
56
|
+
MyModel.objects.create(name=name)
|
|
57
|
+
|
|
58
|
+
# SAFE: Django's built-in CSRF protection (if enabled)
|
|
59
|
+
{% csrf_token %}
|
|
60
|
+
@csrf_protect
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Flag These (Django-Specific)
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
# XSS - Explicit unsafe marking
|
|
67
|
+
{{ variable|safe }} # FLAG: Disables escaping
|
|
68
|
+
{% autoescape off %}...{% endautoescape %} # FLAG: Disables escaping
|
|
69
|
+
mark_safe(user_input) # FLAG: If user_input is user-controlled
|
|
70
|
+
format_html() with unescaped input # CHECK: Depends on usage
|
|
71
|
+
|
|
72
|
+
# SQL Injection
|
|
73
|
+
User.objects.raw(f"SELECT * FROM users WHERE name = '{user_input}'") # FLAG
|
|
74
|
+
User.objects.extra(where=[f"name = '{user_input}'"]) # FLAG (deprecated)
|
|
75
|
+
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}") # FLAG
|
|
76
|
+
RawSQL(f"SELECT * FROM x WHERE y = '{input}'") # FLAG
|
|
77
|
+
connection.execute(query % user_input) # FLAG
|
|
78
|
+
|
|
79
|
+
# Command Injection
|
|
80
|
+
os.system(f"cmd {user_input}") # FLAG
|
|
81
|
+
subprocess.run(cmd, shell=True) # FLAG if cmd contains user input
|
|
82
|
+
subprocess.Popen(cmd, shell=True) # FLAG if cmd contains user input
|
|
83
|
+
|
|
84
|
+
# Deserialization
|
|
85
|
+
pickle.loads(user_data) # FLAG: Always critical
|
|
86
|
+
yaml.load(user_data) # FLAG: Use yaml.safe_load()
|
|
87
|
+
yaml.load(data, Loader=yaml.Loader) # FLAG: Unsafe loader
|
|
88
|
+
|
|
89
|
+
# File Operations
|
|
90
|
+
open(user_controlled_path) # CHECK: Path traversal
|
|
91
|
+
send_file(user_path) # CHECK: Path traversal
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Django Security Settings
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
# Check settings.py for:
|
|
98
|
+
|
|
99
|
+
# VULNERABLE configurations
|
|
100
|
+
DEBUG = True # FLAG in production
|
|
101
|
+
ALLOWED_HOSTS = ['*'] # FLAG
|
|
102
|
+
SECRET_KEY = 'hardcoded-value' # FLAG if committed
|
|
103
|
+
CSRF_COOKIE_SECURE = False # FLAG in production
|
|
104
|
+
SESSION_COOKIE_SECURE = False # FLAG in production
|
|
105
|
+
|
|
106
|
+
# Missing security middleware - CHECK if absent
|
|
107
|
+
MIDDLEWARE = [
|
|
108
|
+
# Should include:
|
|
109
|
+
'django.middleware.security.SecurityMiddleware',
|
|
110
|
+
'django.middleware.csrf.CsrfViewMiddleware',
|
|
111
|
+
]
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Flask
|
|
117
|
+
|
|
118
|
+
### Safe Patterns (Do Not Flag)
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
# SAFE: Jinja2 auto-escapes by default
|
|
122
|
+
{{ variable }}
|
|
123
|
+
render_template('template.html', name=user_input)
|
|
124
|
+
|
|
125
|
+
# SAFE: Parameterized queries with SQLAlchemy
|
|
126
|
+
db.session.query(User).filter(User.name == user_input)
|
|
127
|
+
db.session.execute(text("SELECT * FROM users WHERE id = :id"), {"id": user_id})
|
|
128
|
+
|
|
129
|
+
# SAFE: Flask-WTF CSRF (if configured)
|
|
130
|
+
form.validate_on_submit()
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Flag These (Flask-Specific)
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
# XSS
|
|
137
|
+
Markup(user_input) # FLAG: Marks as safe HTML
|
|
138
|
+
render_template_string(user_input) # FLAG: SSTI vulnerability
|
|
139
|
+
{{ variable|safe }} # FLAG in templates
|
|
140
|
+
|
|
141
|
+
# SQL Injection
|
|
142
|
+
db.engine.execute(f"SELECT * FROM users WHERE name = '{user_input}'") # FLAG
|
|
143
|
+
text(f"SELECT * FROM users WHERE id = {user_id}") # FLAG
|
|
144
|
+
|
|
145
|
+
# SSTI (Server-Side Template Injection)
|
|
146
|
+
render_template_string(user_controlled_template) # FLAG: Critical
|
|
147
|
+
Template(user_input).render() # FLAG: Critical
|
|
148
|
+
|
|
149
|
+
# Session Security
|
|
150
|
+
app.secret_key = 'hardcoded' # FLAG
|
|
151
|
+
app.config['SECRET_KEY'] = 'weak' # FLAG
|
|
152
|
+
|
|
153
|
+
# Debug Mode
|
|
154
|
+
app.run(debug=True) # FLAG in production
|
|
155
|
+
app.debug = True # FLAG in production
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## FastAPI
|
|
161
|
+
|
|
162
|
+
### Safe Patterns (Do Not Flag)
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
# SAFE: Pydantic validates and sanitizes
|
|
166
|
+
@app.post("/users/")
|
|
167
|
+
async def create_user(user: UserCreate): # Pydantic model validates
|
|
168
|
+
pass
|
|
169
|
+
|
|
170
|
+
# SAFE: Path parameters with type hints
|
|
171
|
+
@app.get("/users/{user_id}")
|
|
172
|
+
async def get_user(user_id: int): # Validated as int
|
|
173
|
+
pass
|
|
174
|
+
|
|
175
|
+
# SAFE: SQLAlchemy ORM
|
|
176
|
+
db.query(User).filter(User.id == user_id).first()
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Flag These (FastAPI-Specific)
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
# SQL Injection (same as Flask/SQLAlchemy)
|
|
183
|
+
db.execute(f"SELECT * FROM users WHERE id = {user_id}") # FLAG
|
|
184
|
+
text(f"SELECT * FROM users WHERE name = '{name}'") # FLAG
|
|
185
|
+
|
|
186
|
+
# Response without validation
|
|
187
|
+
@app.get("/data")
|
|
188
|
+
async def get_data():
|
|
189
|
+
return user_controlled_dict # CHECK: May expose sensitive fields
|
|
190
|
+
|
|
191
|
+
# Dependency injection bypass
|
|
192
|
+
@app.get("/admin")
|
|
193
|
+
async def admin(user: User = Depends(get_current_user)):
|
|
194
|
+
# CHECK: Ensure get_current_user validates properly
|
|
195
|
+
pass
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## General Python
|
|
201
|
+
|
|
202
|
+
### Always Flag
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
# Deserialization - Always Critical
|
|
206
|
+
pickle.loads(data)
|
|
207
|
+
pickle.load(file)
|
|
208
|
+
cPickle.loads(data)
|
|
209
|
+
shelve.open(user_path)
|
|
210
|
+
marshal.loads(data)
|
|
211
|
+
yaml.load(data) # Without Loader=SafeLoader
|
|
212
|
+
yaml.load(data, Loader=yaml.FullLoader) # Still unsafe
|
|
213
|
+
yaml.load(data, Loader=yaml.UnsafeLoader)
|
|
214
|
+
|
|
215
|
+
# Code Execution - Always Critical
|
|
216
|
+
eval(user_input)
|
|
217
|
+
exec(user_input)
|
|
218
|
+
compile(user_input, '<string>', 'exec')
|
|
219
|
+
__import__(user_input)
|
|
220
|
+
|
|
221
|
+
# Command Injection - Critical
|
|
222
|
+
os.system(user_cmd)
|
|
223
|
+
os.popen(user_cmd)
|
|
224
|
+
subprocess.call(cmd, shell=True) # If cmd has user input
|
|
225
|
+
subprocess.run(cmd, shell=True) # If cmd has user input
|
|
226
|
+
subprocess.Popen(cmd, shell=True) # If cmd has user input
|
|
227
|
+
commands.getoutput(user_cmd) # Python 2
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Check Context
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
# SSRF - Check if URL is user-controlled
|
|
234
|
+
requests.get(user_url)
|
|
235
|
+
urllib.request.urlopen(user_url)
|
|
236
|
+
httpx.get(user_url)
|
|
237
|
+
aiohttp.ClientSession().get(user_url)
|
|
238
|
+
|
|
239
|
+
# Path Traversal - Check if path is user-controlled
|
|
240
|
+
open(user_path)
|
|
241
|
+
pathlib.Path(user_path).read_text()
|
|
242
|
+
os.path.join(base, user_input) # ../../../etc/passwd possible
|
|
243
|
+
shutil.copy(user_src, user_dst)
|
|
244
|
+
|
|
245
|
+
# Weak Crypto - Check if for security purpose
|
|
246
|
+
hashlib.md5(password) # FLAG if for passwords
|
|
247
|
+
hashlib.sha1(password) # FLAG if for passwords
|
|
248
|
+
random.random() # FLAG if for security (use secrets module)
|
|
249
|
+
random.randint() # FLAG if for security
|
|
250
|
+
|
|
251
|
+
# Safe Alternatives
|
|
252
|
+
secrets.token_hex() # For tokens
|
|
253
|
+
secrets.token_urlsafe() # For URL-safe tokens
|
|
254
|
+
hashlib.pbkdf2_hmac() # For password hashing
|
|
255
|
+
bcrypt.hashpw() # For password hashing
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Input Validation
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
# VULNERABLE: No validation
|
|
262
|
+
def process(data):
|
|
263
|
+
return eval(data['expression'])
|
|
264
|
+
|
|
265
|
+
# SAFE: Type validation
|
|
266
|
+
def process(data: dict):
|
|
267
|
+
if not isinstance(data.get('value'), int):
|
|
268
|
+
raise ValueError("Invalid input")
|
|
269
|
+
return data['value'] * 2
|
|
270
|
+
|
|
271
|
+
# SAFE: Schema validation
|
|
272
|
+
from pydantic import BaseModel, validator
|
|
273
|
+
|
|
274
|
+
class UserInput(BaseModel):
|
|
275
|
+
name: str
|
|
276
|
+
age: int
|
|
277
|
+
|
|
278
|
+
@validator('name')
|
|
279
|
+
def name_must_be_safe(cls, v):
|
|
280
|
+
if not v.isalnum():
|
|
281
|
+
raise ValueError('Name must be alphanumeric')
|
|
282
|
+
return v
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## SQLAlchemy Patterns
|
|
288
|
+
|
|
289
|
+
### Safe (Do Not Flag)
|
|
290
|
+
|
|
291
|
+
```python
|
|
292
|
+
# ORM methods - automatically parameterized
|
|
293
|
+
session.query(User).filter(User.name == name)
|
|
294
|
+
session.query(User).filter_by(name=name)
|
|
295
|
+
User.query.filter(User.id == id).first()
|
|
296
|
+
|
|
297
|
+
# Parameterized text queries
|
|
298
|
+
from sqlalchemy import text
|
|
299
|
+
session.execute(text("SELECT * FROM users WHERE id = :id"), {"id": user_id})
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Flag These
|
|
303
|
+
|
|
304
|
+
```python
|
|
305
|
+
# String interpolation in queries
|
|
306
|
+
session.execute(f"SELECT * FROM users WHERE name = '{name}'")
|
|
307
|
+
session.execute("SELECT * FROM users WHERE name = '%s'" % name)
|
|
308
|
+
session.execute("SELECT * FROM users WHERE name = '" + name + "'")
|
|
309
|
+
|
|
310
|
+
# text() with interpolation
|
|
311
|
+
session.execute(text(f"SELECT * FROM users WHERE id = {user_id}"))
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Common Mistakes
|
|
317
|
+
|
|
318
|
+
### Type Confusion
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
# VULNERABLE: JSON numbers become floats
|
|
322
|
+
data = request.get_json()
|
|
323
|
+
user_id = data['id'] # Could be float, string, dict, etc.
|
|
324
|
+
User.query.get(user_id) # May behave unexpectedly
|
|
325
|
+
|
|
326
|
+
# SAFE: Explicit type conversion
|
|
327
|
+
user_id = int(data['id'])
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Race Conditions
|
|
331
|
+
|
|
332
|
+
```python
|
|
333
|
+
# VULNERABLE: TOCTOU
|
|
334
|
+
if user.balance >= amount:
|
|
335
|
+
# Another request could modify balance here
|
|
336
|
+
user.balance -= amount
|
|
337
|
+
|
|
338
|
+
# SAFE: Atomic operation
|
|
339
|
+
User.query.filter(User.id == user_id, User.balance >= amount).update(
|
|
340
|
+
{User.balance: User.balance - amount}
|
|
341
|
+
)
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Grep Patterns
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
# Django unsafe patterns
|
|
350
|
+
grep -rn "mark_safe\||safe\|autoescape off\|\.raw(\|\.extra(" --include="*.py"
|
|
351
|
+
|
|
352
|
+
# Flask SSTI
|
|
353
|
+
grep -rn "render_template_string\|Template(" --include="*.py"
|
|
354
|
+
|
|
355
|
+
# Deserialization
|
|
356
|
+
grep -rn "pickle\.load\|yaml\.load\|marshal\.load" --include="*.py"
|
|
357
|
+
|
|
358
|
+
# Command injection
|
|
359
|
+
grep -rn "os\.system\|subprocess.*shell=True\|os\.popen" --include="*.py"
|
|
360
|
+
|
|
361
|
+
# SQL injection
|
|
362
|
+
grep -rn "execute.*f\"\|execute.*%\|\.raw.*f\"" --include="*.py"
|
|
363
|
+
```
|