-
Notifications
You must be signed in to change notification settings - Fork 7
Security
Security features and best practices for Memory Journal MCP Server.
Memory Journal is local-first:
- All data stored locally in SQLite
- No external API calls
- No telemetry or analytics
- You own and control your data
MAX_CONTENT_SIZE = 50 * 1024 # 50KB per entry
MAX_TAG_LENGTH = 100 # 100 characters per tagWhy limits:
- Prevent resource exhaustion
- Ensure reasonable performance
- Protect database integrity
All queries use parameterized statements:
# Safe - parameterized query
conn.execute(
"INSERT INTO memory_journal (content) VALUES (?)",
(user_content,)
)
# NEVER do this (vulnerable to SQL injection)
conn.execute(f"INSERT INTO memory_journal (content) VALUES ('{user_content}')")Benefits:
- SQL injection impossible
- Safe handling of quotes and special characters
- Database-level validation
# Create non-root user
RUN addgroup -g 1000 appuser && \
adduser -D -u 1000 -G appuser appuser
# Switch to non-root user
USER appuserBenefits:
- Container cannot modify host system
- Reduced attack surface
- Follows least privilege principle
FROM python:3.11-alpineAlpine Linux benefits:
- Small attack surface (~5MB base)
- Security-focused distribution
- Fewer vulnerabilities
- Fast updates
{
"command": "docker",
"args": [
"run", "--rm", "-i",
// NO --privileged flag
// NO --cap-add flags
"-v", "./data:/app/data",
"writenotenow/memory-journal-mcp:latest"
]
}{
"args": [
"-v", "./data:/app/data:rw", // Only data directory
// NOT: "-v", "/:/host" - would expose entire host
]
}Best practices:
- Mount only necessary directories
- Use read-only mounts where possible
- Avoid mounting sensitive host directories
Recommended (highest security):
# Use SHA-256 digest for immutable reference
docker pull writenotenow/memory-journal-mcp@sha256:abc123...
# Find SHA digests at:
# https://hub.docker.com/r/writenotenow/memory-journal-mcp/tagsBenefits:
- Immutable image reference
- Protection against tag hijacking
- Reproducible deployments
- Supply chain verification
Tag-based (convenience):
docker pull writenotenow/memory-journal-mcp:latestPRAGMA journal_mode = WAL; # Write-Ahead Logging
PRAGMA synchronous = NORMAL; # Balance safety/speedBenefits:
- Crash recovery
- Data integrity
- Concurrent access safety
FOREIGN KEY (entry_id) REFERENCES memory_journal(id) ON DELETE CASCADEBenefits:
- Referential integrity
- Automatic cleanup
- Prevents orphaned records
with db.get_connection() as conn:
# All or nothing
conn.execute("INSERT ...")
conn.execute("UPDATE ...")
# Auto-commit on success
# Auto-rollback on errorBenefits:
- ACID compliance
- Data consistency
- Error recovery
No network access:
- No cloud storage
- No API calls (except Git/GitHub CLI)
- No user tracking
- No analytics
Data location:
- PyPI:
~/.memory-journal/memory_journal.db - Docker:
./data/memory_journal.db(volume mount)
Optional and transparent:
create_entry({
content: "...",
auto_context: false // Disable Git integration
})Git operations:
- Read-only (no commits)
- Local repository info only
- Optional GitHub CLI (user-controlled)
Data captured:
- Repository name and path
- Current branch
- Latest commit
- GitHub issues (if
ghCLI installed)
Not captured:
- File contents
- Uncommitted changes
- Remote repository data
- Credentials
# Soft delete (default)
delete_entry({ entry_id: 42, permanent: false })
# Sets deleted_at timestamp, entry remains in DB
# Permanent delete (explicit)
delete_entry({ entry_id: 42, permanent: true })
# Removes from database completelyBenefits:
- Accidental deletion recovery
- Audit trail
- No data loss
Soft-deleted entries:
- Excluded from searches
- Not visible in lists
- Still in database (for recovery)
Security handled by MCP client:
- Cursor IDE: Desktop app security
- Claude Desktop: Desktop app security
- User controls which servers run
PyPI installation:
# Database created with user permissions
chmod 600 ~/.memory-journal/memory_journal.dbDocker installation:
# Volume mount with appropriate permissions
mkdir -m 755 dataDocker environment variables:
{
"args": [
"-e", "DB_PATH=/app/data/custom.db",
// NO sensitive data in env vars
// NO API keys
// NO credentials
]
}No secrets required:
- No API keys
- No passwords
- No tokens
- Optional: GitHub CLI (user manages
gh auth)
1. Regular backups:
# Backup database
cp ./data/memory_journal.db ./backups/journal-$(date +%Y%m%d).db2. Docker image verification:
# Verify SHA digest
docker images --digests | grep memory-journal
# Use SHA-pinned images
docker pull writenotenow/memory-journal-mcp@sha256:...3. Limit Docker access:
{
"args": [
"-v", "./data:/app/data", // Only mount data dir
"--read-only", // Read-only root filesystem
"--tmpfs", "/tmp" // Writable tmp
]
}4. Review logs:
# Check for errors
docker logs <container_id>1. Input validation:
if len(content) > MAX_CONTENT_SIZE:
raise ValueError(f"Content too large: {len(content)} > {MAX_CONTENT_SIZE}")2. Parameterized queries:
# Always use ? placeholders
conn.execute("SELECT * FROM memory_journal WHERE id = ?", (entry_id,))3. Error handling:
try:
# Operation
except Exception as e:
# Log, don't expose internals to user
logger.error(f"Internal error: {e}")
return "Operation failed"4. Least privilege:
# Don't request unnecessary permissions
# Don't access unnecessary files
# Don't make unnecessary network callsFound a security issue?
- Do NOT open a public GitHub issue
- Email: security@example.com (use your actual security contact)
- Include:
- Description of vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
We will:
- Acknowledge within 48 hours
- Provide fix timeline
- Credit you (if desired)
- Publish security advisory
- ✅ Input validation (size limits)
- ✅ SQL injection prevention (parameterized queries)
- ✅ No credentials in code
- ✅ Non-root Docker execution
- ✅ Minimal base image (Alpine)
- ✅ No unnecessary privileges
- ✅ Local-only data storage
- ✅ Transaction safety (ACID)
- ✅ Error handling
- ✅ Soft delete option
Protected against:
- SQL injection
- Resource exhaustion (size limits)
- Accidental data loss (soft delete)
- Database corruption (WAL, transactions)
- Container escape (non-root, no privileges)
Not protected against:
- Malicious MCP client
- Compromised host system
- Physical access to database file
- User deleting database file
Why:
- Local-first design trusts the host
- User has full control
- Desktop application security model
GDPR-friendly:
- No data collection
- No data transmission
- Local storage only
- User controls all data
- Easy data export/deletion
No PII collection:
- No names
- No email addresses
- No tracking
- No analytics
PyPI:
# Update to latest version
pip install --upgrade memory-journal-mcpDocker:
# Pull latest image
docker pull writenotenow/memory-journal-mcp:latest
# Or specific SHA
docker pull writenotenow/memory-journal-mcp@sha256:...Monitor:
- GitHub releases
- Docker Hub updates
- Security advisories
Next: Check Architecture or Performance.