@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.
- package/dist/index.js +578 -0
- package/package.json +43 -0
- package/src/rules/data/rule-compliance-map.json +43563 -0
- package/src/rules/data/semgrep-rules/README-taint-overlays.md +21 -0
- package/src/rules/data/semgrep-rules/advanced-agent-cloud.yaml +802 -0
- package/src/rules/data/semgrep-rules/app-logic.yaml +445 -0
- package/src/rules/data/semgrep-rules/auth-keycloak.yaml +831 -0
- package/src/rules/data/semgrep-rules/browser-agent.yaml +260 -0
- package/src/rules/data/semgrep-rules/cloud-secrets.yaml +316 -0
- package/src/rules/data/semgrep-rules/csharp-dotnet.yaml +4864 -0
- package/src/rules/data/semgrep-rules/desktop-electron-pro.yaml +30 -0
- package/src/rules/data/semgrep-rules/desktop-vsto-suite.yaml +2759 -0
- package/src/rules/data/semgrep-rules/devops-security.yaml +393 -0
- package/src/rules/data/semgrep-rules/domain-access-management.yaml +1023 -0
- package/src/rules/data/semgrep-rules/domain-data-privacy.yaml +852 -0
- package/src/rules/data/semgrep-rules/domain-input-validation.yaml +2894 -0
- package/src/rules/data/semgrep-rules/domain-platform-hardening.yaml +1715 -0
- package/src/rules/data/semgrep-rules/ds-ml-security.yaml +2431 -0
- package/src/rules/data/semgrep-rules/fastapi-async.yaml +5953 -0
- package/src/rules/data/semgrep-rules/frontend-react.yaml +4035 -0
- package/src/rules/data/semgrep-rules/frontend-security.yaml +200 -0
- package/src/rules/data/semgrep-rules/go-core.yaml +4959 -0
- package/src/rules/data/semgrep-rules/hft-cpp-security.yaml +631 -0
- package/src/rules/data/semgrep-rules/infra-k8s-helm.yaml +4968 -0
- package/src/rules/data/semgrep-rules/integration-security.yaml +2362 -0
- package/src/rules/data/semgrep-rules/java-enterprise.yaml +14756 -0
- package/src/rules/data/semgrep-rules/java-spring.yaml +397 -0
- package/src/rules/data/semgrep-rules/license-compliance.yaml +186 -0
- package/src/rules/data/semgrep-rules/mobile-flutter.yaml +37 -0
- package/src/rules/data/semgrep-rules/mobile-security.yaml +721 -0
- package/src/rules/data/semgrep-rules/nodejs-nestjs.yaml +5164 -0
- package/src/rules/data/semgrep-rules/nodejs-security.yaml +326 -0
- package/src/rules/data/semgrep-rules/observability.yaml +381 -0
- package/src/rules/data/semgrep-rules/php-security.yaml +3601 -0
- package/src/rules/data/semgrep-rules/python-backend-pro.yaml +30 -0
- package/src/rules/data/semgrep-rules/python-django.yaml +181 -0
- package/src/rules/data/semgrep-rules/python-security.yaml +284 -0
- package/src/rules/data/semgrep-rules/ru-regulatory.yaml +496 -0
- package/src/rules/data/semgrep-rules/ruby-rails.yaml +3078 -0
- 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
|