fix(agent): address CRITICAL/HIGH security and validation issues

- Fix SSE JSON injection: use json.dumps for safe serialization
- Add tool validation to dispatcher with allowlist
- Add field validation to tool_registry with proper error handling
- Add run_id consistency check (409 on mismatch)
- Add RunAgentInput constraints: min_length, extra=forbid
- Fix crewai_flow: use Field(default_factory), prefix unused params
This commit is contained in:
qzl
2026-03-03 16:25:43 +08:00
parent ff85c1ab08
commit 9aefb76c9e
7 changed files with 68 additions and 28 deletions
+17 -10
View File
@@ -1,5 +1,6 @@
from __future__ import annotations
import json
from collections.abc import AsyncGenerator
from datetime import datetime, timezone
from decimal import Decimal
@@ -379,17 +380,23 @@ class AgentChatService(BaseService):
return ResumeDecisionResult(applied=True)
async def stream_run(self, input_data: RunAgentInput) -> AsyncGenerator[str, None]:
yield 'data: {"type": "RUN_STARTED", "runId": "' + input_data.runId + '"}\n\n'
yield 'data: {"type": "TEXT_MESSAGE_START", "messageId": "m1"}\n\n'
yield 'data: {"type": "TEXT_MESSAGE_CONTENT", "delta": "Hello"}\n\n'
yield 'data: {"type": "TEXT_MESSAGE_END", "messageId": "m1"}\n\n'
yield 'data: {"type": "RUN_FINISHED", "runId": "' + input_data.runId + '"}\n\n'
if "\n" in input_data.runId or "\r" in input_data.runId:
raise ValueError("runId must not contain newlines")
yield f"data: {json.dumps({'type': 'RUN_STARTED', 'runId': input_data.runId})}\n\n"
yield f"data: {json.dumps({'type': 'TEXT_MESSAGE_START', 'messageId': 'm1'})}\n\n"
yield f"data: {json.dumps({'type': 'TEXT_MESSAGE_CONTENT', 'delta': 'Hello'})}\n\n"
yield f"data: {json.dumps({'type': 'TEXT_MESSAGE_END', 'messageId': 'm1'})}\n\n"
yield f"data: {json.dumps({'type': 'RUN_FINISHED', 'runId': input_data.runId})}\n\n"
async def stream_resume(
self, run_id: str, input_data: RunAgentInput
) -> AsyncGenerator[str, None]:
yield 'data: {"type": "RUN_STARTED", "runId": "' + run_id + '"}\n\n'
yield 'data: {"type": "TEXT_MESSAGE_START", "messageId": "m2"}\n\n'
yield 'data: {"type": "TEXT_MESSAGE_CONTENT", "delta": "Resumed"}\n\n'
yield 'data: {"type": "TEXT_MESSAGE_END", "messageId": "m2"}\n\n'
yield 'data: {"type": "RUN_FINISHED", "runId": "' + run_id + '"}\n\n'
if "\n" in run_id or "\r" in run_id:
raise ValueError("runId must not contain newlines")
yield f"data: {json.dumps({'type': 'RUN_STARTED', 'runId': run_id})}\n\n"
yield f"data: {json.dumps({'type': 'TEXT_MESSAGE_START', 'messageId': 'm2'})}\n\n"
yield f"data: {json.dumps({'type': 'TEXT_MESSAGE_CONTENT', 'delta': 'Resumed'})}\n\n"
yield f"data: {json.dumps({'type': 'TEXT_MESSAGE_END', 'messageId': 'm2'})}\n\n"
yield f"data: {json.dumps({'type': 'RUN_FINISHED', 'runId': run_id})}\n\n"