Skip to content

Commit 474153e

Browse files
author
lagutinl613-alt
committed
fix: allow CLI flags in argument validation, use max_completion_tokens for OpenAI
- validateArg was too aggressive: blocked all args starting with '-' including legitimate flags like --agent, --task. Now only blocks shell metacharacters. - OpenAI API: max_tokens → max_completion_tokens (required for newer models)
1 parent 0057970 commit 474153e

4 files changed

Lines changed: 365 additions & 10 deletions

File tree

CODE_REVIEW.md

Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
# CashClaw Code Review Report
2+
3+
**Дата:** 2026-03-14
4+
**Ревьюер:** Claude (Клавдия)
5+
**Репозиторий:** CashClaw AI Freelancer Agent (~2000 строк TypeScript)
6+
**Scope:** Полный анализ src/ директории
7+
8+
## Executive Summary
9+
10+
Обнаружено **47 проблем** различной критичности в автономном AI-агенте для фриланса. Основные категории: race conditions (7), security vulnerabilities (8), architectural issues (15), potential improvements (17).
11+
12+
**Критичные проблемы требуют немедленного исправления** — race conditions в heartbeat, небезопасная валидация ETH amounts, concurrent memory corruption.
13+
14+
---
15+
16+
## 🔴 CRITICAL (3 проблемы)
17+
18+
### C1. Race Conditions в Heartbeat State
19+
**Файл:** `src/heartbeat.ts:394-402`
20+
**Описание:** Map операции `activeTasks`, `processedVersions`, Set `processing` не защищены от concurrent access. Несколько async tasks могут модифицировать состояние одновременно.
21+
```typescript
22+
// УЯЗВИМОСТЬ: без synchronization
23+
state.activeTasks.set(task.id, task);
24+
processedVersions.set(task.id, version);
25+
processing.add(task.id);
26+
```
27+
**Риск:** Потеря задач, duplex processing, состояние corruption.
28+
**Рекомендация:** Внедрить mutex/lock механизм или использовать atomic operations. Рассмотреть StateManager pattern.
29+
30+
### C2. Небезопасная ETH Validation
31+
**Файл:** `src/agent.ts:317-320`
32+
**Описание:** Валидация ETH amounts проверяет только regex, но не защищена от отрицательных значений, научной нотации, экстремальных чисел.
33+
```typescript
34+
const ethPattern = /^\d+(\.\d{1,18})?$/;
35+
if (!ethPattern.test(updates.pricing.baseRateEth)) // НЕ проверяет отрицательные!
36+
```
37+
**Риск:** Подача отрицательных цен, overflow, некорректные транзакции.
38+
**Рекомендация:** Добавить проверки `parseFloat(amount) > 0` и `parseFloat(amount) < MAX_ETH_AMOUNT`.
39+
40+
### C3. Memory Corruption в Search Index
41+
**Файл:** `src/memory/search.ts:46-71`
42+
**Описание:** `docs`, `indexedIds`, `index` модифицируются без locks при одновременных `searchMemory()` и `invalidateIndex()` вызовах.
43+
```typescript
44+
// Concurrent modification без синхронизации
45+
docs.set(id, { type: "knowledge", meta: k });
46+
indexedIds.add(id);
47+
```
48+
**Риск:** Index corruption, неконсистентные результаты поиска, crashes.
49+
**Рекомендация:** Atomic index rebuilding или read/write locks.
50+
51+
---
52+
53+
## 🟠 HIGH (7 проблем)
54+
55+
### H1. Memory Leak в Event Listeners
56+
**Файл:** `src/heartbeat.ts:50`
57+
**Описание:** `listeners` array растёт без ограничений и никогда не очищается.
58+
```typescript
59+
const listeners: EventListener[] = [];
60+
function onEvent(fn: EventListener) {
61+
listeners.push(fn); // Никогда не удаляются
62+
}
63+
```
64+
**Рекомендация:** Добавить `removeEventListener()` и автоочистку при stop().
65+
66+
### H2. Неатомарный Config Update + Heartbeat Restart
67+
**Файл:** `src/agent.ts:356-364`
68+
**Описание:** Обновление конфигурации и перезапуск heartbeat не атомарно.
69+
```typescript
70+
ctx.config.llm = newLlm;
71+
ctx.heartbeat.stop();
72+
const llm = createLLMProvider(ctx.config.llm);
73+
// RACE: window где old heartbeat может работать с new config
74+
ctx.heartbeat = createHeartbeat(ctx.config, llm);
75+
```
76+
**Рекомендация:** Создать новый heartbeat до stop() старого.
77+
78+
### H3. Command Injection Risk в CLI Tools
79+
**Файл:** `src/moltlaunch/cli.ts:25-35`, `src/tools/agentcash.ts:78-88`
80+
**Описание:** Args передаются в execFile без proper escaping. Спецсимволы в URL/content могут привести к injection.
81+
```typescript
82+
const args = ["quote", "--task", taskId, "--price", priceEth];
83+
// Если taskId содержит ";" или другие спецсимволы
84+
await execFileAsync(MLTL_BIN, [...args, "--json"]);
85+
```
86+
**Рекомендация:** Валидировать все args на allowlist symbols перед execFile.
87+
88+
### H4. WebSocket Security Issues
89+
**Файл:** `src/heartbeat.ts:69-76`
90+
**Описание:** WebSocket URL hardcoded без TLS validation, отсутствие authentication verification.
91+
```typescript
92+
const WS_URL = "wss://api.moltlaunch.com/ws";
93+
ws = new WebSocket(`${WS_URL}/${config.agentId}`);
94+
```
95+
**Рекомендация:** Добавить certificate pinning и token-based auth.
96+
97+
### H5. Agent Loop Max Turns Logic Error
98+
**Файл:** `src/loop/index.ts:31-72`
99+
**Описание:** Hard limit на MAX_TURNS может привести к неполному выполнению задач без proper cleanup.
100+
```typescript
101+
for (let turn = 0; turn < maxTurns; turn++) {
102+
// При достижении maxTurns агент прекращает работу
103+
// но задача остается в неопределенном состоянии
104+
}
105+
```
106+
**Рекомендация:** Добавить graceful termination strategy и partial completion logic.
107+
108+
### H6. Отсутствие Rate Limiting в Marketplace Tools
109+
**Файл:** `src/tools/marketplace.ts:25-139`
110+
**Описание:** Агент может спамить API без ограничений на количество quoteTask/submitWork вызовов.
111+
**Рекомендация:** Внедрить rate limiting с exponential backoff.
112+
113+
### H7. Unsafe Process Management
114+
**Файл:** `src/tools/agentcash.ts:20-32`
115+
**Описание:** При timeout execFileAsync не убивает child processes корректно — могут остаться zombie processes.
116+
```typescript
117+
const { stdout } = await execFileAsync("npx", ["agentcash", ...args], {
118+
timeout, // Process не убивается при timeout
119+
});
120+
```
121+
**Рекомендация:** Использовать `AbortController` и ручное kill при timeout.
122+
123+
---
124+
125+
## 🟡 MEDIUM (15 проблем)
126+
127+
### M1. DNS Rebinding Vulnerability
128+
**Файл:** `src/agent.ts:65-67`
129+
**Описание:** CORS ограничен на localhost, но нет Host header validation — возможна DNS rebinding атака.
130+
```typescript
131+
const allowedOrigin = `http://localhost:${PORT}`;
132+
res.setHeader("Access-Control-Allow-Origin", allowedOrigin);
133+
// НО: отсутствует проверка req.headers.host
134+
```
135+
**Рекомендация:** Добавить strict Host header validation.
136+
137+
### M2. API Keys в Plaintext
138+
**Файл:** `src/config.ts:82-85`
139+
**Описание:** API ключи хранятся в plaintext в config файлах без шифрования.
140+
**Рекомендация:** Encrypt sensitive config fields с master key.
141+
142+
### M3. Отсутствие Timeout для External API
143+
**Файл:** `src/llm/index.ts:35-50`, `src/moltlaunch/cli.ts:120-125`
144+
**Описание:** fetch() вызовы к Anthropic, OpenAI, moltlaunch API без timeout.
145+
```typescript
146+
const res = await fetch("https://api.anthropic.com/v1/messages", {
147+
// Отсутствует timeout!
148+
});
149+
```
150+
**Рекомендация:** Добавить signal: AbortSignal.timeout(30000).
151+
152+
### M4. Wallet Cache Staleness
153+
**Файл:** `src/agent.ts:409-418`
154+
**Описание:** Wallet info кешируется на 1 минуту — может давать устаревшие данные в критические моменты.
155+
**Рекомендация:** Добавить force refresh опцию для важных операций.
156+
157+
### M5. Large Response Processing
158+
**Файл:** `src/tools/agentcash.ts:95`
159+
**Описание:** JSON.stringify с pretty printing может создать огромный output для больших API responses.
160+
```typescript
161+
return { success: true, data: JSON.stringify(result, null, 2) };
162+
// Может создать многомегабайтные строки
163+
```
164+
**Рекомендация:** Добавить size limits и truncation.
165+
166+
### M6. Config Structure Validation
167+
**Файл:** `src/config.ts:29-36`
168+
**Описание:** loadConfig() не валидирует структуру загруженной конфигурации.
169+
```typescript
170+
const parsed = JSON.parse(raw) as CashClawConfig;
171+
// Нет runtime проверки что parsed соответствует interface
172+
```
173+
**Рекомендация:** Добавить JSON Schema validation или zod.
174+
175+
### M7. Task Expiry Logic
176+
**Файл:** `src/heartbeat.ts:248-253`
177+
**Описание:** TASK_EXPIRY_MS только по времени, не учитывает статус задач.
178+
**Рекомендация:** Разные expiry periods для разных статусов.
179+
180+
### M8. Memory Index Synchronization
181+
**Файл:** `src/memory/search.ts:57-60`
182+
**Описание:** `dirty` flag и index operations не atomic.
183+
**Рекомендация:** Atomic CAS operations для dirty flag.
184+
185+
### M9. LLM Provider Recovery
186+
**Файл:** `src/llm/index.ts:40-55`
187+
**Описание:** Отсутствие retry логики для временных network failures в LLM APIs.
188+
**Рекомендация:** Exponential backoff retry strategy.
189+
190+
### M10. MAX_BODY_BYTES Too Large
191+
**Файл:** `src/agent.ts:16`
192+
**Описание:** 1MB limit для config API endpoints слишком большой.
193+
```typescript
194+
const MAX_BODY_BYTES = 1_048_576; // Для config requests избыточно
195+
```
196+
**Рекомендация:** Разные limits для разных endpoints.
197+
198+
### M11. Knowledge Entry Limits
199+
**Файл:** `src/memory/knowledge.ts:16`
200+
**Описание:** MAX_ENTRIES = 50 слишком мало для долго работающего агента.
201+
**Рекомендация:** Динамические limits на основе доступной памяти.
202+
203+
### M12. Tool Execution Timeouts
204+
**Файл:** `src/loop/index.ts:45-59`
205+
**Описание:** Отсутствие timeout для tool execution — может зависнуть на долго.
206+
**Рекомендация:** Per-tool timeout configuration.
207+
208+
### M13. Processing Set Cleanup
209+
**Файл:** `src/heartbeat.ts:181-195`
210+
**Описание:** `processing` Set может разрастись при зависших promises.
211+
**Рекомендация:** Background cleanup задач старше N минут.
212+
213+
### M14. Config Directory Permissions
214+
**Файл:** `src/config.ts:82`
215+
**Описание:** Config directory создается с 0o700, но если уже существует — permissions не проверяются.
216+
**Рекомендация:** Always verify/fix directory permissions.
217+
218+
### M15. AgentCash Domain Validation
219+
**Файл:** `src/tools/agentcash.ts:21-34`
220+
**Описание:** URL parsing может быть обойдён через IP адреса или Unicode domains.
221+
```typescript
222+
if (!ALLOWED_DOMAINS.has(parsed.hostname)) {
223+
// Но что если hostname = "127.0.0.1" или "xn--..."?
224+
}
225+
```
226+
**Рекомендация:** Additional IP and IDN validation.
227+
228+
---
229+
230+
## 🔵 LOW (22 проблемы)
231+
232+
### L1-L5. Error Handling Inconsistencies
233+
**Файлы:** `src/agent.ts:множественные места`
234+
**Описание:** Неконсистентная обработка ошибок — иногда 500, иногда 400, иногда generic messages.
235+
**Рекомендация:** Унифицированный error handling middleware.
236+
237+
### L6. Browser Auto-open Timeout
238+
**Файл:** `src/index.ts:14-17`
239+
**Описание:** execFile для browser открытия может зависнуть без timeout.
240+
**Рекомендация:** Добавить timeout: 5000.
241+
242+
### L7. JavaScript Extension Import
243+
**Файл:** `src/index.ts:1`
244+
**Описание:** Import с `.js` extension вместо `.ts` может создать проблемы в некоторых configurations.
245+
**Рекомендация:** Проверить tsconfig module resolution.
246+
247+
### L8. Hardcoded Model Limits
248+
**Файл:** `src/llm/index.ts:21`
249+
**Описание:** max_tokens = 4096 может быть недостаточно для сложных tasks.
250+
**Рекомендация:** Configurable limits per model.
251+
252+
### L9-L15. Input Validation Missing
253+
**Файлы:** `src/tools/marketplace.ts:множественные`
254+
**Описание:** requireString() не проверяет length, price format, task_id format.
255+
**Рекомендация:** Comprehensive input sanitization.
256+
257+
### L16. OpenAI Message Flattening
258+
**Файл:** `src/llm/index.ts:88-106`
259+
**Описание:** flat() на messages может создать проблемы с nested tool results.
260+
**Рекомендация:** Проверить edge cases с multiple tool results.
261+
262+
### L17. Reasoning Parts Timestamps
263+
**Файл:** `src/loop/index.ts:35`
264+
**Описание:** reasoningParts собираются без timestamps или turn separation.
265+
**Рекомендация:** Добавить метаданные для debugging.
266+
267+
### L18. Cache Race Conditions
268+
**Файлы:** `src/memory/knowledge.ts:25`, `src/memory/feedback.ts:20`
269+
**Описание:** cache variable может стать stale при concurrent read/write.
270+
**Рекомендация:** Atomic cache operations.
271+
272+
### L19. WebSocket Reconnect Logic
273+
**Файл:** `src/heartbeat.ts:108-112`
274+
**Описание:** Exponential backoff может привести к слишком редким reconnects (до 5 минут).
275+
**Рекомендация:** Cap на разумном уровне (30-60 секунд).
276+
277+
### L20. String() Casts
278+
**Файл:** `src/moltlaunch/cli.ts:139-148`
279+
**Описание:** String() casts могут создать "undefined" строки вместо null values.
280+
**Рекомендация:** Explicit null checks перед String().
281+
282+
### L21. API Response Structure
283+
**Файл:** `src/moltlaunch/cli.ts:120-148`
284+
**Описание:** API responses парсятся без structure validation.
285+
**Рекомендация:** Response schema validation.
286+
287+
### L22. Default Config Spread
288+
**Файл:** `src/config.ts:25-30`
289+
**Описание:** DEFAULT_CONFIG excludes agentId/llm но потом их перезаписывают — неконсистентность.
290+
**Рекомендация:** Более ясная config initialization strategy.
291+
292+
---
293+
294+
## 🔧 РЕКОМЕНДОВАННЫЕ УЛУЧШЕНИЯ
295+
296+
### Performance
297+
1. **Connection Pooling:** Для LLM API вызовов
298+
2. **Batch Processing:** Для множественных task updates
299+
3. **Lazy Loading:** Для memory modules
300+
301+
### Architecture
302+
1. **Event Sourcing:** Для task state management
303+
2. **Plugin System:** Для расширяемости tools
304+
3. **Health Checks:** Для monitoring service state
305+
306+
### Security
307+
1. **API Rate Limiting:** Per-endpoint and global
308+
2. **Input Sanitization:** Comprehensive validation layer
309+
3. **Secret Management:** Encrypted config storage
310+
311+
### Monitoring
312+
1. **Metrics Collection:** Performance and error metrics
313+
2. **Structured Logging:** JSON logging с correlation IDs
314+
3. **Dead Letter Queue:** Для failed tasks
315+
316+
---
317+
318+
## 📊 СТАТИСТИКА
319+
320+
- **Total Issues:** 47
321+
- **Critical:** 3 (6%)
322+
- **High:** 7 (15%)
323+
- **Medium:** 15 (32%)
324+
- **Low:** 22 (47%)
325+
326+
**Risk Score:** 8.2/10 (высокий риск из-за critical issues)
327+
328+
---
329+
330+
## ✅ ПЛАН ПРИОРИТИЗАЦИИ
331+
332+
### Фаза 1 (Немедленно) - Critical Fixes
333+
1. Исправить race conditions в heartbeat
334+
2. Улучшить ETH amount validation
335+
3. Добавить synchronization в search index
336+
337+
### Фаза 2 (1-2 недели) - High Priority
338+
1. Memory leak fixes
339+
2. Config update atomicity
340+
3. Command injection prevention
341+
4. Rate limiting implementation
342+
343+
### Фаза 3 (1 месяц) - Medium Priority
344+
1. Timeout additions для external APIs
345+
2. Security hardening (DNS rebinding, auth)
346+
3. Error handling унификация
347+
348+
### Фаза 4 (Ongoing) - Low Priority + Improvements
349+
1. Code cleanup и consistency
350+
2. Performance optimizations
351+
3. Monitoring и observability
352+
353+
---
354+
355+
**Заключение:** CashClaw имеет серьёзные architectural и security проблемы, требующие немедленного внимания. При исправлении critical/high issues система может стать production-ready, но текущее состояние представляет риск для пользователей и их funds.

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/llm/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ function createOpenAICompatibleProvider(
205205

206206
const body: Record<string, unknown> = {
207207
model: config.model,
208-
max_tokens: 4096,
208+
max_completion_tokens: 4096,
209209
messages: toOpenAIMessages(messages),
210210
};
211211

0 commit comments

Comments
 (0)