- Please email security@anchormarks.app (or open a private security advisory on GitHub) with a clear description, reproduction steps, and potential impact.
- Do not create public issues for vulnerabilities until a fix is available.
- We aim to acknowledge reports within 3 business days and provide a remediation plan or fix within 14 days when feasible.
We currently support security fixes on the latest main branch and the most recent tagged release.
- Avoid automated scans against production deployments without consent.
- Do not attempt to access another user's data.
- Credit will be given in release notes if desired.
Developer reference: the authentication and CSRF protection flow is documented in the in-app help page under “Developer: Auth & CSRF”:
help.html#developer-auth-csrf
AnchorMarks implements the following security measures:
- Password hashing using bcrypt with appropriate cost factor
- JWT-based session authentication with HTTP-only cookies
- CSRF token validation for state-changing operations
- API key authentication for programmatic access
- All database queries include user_id filtering for data isolation
- App-specific cookie names: Cookies are prefixed with a deployment-specific identifier (derived from
JWT_SECRET) to prevent authentication conflicts when multiple applications share the same domain. This ensures that logging into one app doesn't interfere with sessions in another app on the same domain.
- Request body size limits (10MB max)
- URL validation before processing
- SQL injection prevention via parameterized queries (better-sqlite3)
- Helmet.js for security headers (CSP, X-Frame-Options, etc.)
- CORS configuration with credentials support
- SSRF protection: private/loopback IP blocking in production for favicon/metadata fetching
- Rate limiting on API endpoints
- Multi-tenant architecture with strict user data isolation
- No bookmark sharing between users
- No user-uploadable file storage
- Helmet.js security headers
- CSRF protection on mutations
- Rate limiting
- SSRF protection for outbound requests
- Parameterized SQL queries
- User data isolation
- No file upload functionality
- Content-Type enforcement on static assets
- Subresource Integrity (SRI) infrastructure (see below)
- Security audit logging (see below)
Current Status: ✅ All scripts and stylesheets are self-hosted. No external CDN dependencies.
If you need to add external scripts or stylesheets from CDNs, use the SRI helper:
# Generate SRI hash for a URL
node apps/server/helpers/sri.js generate https://cdn.example.com/lib.js
# Output example:
# sha384-abc123...Then add the integrity and crossorigin attributes:
<script
src="https://cdn.example.com/lib.js"
integrity="sha384-abc123..."
crossorigin="anonymous"
></script>For stylesheets:
<link
rel="stylesheet"
href="https://cdn.example.com/style.css"
integrity="sha384-xyz789..."
crossorigin="anonymous"
/>AnchorMarks includes a comprehensive security audit logging system that tracks security-relevant events.
| Event Type | Severity | Description |
|---|---|---|
AUTH_LOGIN_SUCCESS |
INFO | Successful user login |
AUTH_LOGIN_FAILURE |
WARNING | Failed login attempt (wrong password or user not found) |
AUTH_LOGOUT |
INFO | User logout |
AUTH_REGISTER |
INFO | New user registration |
AUTH_PASSWORD_CHANGE |
INFO | Password successfully changed |
AUTH_API_KEY_REGENERATE |
WARNING | API key was regenerated |
ACCESS_DENIED |
WARNING | Authorization failure |
RATE_LIMIT_EXCEEDED |
WARNING | Rate limit triggered |
CSRF_VALIDATION_FAILURE |
CRITICAL | CSRF token validation failed |
SUSPICIOUS_ACTIVITY |
CRITICAL | Potentially malicious behavior detected |
Each log entry includes:
- Timestamp
- Event type and severity
- User ID (if authenticated)
- Client IP address
- User agent
- Endpoint and HTTP method
- Additional context details (sanitized, no passwords/tokens)
- Retention period: Audit entries (database and file) are retained for a configurable number of days (default 90 days). Older entries are removed by a daily retention job.
- What is rotated:
- Database: Rows in
security_audit_logolder than the retention period are deleted. - File logs: When file logging is enabled, logs are written to date-based files (
security-audit-YYYY-MM-DD.log). Files older than the retention period are deleted by the same daily job.
- Database: Rows in
- Schedule: Retention cleanup runs once per day (time is server-dependent; typically shortly after process start and then every 24 hours).
- Compliance: If you need longer retention for CRITICAL events or compliance (e.g. 1 year), increase
SECURITY_LOG_RETENTION_DAYSor retain exports/backups of the audit log outside the application.
Environment variables:
# Enable file logging (in addition to database). Logs are written to date-based files and rotated by retention.
SECURITY_LOG_FILE=true
# Audit log retention period in days (default: 90). Database rows and log files older than this are removed daily.
SECURITY_LOG_RETENTION_DAYS=90The audit logs are stored in the security_audit_log table. Example queries:
-- Recent failed login attempts
SELECT * FROM security_audit_log
WHERE event_type = 'AUTH_LOGIN_FAILURE'
ORDER BY timestamp DESC LIMIT 50;
-- Security events by user
SELECT * FROM security_audit_log
WHERE user_id = 'user-uuid-here'
ORDER BY timestamp DESC;
-- Critical events in last 24 hours
SELECT * FROM security_audit_log
WHERE severity = 'CRITICAL'
AND timestamp > datetime('now', '-24 hours');