v0.2.5
Release Notes for v0.2.5
This release is a major security hardening pass across the API, CLI, and Web UI: path-traversal fixes wherever agent_id/session_id/dates flow into filesystem paths, a CORS credential-exposure fix, localhost-only gating for destructive UI endpoints, unpredictable session-secret generation, stricter session-token validation, and a large cleanup that collapses the legacy scope/namespace model down to a single agent_id.
Security
-
Path traversal via
agent_id/session_id/ dates (memanto/app/utils/validation.py,
memanto/app/services/{session_service,memory_export_service,daily_analysis_service}.py)- Unsanitized
agent_id/session_idvalues were concatenated directly into
pathlib.Pathexpressions (e.g.sessions_dir / f"{agent_id}.json"),
letting a caller escape the storage directory with input like
"../../etc/passwd". All filesystem call-sites now run through
validate_safe_id(). - Extended the same guard to
memory_export_service,daily_analysis_service
(including the date parameter used in glob patterns and JSON output paths),
and the--output-pathCLI flag (anchored to a base dir viarelative_to()
containment checks).
- Unsanitized
-
CORS reflected-origin credential exposure (
memanto/app/main.py)- Default
ALLOWED_ORIGINS=["*"]combined withallow_credentials=True
caused Starlette to mirror any requestOriginback in
Access-Control-Allow-Originwhile also sending
Access-Control-Allow-Credentials: true— letting any website make
credentialed cross-origin requests to the Memanto API. Fixed to stop
mirroring arbitrary origins when credentials are allowed.
- Default
-
Sensitive Web UI endpoints gated to localhost-only (
memanto/app/ui/routes/ui_router.py)POST /api/ui/shutdown,GET /api/ui/browse,PATCH /api/ui/config,
PUT /api/ui/api-key,POST /api/ui/onprem/restart, plus the
connections and migrate endpoints, were reachable from any network host
with no authentication (remote DoS, arbitrary file listing, config/API-key
overwrite). Added a_require_local()dependency that returns 403 for any
caller that isn't127.0.0.1/::1(including IPv4-mapped IPv6 loopback),
and blocked glob-pattern injection in the browse endpoint.
-
Unpredictable session secret (
memanto/app/config.py,memanto/app/services/session_service.py)- Removed the hardcoded default JWT signing secret
("memanto-default-secret-change-in-production"). When
MEMANTO_SECRET_KEYisn't set, a per-instance random secret is now
generated (secrets.token_hex(32)) and persisted locally instead of
falling back to a publicly-known constant.
- Removed the hardcoded default JWT signing secret
-
Session token lifecycle hardening (
memanto/app/services/session_service.py,
memanto/app/routes/memory.py,memanto/cli/client/{direct_client,sdk_client}.py)- Deactivated/terminated session tokens are now rejected outright (401)
instead of continuing to authorize writes. - Cross-agent session/agent mismatches now consistently raise
AuthorizationError→ HTTP 403 (was a generic 500) across all
session-scoped endpoints. - CLI clients now validate cached sessions before reuse instead of trusting
a stale cached token. - TypeScript SDK resets its local session state after
deleteAgent().
- Deactivated/terminated session tokens are now rejected outright (401)
Improvements
-
Legacy scope model collapsed to
agent_id(memanto/app/core.py,
memanto/app/models/__init__.py,memanto/app/constants.py,
memanto/app/services/*.py)- Removed the
scope_type/scope_idpair (and the underlying
MemoryScope/namespace-parsing machinery) in favor of a singleagent_id
field; namespaces are now built by one free function
(agent_namespace(agent_id)). Dead code from this and prior cleanups moved
tomemanto/app/legacy/(excluded from CI lint/type-check). - Removed orphaned "trust" fields that were never populated by any live
write/read path (superseded_by,validation_count,
contradiction_detected, etc.) and the unusedValidationPolicyclass.
- Removed the
-
Confidence filtering bug fix (
memanto/app/services/memory_read_service.py)- Numeric
min_confidencefiltering in memory search previously relied on
Moorcheh keyword syntax that never matched; it's now applied as a
post-filter on the numericconfidencefield, fixing a zero-threshold
edge case that silently returned nothing.
- Numeric
-
Manual conflict resolution validation (
memanto/app/models/__init__.py)ConflictResolveRequestnow requires non-emptymanual_contentwhen
action == "manual", both on the API and in the UI (blank submissions show
a warning toast and refocus the textarea).
-
Timestamp normalization (
memanto/app/utils/temporal_helpers.py)- Parsed ISO timestamps are now consistently normalized to UTC, whether the
input has an explicit offset or is naive.
- Parsed ISO timestamps are now consistently normalized to UTC, whether the
-
CLI: honor custom title for short memories (
memanto/cli/commands/memory.py)memanto rememberno longer overrides an explicit--titlewith an
auto-truncated content snippet when the memory content is short.
-
Memory deletion response handling (
memanto/app/services/memory_write_service.py)- Tightened success/failure detection for memory deletion and update-then-delete
flows so partial or malformed backend responses aren't reported as success.
- Tightened success/failure detection for memory deletion and update-then-delete
-
TypeScript SDK & CI — updated dependencies, CI workflow permissions,
regeneratedopenapi.json, and added an npm publishing workflow
(.github/workflows/publish.yml).
Tests
- New
tests/test_cors_fix.py,tests/test_output_path_traversal.py,
tests/test_ui_auth.py,tests/test_remaining_ui_auth.pycovering the CORS,
path-traversal, and localhost-gating fixes. - New
tests/test_memory_read_confidence.pyandtests/test_temporal_helpers.py. - Expanded
tests/test_api.py,tests/test_cli.py,tests/test_unit.pyfor
session-secret generation, inactive-token rejection, and deletion handling.
Full Changelog
Full Changelog: v0.2.4...v0.2.5