diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 1c145b3a..8274f332 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -2,3 +2,8 @@ **Vulnerability:** User-provided string fields (like project and connection names) lacked strict validation against control characters, only relying on length constraints. **Learning:** This could potentially lead to Log Injection (CRLF injection), Null Byte Injection, or terminal escape injection if these strings are subsequently logged or rendered directly. **Prevention:** Use explicit regex validation `pattern=r'^[^\x00-\x1F\x7F]+$'` on Pydantic string fields to strictly reject control characters. + +## 2025-02-27 - Strict ASCII Control Character Validation in Pydantic Schemas +**Vulnerability:** Pydantic `str` fields intended for identifiers/names (e.g., `DiagramViewCreateIn.name`, `TableAnnotationUpsertIn.schema_name`, `ApiKeyCreateIn.key_name`) were previously lacking strict validation against ASCII control characters, exposing the system to potential log injection and terminal escape sequence vulnerabilities. +**Learning:** Standard length limits (`min_length`, `max_length`) do not prevent the ingestion of invisible control characters (`\x00-\x1F\x7F`). +**Prevention:** Enforce strict pattern matching using `pattern=r"^[^\x00-\x1F\x7F]+$"` for string fields that do not legitimately require multiline inputs or control characters, preventing malicious inputs from persisting into logs or execution environments. diff --git a/backend/app/schemas.py b/backend/app/schemas.py index d7c6de77..5fd3a792 100644 --- a/backend/app/schemas.py +++ b/backend/app/schemas.py @@ -190,7 +190,11 @@ class IndexRedundancyOut(BaseModel): class DiagramViewCreateIn(BaseModel): """Request body for saving an ERD canvas view.""" - name: str = Field(min_length=1, max_length=200) + name: str = Field( + min_length=1, + max_length=200, + pattern=r"^[^\x00-\x1F\x7F]+$", + ) # Opaque client layout (node positions, hidden tables, viewport). The API # bounds the serialized size in the endpoint to prevent abuse. layout_json: dict @@ -214,8 +218,16 @@ class DiagramViewDetailOut(DiagramViewOut): class TableAnnotationUpsertIn(BaseModel): """Request body for creating/updating a table annotation.""" - schema_name: str = Field(min_length=1, max_length=255) - relation_name: str = Field(min_length=1, max_length=255) + schema_name: str = Field( + min_length=1, + max_length=255, + pattern=r"^[^\x00-\x1F\x7F]+$", + ) + relation_name: str = Field( + min_length=1, + max_length=255, + pattern=r"^[^\x00-\x1F\x7F]+$", + ) body: str = Field(min_length=1, max_length=10_000) @@ -302,7 +314,11 @@ class DbmlConvertOut(BaseModel): class ApiKeyCreateIn(BaseModel): """Request body for creating an API key.""" - key_name: str = Field(min_length=1, max_length=128) + key_name: str = Field( + min_length=1, + max_length=128, + pattern=r"^[^\x00-\x1F\x7F]+$", + ) class ApiKeyOut(BaseModel):