@runsec/mcp 1.0.1

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 (40) hide show
  1. package/dist/index.js +578 -0
  2. package/package.json +43 -0
  3. package/src/rules/data/rule-compliance-map.json +43563 -0
  4. package/src/rules/data/semgrep-rules/README-taint-overlays.md +21 -0
  5. package/src/rules/data/semgrep-rules/advanced-agent-cloud.yaml +802 -0
  6. package/src/rules/data/semgrep-rules/app-logic.yaml +445 -0
  7. package/src/rules/data/semgrep-rules/auth-keycloak.yaml +831 -0
  8. package/src/rules/data/semgrep-rules/browser-agent.yaml +260 -0
  9. package/src/rules/data/semgrep-rules/cloud-secrets.yaml +316 -0
  10. package/src/rules/data/semgrep-rules/csharp-dotnet.yaml +4864 -0
  11. package/src/rules/data/semgrep-rules/desktop-electron-pro.yaml +30 -0
  12. package/src/rules/data/semgrep-rules/desktop-vsto-suite.yaml +2759 -0
  13. package/src/rules/data/semgrep-rules/devops-security.yaml +393 -0
  14. package/src/rules/data/semgrep-rules/domain-access-management.yaml +1023 -0
  15. package/src/rules/data/semgrep-rules/domain-data-privacy.yaml +852 -0
  16. package/src/rules/data/semgrep-rules/domain-input-validation.yaml +2894 -0
  17. package/src/rules/data/semgrep-rules/domain-platform-hardening.yaml +1715 -0
  18. package/src/rules/data/semgrep-rules/ds-ml-security.yaml +2431 -0
  19. package/src/rules/data/semgrep-rules/fastapi-async.yaml +5953 -0
  20. package/src/rules/data/semgrep-rules/frontend-react.yaml +4035 -0
  21. package/src/rules/data/semgrep-rules/frontend-security.yaml +200 -0
  22. package/src/rules/data/semgrep-rules/go-core.yaml +4959 -0
  23. package/src/rules/data/semgrep-rules/hft-cpp-security.yaml +631 -0
  24. package/src/rules/data/semgrep-rules/infra-k8s-helm.yaml +4968 -0
  25. package/src/rules/data/semgrep-rules/integration-security.yaml +2362 -0
  26. package/src/rules/data/semgrep-rules/java-enterprise.yaml +14756 -0
  27. package/src/rules/data/semgrep-rules/java-spring.yaml +397 -0
  28. package/src/rules/data/semgrep-rules/license-compliance.yaml +186 -0
  29. package/src/rules/data/semgrep-rules/mobile-flutter.yaml +37 -0
  30. package/src/rules/data/semgrep-rules/mobile-security.yaml +721 -0
  31. package/src/rules/data/semgrep-rules/nodejs-nestjs.yaml +5164 -0
  32. package/src/rules/data/semgrep-rules/nodejs-security.yaml +326 -0
  33. package/src/rules/data/semgrep-rules/observability.yaml +381 -0
  34. package/src/rules/data/semgrep-rules/php-security.yaml +3601 -0
  35. package/src/rules/data/semgrep-rules/python-backend-pro.yaml +30 -0
  36. package/src/rules/data/semgrep-rules/python-django.yaml +181 -0
  37. package/src/rules/data/semgrep-rules/python-security.yaml +284 -0
  38. package/src/rules/data/semgrep-rules/ru-regulatory.yaml +496 -0
  39. package/src/rules/data/semgrep-rules/ruby-rails.yaml +3078 -0
  40. package/src/rules/data/semgrep-rules/rust-security.yaml +2701 -0
@@ -0,0 +1,445 @@
1
+ rules:
2
+ - id: runsec.app-logic.biz-001
3
+ metadata:
4
+ runsec_version: v1.0
5
+ confidence: |-
6
+ 0.9
7
+ exploit_scenario: |-
8
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
9
+ fix_template: |-
10
+ @app.get("/orders/{order_id}") async def get_order(order_id: int, user=Depends(current_user)): order = await repo.get_order(order_id) if not order or order.owner_id != user.id: raise HTTPException(status_code=404, detail="not found") return order
11
+ pattern-either:
12
+ - pattern: |-
13
+ @app.get("/orders/{order_id}")
14
+ async def get_order(order_id: int):
15
+ order = await repo.get_order(order_id)
16
+ return order
17
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-001\\b'
18
+ message: |-
19
+ RunSec Detection [BIZ-001]: OWASP API Security Top 10 (2023) API1: Broken Object Level Authorization; OWASP ASVS v4.0.3 V4 Access Control
20
+ languages:
21
+ - python
22
+ severity: WARNING
23
+ - id: runsec.app-logic.biz-002
24
+ metadata:
25
+ runsec_version: v1.0
26
+ confidence: |-
27
+ 0.9
28
+ exploit_scenario: |-
29
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
30
+ fix_template: |-
31
+ @app.get("/profile") async def profile(user=Depends(current_user)): return await repo.get_profile(user.id)
32
+ pattern-either:
33
+ - pattern: |-
34
+ @app.get("/profile")
35
+ async def profile(user_id: int):
36
+ return await repo.get_profile(user_id)
37
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-002\\b'
38
+ message: |-
39
+ RunSec Detection [BIZ-002]: OWASP API Security Top 10 (2023) API1: Broken Object Level Authorization
40
+ languages:
41
+ - python
42
+ severity: WARNING
43
+ - id: runsec.app-logic.biz-003
44
+ metadata:
45
+ runsec_version: v1.0
46
+ confidence: |-
47
+ 0.9
48
+ exploit_scenario: |-
49
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
50
+ fix_template: |-
51
+ OWASP API Security Top 10 (2023) API3: Broken Object Property Level Authorization
52
+ pattern-either:
53
+ - pattern: |-
54
+ class AccountUpdate(BaseModel):
55
+ email: str
56
+ is_admin: bool = False
57
+ balance: int = 0
58
+ @app.patch("/accounts/{account_id}")
59
+ async def patch_account(account_id: int, dto: AccountUpdate):
60
+ await repo.update_account(account_id, **dto.model_dump())
61
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-003\\b'
62
+ message: |-
63
+ RunSec Detection [BIZ-003]: None = None
64
+ @app.patch("/accounts/{account_id}")
65
+ async def patch_account(account_id: int, dto: AccountUpdatePublic, user=Depends(current_user)):
66
+ account = await repo.get_account(account_id)
67
+ if not account or account.owner_id != user.id:
68
+ raise HTTPException(status_code=404, detail="not found")
69
+ payload = dto.model_dump(exclude_none=True, include={"email", "display_name"})
70
+ await repo.update_account(account_id, **payload)
71
+ languages:
72
+ - python
73
+ severity: WARNING
74
+ - id: runsec.app-logic.biz-004
75
+ metadata:
76
+ runsec_version: v1.0
77
+ confidence: |-
78
+ 0.9
79
+ exploit_scenario: |-
80
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
81
+ fix_template: |-
82
+ @app.post("/admin/promote") async def promote(dto: PromoteUserDTO, actor=Depends(current_user)): if actor.role != "admin": raise HTTPException(status_code=403, detail="forbidden") if dto.role not in {"manager", "auditor"}: raise HTTPException(status_code=400, detail="invalid role") await repo.update_user(dto.user_id, role=dto.role)
83
+ pattern-either:
84
+ - pattern: |-
85
+ @app.post("/admin/promote")
86
+ async def promote(dto: dict):
87
+ await repo.update_user(dto["user_id"], role=dto["role"])
88
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-004\\b'
89
+ message: |-
90
+ RunSec Detection [BIZ-004]: OWASP Top 10 (2021) A01 Broken Access Control; OWASP API Security Top 10 (2023) API5 Broken Function Level Authorization
91
+ languages:
92
+ - python
93
+ severity: WARNING
94
+ - id: runsec.app-logic.biz-005
95
+ metadata:
96
+ runsec_version: v1.0
97
+ confidence: |-
98
+ 0.9
99
+ exploit_scenario: |-
100
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
101
+ fix_template: |-
102
+ @app.post("/payments/{payment_id}/confirm") async def confirm(payment_id: int, user=Depends(current_user)): if not user.step_up_verified_at or user.step_up_verified_at < datetime.now(timezone.utc) - timedelta(minutes=5): raise HTTPException(status_code=401, detail="step-up required") return await payments.confirm(payment_id, user.id)
103
+ pattern-either:
104
+ - pattern: |-
105
+ @app.post("/payments/{payment_id}/confirm")
106
+ async def confirm(payment_id: int, user=Depends(current_user)):
107
+ return await payments.confirm(payment_id, user.id)
108
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-005\\b'
109
+ message: |-
110
+ RunSec Detection [BIZ-005]: OWASP API Security Top 10 (2023) API2 Broken Authentication; OWASP ASVS v4.0.3 V2 Authentication
111
+ languages:
112
+ - python
113
+ severity: WARNING
114
+ - id: runsec.app-logic.biz-006
115
+ metadata:
116
+ runsec_version: v1.0
117
+ confidence: |-
118
+ 0.9
119
+ exploit_scenario: |-
120
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
121
+ fix_template: |-
122
+ @app.post("/mfa/verify") async def verify(req: MFAVerifyRequest, user=Depends(current_user)): challenge = await mfa.get_challenge(req.challenge_id) if not challenge or challenge.user_id != user.id or challenge.context != req.context: raise HTTPException(status_code=400, detail="invalid challenge") if not await mfa.verify_code(user.id, req.code): raise HTTPException(status_code=401, detail="invalid code") await mfa.mark_step_up(user.id, context=req.context) return {"ok": True}
123
+ pattern-either:
124
+ - pattern: |-
125
+ @app.post("/mfa/verify")
126
+ async def verify(code: str, user=Depends(current_user)):
127
+ if await mfa.verify_code(user.id, code):
128
+ return {"ok": True}
129
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-006\\b'
130
+ message: |-
131
+ RunSec Detection [BIZ-006]: OWASP ASVS v4.0.3 V2; OWASP API Security Top 10 (2023) API2 Broken Authentication
132
+ languages:
133
+ - python
134
+ severity: WARNING
135
+ - id: runsec.app-logic.biz-007
136
+ metadata:
137
+ runsec_version: v1.0
138
+ confidence: |-
139
+ 0.9
140
+ exploit_scenario: |-
141
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
142
+ fix_template: |-
143
+ ALLOWED = {"draft": {"submitted"}, "submitted": {"approved"}, "approved": {"paid"}} @app.post("/orders/{order_id}/pay") async def pay(order_id: int, user=Depends(current_user)): order = await repo.get_order(order_id) if not order or order.owner_id != user.id: raise HTTPException(status_code=404, detail="not found") if "paid" not in ALLOWED.get(order.status, set()): raise HTTPException(status_code=409, detail="invalid transition") await repo.update_order(order_id, status="paid")
144
+ pattern-either:
145
+ - pattern: |-
146
+ @app.post("/orders/{order_id}/pay")
147
+ async def pay(order_id: int):
148
+ await repo.update_order(order_id, status="paid")
149
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-007\\b'
150
+ message: |-
151
+ RunSec Detection [BIZ-007]: OWASP API Security Top 10 (2023) API6 Unrestricted Access to Sensitive Business Flows
152
+ languages:
153
+ - python
154
+ severity: WARNING
155
+ - id: runsec.app-logic.biz-008
156
+ metadata:
157
+ runsec_version: v1.0
158
+ confidence: |-
159
+ 0.9
160
+ exploit_scenario: |-
161
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
162
+ fix_template: |-
163
+ @app.post("/transfers") async def transfer(req: TransferRequest, request: Request, user=Depends(current_user)): idem = request.headers.get("Idempotency-Key", "").strip() if not idem: raise HTTPException(status_code=400, detail="missing idempotency key") if await idem_store.exists(user.id, idem): raise HTTPException(status_code=409, detail="duplicate request") result = await svc.transfer(user.id, req.target_id, req.amount) await idem_store.save(user.id, idem) return result
164
+ pattern-either:
165
+ - pattern: |-
166
+ @app.post("/transfers")
167
+ async def transfer(req: TransferRequest, user=Depends(current_user)):
168
+ return await svc.transfer(user.id, req.target_id, req.amount)
169
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-008\\b'
170
+ message: |-
171
+ RunSec Detection [BIZ-008]: OWASP API Security Top 10 (2023) API6 Unrestricted Access to Sensitive Business Flows; OWASP ASVS v4.0.3 V3 Session Management
172
+ languages:
173
+ - python
174
+ severity: WARNING
175
+ - id: runsec.app-logic.biz-009
176
+ metadata:
177
+ runsec_version: v1.0
178
+ confidence: |-
179
+ 0.9
180
+ exploit_scenario: |-
181
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
182
+ fix_template: |-
183
+ @app.get("/invoices/{invoice_id}") async def invoice(invoice_id: int, user=Depends(current_user)): inv = await repo.get_invoice(invoice_id) if not inv or inv.tenant_id != user.tenant_id: raise HTTPException(status_code=404, detail="not found") return inv
184
+ pattern-either:
185
+ - pattern: |-
186
+ @app.get("/invoices/{invoice_id}")
187
+ async def invoice(invoice_id: int):
188
+ return await repo.get_invoice(invoice_id)
189
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-009\\b'
190
+ message: |-
191
+ RunSec Detection [BIZ-009]: OWASP Top 10 (2021) A01 Broken Access Control; OWASP API Security Top 10 (2023) API1 Broken Object Level Authorization
192
+ languages:
193
+ - python
194
+ severity: WARNING
195
+ - id: runsec.app-logic.biz-010
196
+ metadata:
197
+ runsec_version: v1.0
198
+ confidence: |-
199
+ 0.9
200
+ exploit_scenario: |-
201
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
202
+ fix_template: |-
203
+ @app.post("/users/me/change-email") async def change_email(req: ChangeEmailRequest, user=Depends(current_user)): if not await auth.verify_password(user.id, req.current_password): raise HTTPException(status_code=401, detail="re-auth required") await repo.update_user(user.id, email=req.new_email)
204
+ pattern-either:
205
+ - pattern: |-
206
+ @app.post("/users/me/change-email")
207
+ async def change_email(req: ChangeEmailRequest, user=Depends(current_user)):
208
+ await repo.update_user(user.id, email=req.new_email)
209
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-010\\b'
210
+ message: |-
211
+ RunSec Detection [BIZ-010]: OWASP API Security Top 10 (2023) API2 Broken Authentication; OWASP ASVS v4.0.3 V2
212
+ languages:
213
+ - python
214
+ severity: WARNING
215
+ - id: runsec.app-logic.biz-011
216
+ metadata:
217
+ runsec_version: v1.0
218
+ confidence: |-
219
+ 0.9
220
+ exploit_scenario: |-
221
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
222
+ fix_template: |-
223
+ def _is_blocked_host(host: str) -> bool: if host in {"localhost"}: return True try: ip = ipaddress.ip_address(host) return ip.is_private or ip.is_loopback or ip.is_link_local except ValueError: return False @app.post("/preview") async def preview(dto: PreviewRequest): parsed = urlparse(dto.url) if parsed.scheme not in {"https"} or not parsed.hostname or _is_blocked_host(parsed.hostname): raise HTTPException(status_code=400, detail="blocked target") async with httpx.AsyncClient(timeout=5.0, follow_redirects=False) as client: r = await client.get(dto.url) return {"status": r.status_code}
224
+ pattern-either:
225
+ - pattern: |-
226
+ @app.post("/preview")
227
+ async def preview(dto: dict):
228
+ async with httpx.AsyncClient() as client:
229
+ r = await client.get(dto["url"])
230
+ return {"status": r.status_code}
231
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-011\\b'
232
+ message: |-
233
+ RunSec Detection [BIZ-011]: OWASP API Security Top 10 (2023) API7: Server Side Request Forgery; OWASP ASVS v4.0.3 V5 Validation, Sanitization and Encoding
234
+ languages:
235
+ - python
236
+ severity: WARNING
237
+ - id: runsec.app-logic.biz-012
238
+ metadata:
239
+ runsec_version: v1.0
240
+ confidence: |-
241
+ 0.9
242
+ exploit_scenario: |-
243
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
244
+ fix_template: |-
245
+ class RiskResponse(BaseModel): user_id: int risk_level: Literal["low", "medium", "high"] allow_transfer: bool @app.get("/risk/{user_id}") async def risk(user_id: int): async with httpx.AsyncClient(timeout=5.0) as client: r = await client.get(f"http://risk.internal/score/{user_id}") r.raise_for_status() data = RiskResponse.model_validate(r.json()) if data.user_id != user_id: raise HTTPException(status_code=502, detail="upstream mismatch") return {"allow_transfer": data.allow_transfer}
246
+ pattern-either:
247
+ - pattern: |-
248
+ @app.get("/risk/{user_id}")
249
+ async def risk(user_id: int):
250
+ async with httpx.AsyncClient(timeout=5.0) as client:
251
+ r = await client.get(f"http://risk.internal/score/{user_id}")
252
+ return {"allow_transfer": r.json()["allow_transfer"]}
253
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-012\\b'
254
+ message: |-
255
+ RunSec Detection [BIZ-012]: OWASP API Security Top 10 (2023) API10: Unsafe Consumption of APIs; OWASP ASVS v4.0.3 V14 Config / V5 Input Validation
256
+ languages:
257
+ - python
258
+ severity: WARNING
259
+ - id: runsec.app-logic.biz-013
260
+ metadata:
261
+ runsec_version: v1.0
262
+ confidence: |-
263
+ 0.9
264
+ exploit_scenario: |-
265
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
266
+ fix_template: |-
267
+ def create_app(env: str) -> FastAPI: app = FastAPI() if env != "prod": @app.get("/debug/sql") async def debug_sql(): return {"ok": True} return app @app.get("/legacy/report", include_in_schema=False) async def legacy_report(): raise HTTPException(status_code=410, detail="endpoint removed")
268
+ pattern-either:
269
+ - pattern: |-
270
+ @app.get("/debug/sql")
271
+ async def debug_sql():
272
+ return {"dsn": os.getenv("DATABASE_URL")}
273
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-013\\b'
274
+ message: |-
275
+ RunSec Detection [BIZ-013]: OWASP API Security Top 10 (2023) API9: Improper Inventory Management; OWASP Top 10 (2021) A05 Security Misconfiguration
276
+ languages:
277
+ - python
278
+ severity: WARNING
279
+ - id: runsec.app-logic.biz-014
280
+ metadata:
281
+ runsec_version: v1.0
282
+ confidence: |-
283
+ 0.9
284
+ exploit_scenario: |-
285
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
286
+ fix_template: |-
287
+ @app.post("/wallet/transfer") async def transfer(req: TransferRequest, db=Depends(get_db)): async with db.transaction(): src = await repo.get_wallet_for_update(req.src_id, db) dst = await repo.get_wallet_for_update(req.dst_id, db) if src.balance < req.amount: raise HTTPException(status_code=409, detail="insufficient funds") await repo.update_balance(req.src_id, -req.amount, db) await repo.update_balance(req.dst_id, req.amount, db)
288
+ pattern-either:
289
+ - pattern: |-
290
+ @app.post("/wallet/transfer")
291
+ async def transfer(req: TransferRequest):
292
+ src = await repo.get_wallet(req.src_id)
293
+ dst = await repo.get_wallet(req.dst_id)
294
+ src.balance -= req.amount
295
+ dst.balance += req.amount
296
+ await repo.save_wallet(src)
297
+ await repo.save_wallet(dst)
298
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-014\\b'
299
+ message: |-
300
+ RunSec Detection [BIZ-014]: OWASP API Security Top 10 (2023) API6: Unrestricted Access to Sensitive Business Flows; OWASP Top 10 (2021) A04 Insecure Design
301
+ languages:
302
+ - python
303
+ severity: WARNING
304
+ - id: runsec.app-logic.biz-015
305
+ metadata:
306
+ runsec_version: v1.0
307
+ confidence: |-
308
+ 0.9
309
+ exploit_scenario: |-
310
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
311
+ fix_template: |-
312
+ @app.get("/search") async def search(request: Request): roles = request.query_params.getlist("role") if len(roles) != 1: raise HTTPException(status_code=400, detail="duplicate role parameter") role = roles[0] if role not in {"user", "manager"}: raise HTTPException(status_code=400, detail="invalid role") return await repo.search(role=role)
313
+ pattern-either:
314
+ - pattern: |-
315
+ @app.get("/search")
316
+ async def search(role: str = "user"):
317
+ return await repo.search(role=role)
318
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-015\\b'
319
+ message: |-
320
+ RunSec Detection [BIZ-015]: OWASP API Security Top 10 (2023) API8: Security Misconfiguration; OWASP ASVS v4.0.3 V5 Validation, Sanitization and Encoding
321
+ languages:
322
+ - python
323
+ severity: WARNING
324
+ - id: runsec.app-logic.biz-016
325
+ metadata:
326
+ runsec_version: v1.0
327
+ confidence: |-
328
+ 0.9
329
+ exploit_scenario: |-
330
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
331
+ fix_template: |-
332
+ MAX_EXPORT_ROWS = 10000 @app.get("/exports/orders.csv") async def export_orders(limit: int = 1000): if limit <= 0 or limit > MAX_EXPORT_ROWS: raise HTTPException(status_code=400, detail="limit out of range") rows = await repo.list_orders(limit=limit) return to_csv(rows)
333
+ pattern-either:
334
+ - pattern: |-
335
+ @app.get("/exports/orders.csv")
336
+ async def export_orders(limit: int = 1000000):
337
+ rows = await repo.list_orders(limit=limit)
338
+ return to_csv(rows)
339
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-016\\b'
340
+ message: |-
341
+ RunSec Detection [BIZ-016]: OWASP API Security Top 10 (2023) API4: Unrestricted Resource Consumption; OWASP ASVS v4.0.3 V1 Architecture, Design and Threat Modeling
342
+ languages:
343
+ - python
344
+ severity: WARNING
345
+ - id: runsec.app-logic.biz-017
346
+ metadata:
347
+ runsec_version: v1.0
348
+ confidence: |-
349
+ 0.9
350
+ exploit_scenario: |-
351
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
352
+ fix_template: |-
353
+ DANGEROUS_PREFIXES = ("=", "+", "-", "@") def sanitize_cell(value: str) -> str: if value.startswith(DANGEROUS_PREFIXES): return "'" + value return value def row_to_csv(user: dict[str, str]) -> list[str]: return [ sanitize_cell(user["name"]), sanitize_cell(user["email"]), sanitize_cell(user["comment"]), ]
354
+ pattern-either:
355
+ - pattern: |-
356
+ def row_to_csv(user: dict[str, str]) -> list[str]:
357
+ return [user["name"], user["email"], user["comment"]]
358
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-017\\b'
359
+ message: |-
360
+ RunSec Detection [BIZ-017]: OWASP API Security Top 10 (2023) API8: Security Misconfiguration; OWASP ASVS v4.0.3 V5 Validation, Sanitization and Encoding
361
+ languages:
362
+ - python
363
+ severity: WARNING
364
+ - id: runsec.app-logic.biz-018
365
+ metadata:
366
+ runsec_version: v1.0
367
+ confidence: |-
368
+ 0.9
369
+ exploit_scenario: |-
370
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
371
+ fix_template: |-
372
+ @app.post("/checkout") async def checkout(req: CheckoutRequest, user=Depends(current_user)): items = await catalog.get_items(req.item_ids) subtotal = sum(item.price for item in items) discount = await promotions.calculate_discount(user.id, req.promo_code, items) total = max(subtotal - discount, 0) if req.client_total is not None and abs(req.client_total - total) > Decimal("0.01"): raise HTTPException(status_code=400, detail="price tampering detected") await billing.charge(user.id, total)
373
+ pattern-either:
374
+ - pattern: |-
375
+ @app.post("/checkout")
376
+ async def checkout(payload: dict):
377
+ order_total = payload["client_total"]
378
+ discount = payload.get("discount", 0)
379
+ await billing.charge(payload["user_id"], order_total - discount)
380
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-018\\b'
381
+ message: |-
382
+ RunSec Detection [BIZ-018]: OWASP API Security Top 10 (2023) API3: Broken Object Property Level Authorization / API8: Security Misconfiguration; OWASP ASVS v4.0.3 V4 Access Control and V5 Validation
383
+ languages:
384
+ - python
385
+ severity: WARNING
386
+ - id: runsec.app-logic.biz-019
387
+ metadata:
388
+ runsec_version: v1.0
389
+ confidence: |-
390
+ 0.9
391
+ exploit_scenario: |-
392
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
393
+ fix_template: |-
394
+ @app.post("/webhook/payment") async def payment_webhook(request: Request): body = await request.body() sig = request.headers.get("x-signature", "") if not verify_hmac(body, sig, webhook_secret): raise HTTPException(status_code=401, detail="invalid signature") payload = json.loads(body) ... await payments.mark_paid(payload["order_id"])
395
+ pattern-either:
396
+ - pattern: |-
397
+ @app.post("/webhook/payment")
398
+ async def payment_webhook(request: Request):
399
+ payload = await request.json()
400
+ ...
401
+ await payments.mark_paid(payload["order_id"])
402
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-019\\b'
403
+ message: |-
404
+ RunSec Detection [BIZ-019]: CWE-345
405
+ languages:
406
+ - python
407
+ severity: WARNING
408
+ - id: runsec.app-logic.biz-020
409
+ metadata:
410
+ runsec_version: v1.0
411
+ confidence: |-
412
+ 0.9
413
+ exploit_scenario: |-
414
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
415
+ fix_template: |-
416
+ Явно задавать безопасный serializer (json/msgpack), запретить pickle в job payload и валидировать схему аргументов задач.
417
+ pattern-either:
418
+ - pattern: |-
419
+ Queue("default", connection=redis_conn)
420
+ Worker([q], connection=redis_conn)
421
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-020\\b'
422
+ message: |-
423
+ RunSec Detection [BIZ-020]: CWE Final Certification
424
+ languages:
425
+ - python
426
+ severity: WARNING
427
+ - id: runsec.app-logic.biz-021
428
+ metadata:
429
+ runsec_version: v1.0
430
+ confidence: |-
431
+ 0.9
432
+ exploit_scenario: |-
433
+ Атакующий доставляет входные данные, соответствующие anti-pattern; реальный ущерб зависит от приёмника (sink), конфигурации и границ доверия.
434
+ fix_template: |-
435
+ Всегда задавать timeout (и retry budget), чтобы исключить зависание и неконтролируемое потребление ресурсов.
436
+ pattern-either:
437
+ - pattern: |-
438
+ httpx.get(url)
439
+ httpx.post(api, json=payload)
440
+ - pattern-regex: 'Vulnerable:\\s*BIZ\\-021\\b'
441
+ message: |-
442
+ RunSec Detection [BIZ-021]: CWE Final Certification
443
+ languages:
444
+ - python
445
+ severity: WARNING