Skip to content

Commit 18841b5

Browse files
authored
Default MAX_STRING_LENGTH to aggressive (#328)
* Default MAX_STRING_LENGTH to aggressive We had a MAX_STRING_LENGTH of 1000 which was lopping off deep research reports, changed to the more sensible 100,000 (100KB) Signed-off-by: Luke Hinds <lukehinds@gmail.com> * Don't use non type base int Signed-off-by: Luke Hinds <lukehinds@gmail.com> * Bump versions to v075 Signed-off-by: Luke Hinds <lukehinds@gmail.com> --------- Signed-off-by: Luke Hinds <lukehinds@gmail.com>
1 parent c2bc0de commit 18841b5

File tree

6 files changed

+62
-8
lines changed

6 files changed

+62
-8
lines changed

CLAUDE.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ src/agent/
155155
- **Authentication**: Never bypass authentication checks; use UnifiedAuthenticationManager for consistent auth handling
156156
- **Plugin Security**: Plugins must declare required scopes; use allowlist-based validation for plugin loading
157157
- **Audit Logging**: Log all security events (authentication, authorization, access denials) with appropriate risk levels
158+
- **Function Argument Sanitization**: Configure `max_string_length` and `sanitization_enabled` in security config to control how function arguments are sanitized:
159+
- `max_string_length: 100000` - Default 100KB limit for string arguments (prevents large file content truncation)
160+
- `max_string_length: -1` - Disable string length limits entirely (use with caution)
161+
- `sanitization_enabled: false` - Disable all argument sanitization (not recommended for production)
158162

159163
## Task Completion Workflow
160164

@@ -263,6 +267,10 @@ security:
263267
files:write: ["files:read"]
264268
api:admin: ["api:write", "api:read"]
265269
api:write: ["api:read"]
270+
271+
# Function argument sanitization settings
272+
sanitization_enabled: true # Enable function argument sanitization
273+
max_string_length: 100000 # Max string length in chars (100KB default, -1 = unlimited)
266274
```
267275
268276
**Important**: Each function requires specific scopes. If a user's API key doesn't have the required scope (either directly or through hierarchy inheritance), access will be denied with a 403 error.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "agentup"
3-
version = "0.7.4"
3+
version = "0.7.5"
44
description = "Create AI agents with all the trappings, out of the box."
55
readme = "README.md"
66
requires-python = ">=3.11"

src/agent/config/model.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,14 @@ class SecurityConfig(BaseModel):
313313
)
314314
scope_hierarchy: dict[str, list[str]] = Field(default_factory=dict, description="Scope hierarchy configuration")
315315

316+
# Function argument sanitization settings
317+
max_string_length: int = Field(
318+
default=100000,
319+
description="Maximum allowed string length in function arguments (in characters). Set to -1 to disable limit.",
320+
ge=-1,
321+
)
322+
sanitization_enabled: bool = Field(default=True, description="Enable function argument sanitization for security")
323+
316324
@field_validator("scope_hierarchy", mode="before")
317325
@classmethod
318326
def validate_scope_hierarchy(cls, v):

src/agent/core/function_executor.py

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,11 @@ async def execute_function_call(self, function_name: str, arguments: dict[str, A
174174
audit_logger.log_configuration_error(
175175
"function_validation",
176176
"function_validation_failed",
177-
{"correlation_id": correlation_id, "error_type": "ValueError", "function_name": function_name},
177+
{
178+
"correlation_id": correlation_id,
179+
"error_type": "ValueError",
180+
"function_name": function_name,
181+
},
178182
)
179183
return f"Invalid request format [ref:{correlation_id}]"
180184

@@ -211,7 +215,26 @@ async def execute_function_call(self, function_name: str, arguments: dict[str, A
211215

212216
def _sanitize_function_arguments(self, arguments: dict[str, Any], correlation_id: str) -> dict[str, Any]:
213217
"""Sanitize function arguments to prevent injection attacks."""
214-
MAX_STRING_LENGTH = 1000
218+
# Get configuration for security settings
219+
try:
220+
from agent.config import get_config
221+
222+
config = get_config()
223+
security_config = config.agent_config.security
224+
225+
# Check if sanitization is disabled
226+
if not security_config.sanitization_enabled:
227+
logger.debug(f"Function argument sanitization disabled [corr:{correlation_id}]")
228+
return arguments
229+
230+
# Get configurable string length limit
231+
max_string_length = security_config.max_string_length
232+
# A value of -1 indicates no limit. This is handled in the truncation logic below.
233+
234+
except Exception as e:
235+
logger.warning(f"Failed to load security config, using defaults [corr:{correlation_id}]: {e}")
236+
max_string_length = 100000 # Fallback to 100KB
237+
215238
MAX_NESTED_DEPTH = 5
216239
ALLOWED_TYPES = (str, int, float, bool, list, dict, type(None))
217240

@@ -222,12 +245,20 @@ def _sanitize_value(value, depth=0):
222245

223246
if not isinstance(value, ALLOWED_TYPES):
224247
logger.warning(f"Disallowed argument type: {type(value)} [corr:{correlation_id}]")
225-
return str(value)[:MAX_STRING_LENGTH]
248+
sanitized_str = str(value)
249+
if max_string_length != -1:
250+
return sanitized_str[:max_string_length]
251+
return sanitized_str
226252

227253
if isinstance(value, str):
228254
# Sanitize string length and remove potential control characters
229255
sanitized = "".join(char for char in value if ord(char) >= 32 or char in "\t\n\r")
230-
return sanitized[:MAX_STRING_LENGTH]
256+
if max_string_length != -1 and len(sanitized) > max_string_length:
257+
logger.debug(
258+
f"String truncated from {len(sanitized)} to {max_string_length} chars [corr:{correlation_id}]"
259+
)
260+
return sanitized[:max_string_length]
261+
return sanitized
231262

232263
elif isinstance(value, list):
233264
if len(value) > 100: # Limit array size
@@ -296,7 +327,10 @@ async def _execute_with_state_management(self, handler, task, function_name: str
296327

297328
async def _apply_ai_middleware(self, handler, function_name: str):
298329
try:
299-
from agent.middleware import execute_ai_function_with_middleware, get_ai_compatible_middleware
330+
from agent.middleware import (
331+
execute_ai_function_with_middleware,
332+
get_ai_compatible_middleware,
333+
)
300334

301335
# Check if there's any AI-compatible middleware to apply
302336
ai_middleware = get_ai_compatible_middleware()

src/agent/templates/config/agentup.yml.j2

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ security:
212212
{% if has_mcp %}
213213
weather:admin: ["alerts:read", "weather:read"]
214214
{% endif %}
215+
216+
# Function argument sanitization settings
217+
sanitization_enabled: {{ sanitization_enabled | default(true) }} # Enable function argument sanitization
218+
max_string_length: {{ max_string_length | default(100000) }} # Max string length in chars (100KB default, -1 = unlimited)
215219
{% endif %}
216220

217221
{%- if ai_provider_config %}

uv.lock

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

0 commit comments

Comments
 (0)