Symaira Vault v1.0.0 is the first stable release. Security reports are accepted for the latest stable 1.x release. Snapshots and local builds are unsupported except where a maintainer explicitly requests reproduction details for a current fix.
| Version | Supported | Notes |
|---|---|---|
| v1.x | ✅ | Latest stable release line |
| Snapshots and local builds | ❌ | Reproduce on the latest stable release before reporting |
We prioritize vulnerability fixes based on impact. Fixes may ship as a patch release, documentation update, or configuration guidance. Unsupported snapshots and local builds do not receive maintenance releases or backports.
We take security vulnerabilities seriously. If you discover a security issue, please report it responsibly.
- Do NOT open a public GitHub issue for security vulnerabilities
- Submit a private vulnerability report via GitHub Security Advisories
- Include the following in your report:
- Description of the vulnerability
- Steps to reproduce the issue
- Potential impact of the vulnerability
- Any suggested fixes (optional)
- Initial Response: Within 48 hours, we will acknowledge receipt of your report
- Status Update: We aim to provide a timeline for when a fix will be available
- Credit: With your permission, we will credit you in the security advisory (if public)
- Disclosure: We follow a coordinated disclosure process
The following are within scope for vulnerability reports:
- Encryption implementation (age X25519 + ChaCha20-Poly1305)
- Passphrase handling and storage
- Session management and keyring integration
- MCP server security (stdio and HTTP modes)
- Vault file format and entry encryption
The following are out of scope:
- Social engineering attacks
- Physical security of the user's machine
- Third-party dependencies (report to their respective maintainers)
No known vulnerabilities at this time.
For historical security advisories, see the Security Advisories page.
Symaira Vault releases publish SHA-256 checksums for downloadable artifacts. To verify a downloaded artifact:
sha256sum --check symaira-vault_VERSION_checksums.txtOn macOS, use shasum -a 256 --check symaira-vault_VERSION_checksums.txt if
sha256sum is not installed.
The symvault update check command queries the GitHub API for the latest release.
All outbound HTTPS connections from the update checker enforce TLS 1.3 as the
minimum protocol version. Connections to servers that do not support TLS 1.3
will be rejected.
TLS certificate verification errors produce a user-friendly error message:
update check failed: TLS certificate verification error - ...
This ensures that:
- Downgrade attacks to TLS 1.2 or earlier are prevented
- Certificate validation failures are clearly communicated
- The update channel cannot be intercepted by malicious endpoints with weak TLS configurations
Ensure your vault directory has appropriate access controls:
# Restrict vault directory access (Unix-like systems)
chmod 700 ~/.symvault
chmod 600 ~/.symvault/identity.ageSymaira Vault exposes vault credentials to LLM agents via the MCP server. That
makes prompt injection (OWASP LLM01, MITRE ATLAS AML.T0051) the primary
threat class for this surface. The full threat model — covering direct and
indirect prompt injection, tool poisoning, sensitive-information disclosure,
path traversal, and excessive agency — lives in
docs/threat-model.md.
Headline defenses:
- Central output chokepoint — every MCP tool response passes through
a three-phase sanitizer (Unicode NFKC, dangerous-Unicode strip, byte-level
ANSI/XML/HTML scrubber) in
internal/mcp/render.gobefore reaching the LLM. Implemented as a single chokepoint so no handler can opt out. - Out-of-band TTY approval for all Critical-tier tools (
set_entry_field,delete_entry,execute_api_request,secure_input,request_credential). The TTY is a separate channel from the MCP transport so a jailbroken agent cannot self-approve. - Sealing for high-classification secrets — agents receive an opaque
op://path/fieldhandle by default and must explicitly callsecret_unseal(with its own approval) to reveal a value. - Compile-time taint system (
internal/vault/taint/, enforced by the custompasslintlinter) —Untrustedvalues cannot be stringified by accident; the type'sFormat()emits<untrusted:Source>instead of content for any%s/%v/%q. - Token-scoped tool & path allowlists, constant-time token comparison, rate-limiting, and audit logging on every call.
- Anomaly detection — desktop notifications for canary access, sweep patterns, request-rate spikes, and off-hours activity.
If you are integrating an agent profile, start from
docs/agent-integration.md (metadata-first
adoption pattern) and review the hermes-safe-adoption.md gates.
- Uses process isolation; no network exposure
- Agent permissions controlled via
approvalModesetting
- Binds to
127.0.0.1only (localhost) — not exposed to network - Bearer token authentication required
- Token auto-generated and stored at
<vault>/mcp-token - Agent identified per-request via
X-Symaira Vault-Agentheader - Max request body size: 1MB (requests exceeding this return 413 Request Entity Too Large)
Security recommendations for HTTP mode:
- Never expose the MCP server port to the network
- Use
approvalMode: denyorapprovalMode: promptfor untrusted agents
The /metrics endpoint exposes Prometheus-format metrics for local monitoring only. This is not outbound telemetry — metrics are served on-request to local monitoring tools and never transmitted to external services.
- On loopback binds (
127.0.0.1,::1,localhost),/metricsis accessible without authentication - On non-loopback binds,
/metricsrequires bearer token authentication by default - This behavior is controlled via the
metrics_auth_requiredconfig option:
mcp:
metrics_auth_required: true # default: require auth on non-loopback bindsSetting metrics_auth_required: false allows anonymous access to /metrics when bound to non-local addresses. Only disable this if you have other access controls (e.g., firewall rules or reverse-proxy auth) in place.
Bearer tokens can be rotated using the mcp-token-rotate command:
symvault mcp-token-rotateThis invalidates the previous token and generates a new one. Any MCP clients using the old token will need to be updated with the new token.
When generating MCP configurations that may be displayed in terminals or committed to version control, use the --redact flag:
symvault mcp-config claude-code --http --redactThis outputs env:SYMVAULT_MCP_TOKEN instead of the actual token value. Clients using redacted configs must set the SYMVAULT_MCP_TOKEN environment variable.
For scripts that need the raw token:
symvault mcp-config <agent> --token-onlyWhen using shared vaults with recipients (multiple people who can decrypt entries), MCP write operations (set_entry_field) preserve multi-recipient encryption. Unlike a plain vault.WriteEntry which only encrypts for the current user, MCP writes use MergeEntryWithRecipients (for updates) or WriteEntryWithRecipients (for new entries) to ensure all configured recipients can continue to decrypt the entry.
This means agents can safely update shared vault entries without breaking access for other recipients.
# ~/.symvault/config.yaml
agents:
# Trusted local agents
claude-code:
allowedPaths: ["*"]
canWrite: true
approvalMode: none
# Untrusted or external agents
external-agent:
allowedPaths: ["public/*", "work/*"]
canWrite: false
approvalMode: denyAgents can be configured to have sensitive fields redacted from get_entry responses using redactFields:
agents:
# Agent that should not see TOTP secrets
readonly-agent:
allowedPaths: ["*"]
canWrite: false
redactFields: ["totp.secret"]When totp.secret is redacted, the agent receives [REDACTED] instead of the actual TOTP seed. The generate_totp tool continues to work normally for generating TOTP codes.
Supported patterns:
"totp.secret"- redacts the TOTP secret field specifically"*"- redacts all fields (use with caution)
Recommendation: For agents that only need TOTP codes, configure redactFields: ["totp.secret"] and use the generate_totp tool instead of get_entry.
Symaira Vault supports optional Touch ID authentication for vault unlock on macOS. When enabled, Touch ID is used instead of typing your passphrase for unlock, while still maintaining secure keyring-cached session storage.
Set the auth method with the CLI:
symvault auth set touchidOr add to your config (~/.symvault/config.yaml or vault config.yaml):
authMethod: touchidLegacy useTouchID: true and vault.useTouchID: true are still accepted for
backward compatibility. Prefer authMethod: touchid for new configs.
You can switch back at any time:
symvault auth set passphrase- Enabling Touch ID validates your passphrase or active session
- The passphrase is stored in a biometric-protected macOS Keychain item
- On subsequent unlocks, Touch ID prompts instead of passphrase
- If Touch ID succeeds, the passphrase is retrieved from Keychain
- If Touch ID fails or is cancelled, interactive CLI commands fall back to a passphrase prompt
- macOS only: Touch ID requires macOS with Touch ID hardware. Non-macOS builds use passphrase-only unlock.
- Keychain dependency: Touch ID authentication accesses the macOS Keychain, which itself may require user password on first Keychain access per session
- Not a replacement for passphrase: The passphrase is still the ultimate factor; Touch ID is a convenience layer accessing the same keyring-cached session
- Biometric availability: Touch ID must be configured and available on the system for
useTouchID: trueto work
- Touch ID provides convenience, not additional cryptographic protection
- The Keychain already requires user authentication to access secrets
- Touch ID allows faster access to the cached session, reducing friction but not weakening security
- Physical access to an unlocked session still bypasses Touch ID (same as passphrase)
- For highest security, use
sessionTimeout: 0to disable session caching entirely
| Variable | Purpose | Security Note |
|---|---|---|
SYMVAULT_VAULT |
Override vault location | Ensure path has proper permissions |
SYMVAULT_PASSPHRASE |
Non-interactive vault unlock | Unset after reading to prevent leakage to child processes |
SYMVAULT_MCP_TOKEN |
Override MCP bearer token (HTTP mode) | Unset after reading to prevent leakage to child processes |
SYMVAULT_AUDIT_MAX_SIZE_MB |
Max audit log file size in MB | Higher values increase disk usage |
SYMVAULT_AUDIT_MAX_BACKUPS |
Number of audit backups to retain | More backups use more disk space |
SYMVAULT_AUDIT_MAX_AGE_DAYS |
Days before audit backups are deleted | Longer retention uses more space |
- Keep backups: Regularly backup your vault directory
- Use strong passphrases: Use
symvault generate --length 32 --symbols - Lock sessions: Use
symvault lockwhen leaving your terminal - Review agent permissions: Only grant
canWrite: trueto trusted agents - Rotate tokens: Periodically rotate MCP bearer tokens in HTTP mode
- Secure your Git repository: If using Git sync, ensure your remote is secure
Symaira Vault uses age for encryption:
- Key Exchange: X25519 (Curve25519 elliptic curve Diffie-Hellman)
- Encryption: ChaCha20-Poly1305 (authenticated encryption)
- Identity File: Encrypted with the identity's own public key, protected by scrypt (passphrase)
Each vault entry is encrypted individually as a standalone .age file, ensuring:
- No compound encryption failures
- Efficient partial access patterns
- Git history contains only ciphertext
Symaira Vault currently uses scrypt (N=262144, r=8, p=1 — work factor 18) for passphrase-based key derivation. While scrypt provides reasonable protection, argon2id is the industry-standard memory-hard KDF (RFC 9106) and provides stronger resistance against GPU/ASIC-based attacks.
| Vault Format | KDF | Work Factor | Doctor Check |
|---|---|---|---|
| v1 (current) | scrypt | 18 | crypto.kdf.modern warns |
| v2 (planned) | argon2id | TBD | crypto.kdf.modern OK |
A future release will provide:
symvault migrate kdfcommand to re-encrypt vault entries with argon2id- Automatic detection of vault format version
- Doctor check
crypto.kdf.modernto track migration status
- Back up your vault before any migration:
cp -r ~/.symvault ~/.symvault.backup
- Run
symvault doctorto check current KDF status - Wait for the migration command to be available in a future release
- Memory-hard: Resistant to GPU, FPGA, and ASIC acceleration
- Side-channel resistant: argon2id mode resists both timing and cache-timing attacks
- Industry standard: Winner of the 2015 Password Hashing Competition (PHC)
- RFC 9106: Standardized by the IETF
- Broader ecosystem: Used by major password managers and security tools
Symaira Vault uses unsafe.Pointer and package-level sink variables to attempt to clear sensitive data (passphrases, decrypted entry contents) from memory after use via crypto.Wipe(). This is a best-effort measure with known limitations:
- Go's runtime may create copies of data that
Wipe()cannot reach (string interning, GC compaction, escape analysis) - The OS may swap memory to disk
- Memory clearing is not guaranteed by the Go language specification
Explicit threat model boundary: Symaira Vault's memory wiping protects against casual recovery of secrets from stale process memory (e.g., reused heap pages). It does not protect against an attacker with memory dump access (core dumps, swap analysis, debugger attachment, or /proc/pid/mem inspection). The crypto.Wipe mechanism raises the bar for post-compromise forensics but is not a defense against a determined local attacker.
A full evaluation of github.com/awnumar/memguard (which provides mlock(2)-backed guarded heap allocations) was performed in ADR 0003. The decision was to keep the zero-dependency best-effort approach because:
- Passphrases exist in memory only briefly during unlock operations
- Adding
memguardwould require refactoring every crypto and vault API - The primary threat for a CLI password manager is local malware, where
Wiperaises the bar sufficiently
The ADR will be revisited if a concrete threat model justifies the complexity cost of guarded memory allocations.
Symaira Vault uses zalando/go-keyring to
cache session passphrases in the OS keyring. The library interface uses Go string
values (keyring.Set(service, user, password string)), which introduces additional
memory copies beyond Symaira Vault's own crypto.Wipe scope:
- macOS: Passphrases are piped via
stdinto/usr/bin/security. The kernel manages the stdin buffer, and the command-line tool may retain the value in its own memory space until the process exits. - Linux / D-Bus: Passphrases are serialized into D-Bus message buffers (Secret Service API). D-Bus is a local IPC bus; message buffers are managed by the D-Bus daemon and may persist in the daemon's memory beyond the library call.
- Windows: Passphrases pass through the Credential Manager API, which may retain data in internal buffers managed by the operating system.
These intermediate copies are created by the OS keyring transport layer and are
outside Go's control — they cannot be reached by crypto.Wipe(). An attacker with
kernel-level memory access, swap analysis, or D-Bus message interception capability
may recover passphrase fragments from these buffers.
Evaluation of go-keyring wipe hooks (May 2026): The go-keyring v0.2.8
library exposes no zeroing or wipe API. Its Keyring interface defines only
Set, Get, Delete, and DeleteAll. The library communicates with OS-native
tools (security, D-Bus, Credential Manager) that manage their own buffers
independently. No amount of Go-level memory zeroing can reach these
OS-managed buffers.
Deployment advisory for high-security environments:
- Enable mlock where supported: On Linux, use
setrlimit(RLIMIT_MEMLOCK)to prevent the process heap from being swapped to disk. This reduces the risk of passphrase data appearing in swap files. Thesymvaultbinary does not callmlockby default; site operators must configure this via systemd or PAM.# systemd service unit [Service] LimitMEMLOCK=infinity MemoryDenyWriteExecute=yes
- Minimize session TTL: Set
sessionTimeout: 0inconfig.yamlto disable session caching entirely. This forces passphrase entry on every operation, eliminating the keyring as a persistence vector. - Use stdio MCP mode: The
symvault serve --stdiomode avoids D-Bus entirely for MCP transport, reducing the keyring's attack surface to the unlock path. - Prefer passphrase-only unlock: Set
authMethod: passphraseto avoid biometric keychain items that may have different access control properties.
Symaira Vault does NOT collect any product analytics, error reports, or usage telemetry.
As a password manager handling highly sensitive credentials, we believe telemetry would create unacceptable privacy and security risks:
- No external telemetry services: We don't use Sentry, Datadog, Crashlytics, or similar services
- No in-app analytics: We don't track user behavior, command usage, or feature adoption
- No error reporting services: User errors stay local; no data exfiltration to third parties
- No network phoning home: Symaira Vault operates entirely offline after installation
- Local metrics only: The
/metricsendpoint serves Prometheus metrics locally on request; no metrics are pushed or transmitted to external services
All data remains on your device:
- Vault contents: Your passwords, TOTP secrets, and notes are never transmitted
- Audit logs: Stored locally in
~/.symvault/audit-*.logwith rotation and retention limits - Error information: Diagnostic commands like
symvault --versionandsymvault liststay on your machine - Session data: Cached via OS keyring, never transmitted
Symaira Vault maintains local audit logs for MCP tool calls (see internal/audit/audit.go). These logs:
- Are stored in
~/.symvault/audit-<agent>.log - Rotate when they exceed 100MB per file or 30 days old
- Are retained up to 5 backup files before oldest are pruned
- Contain only action metadata, no field values or secrets
Audit log rotation is configurable via environment variables:
| Variable | Default | Description |
|---|---|---|
SYMVAULT_AUDIT_MAX_SIZE_MB |
100 | Max size in MB per audit log file before rotation |
SYMVAULT_AUDIT_MAX_BACKUPS |
5 | Number of rotated backup files to retain |
SYMVAULT_AUDIT_MAX_AGE_DAYS |
30 | Max age in days before rotated files are deleted |
Symaira Vault is GDPR-compliant by design:
- No personal data is collected
- No data is processed by third parties
- No consent dialogs required for telemetry (because there is no telemetry)
For more details on error tracking strategy, see docs/error-tracking-strategy.md.
- GitHub Security Advisories: https://github.com/danieljustus/symaira-vault/security/advisories/new
- Public Security Advisories: https://github.com/danieljustus/symaira-vault/security/advisories
For non-security issues, please use the public issue tracker.