Obsidian VaultGuard - Security Model
This document describes the security architecture, threat model, and compliance posture of Obsidian VaultGuard. It is intended for security engineers, compliance reviewers, and technical decision-makers evaluating the system.
⚠️ Status: historical / narrative — superseded for current claims by docs/SECURITY.md. This document is retained as a deep architectural narrative. Where it conflicts with
docs/SECURITY.md, the source code, or the tests, those win. It was reconciled against the implementation on 2026-07-10 (security audit SD-01); several controls that described target/aspirational architecture rather than the current build have been corrected or removed. Verify any specific control against source before relying on it in an external commitment.
Table of Contents
- Threat Model
- Encryption Architecture
- Key Management Lifecycle
- The Offboarding Flow
- Device Access Analysis
- Comparison with Alternatives
- Compliance Considerations
- Known Limitations and Residual Risks
- Defense-in-Depth Recommendations
Threat Model
What We Protect Against
| Threat | Mitigation | Residual Risk |
|---|---|---|
| Unauthorized file access | Per-path permission rules, enforced server-side | Admin misconfiguration |
| Ex-employee data retention | Revocation flow with key rotation and cache destruction | Data copied before revocation (see Limitations) |
| Credential theft | Short-lived tokens, MFA, session binding | Token theft during valid session window |
| Man-in-the-middle | TLS 1.3 (standard certificate validation) | Compromised CA (extremely rare) |
| Server-side breach | Envelope encryption -- AWS cannot read content | Compromised KMS master key (AWS-managed) |
| Insider threat (admin) | Audit logging of all admin actions, no raw file access via API | Colluding admins |
| Device theft/loss | At-rest encryption of every vault file on disk (AES-256-GCM, key wrapped by OS keychain), recovery code for cross-device restore, remote wipe signal | Unlocked device at moment of theft; the running Obsidian process holds decrypted content in memory |
| Brute force attacks | Cognito lockout policy, rate limiting, alert on failures | Distributed attacks below threshold |
| Data exfiltration | Audit log monitoring, no bulk download API | Slow exfiltration via normal access patterns |
| Supply chain attack | Plugin code signing, integrity verification | Compromised build pipeline |
Actors Considered
- External attacker -- No credentials, network-level access only
- Disgruntled employee -- Valid credentials, attempting data theft before departure
- Ex-employee -- Previously valid credentials, attempting access after offboarding
- Curious insider -- Valid credentials, attempting to access files beyond their role
- Compromised admin -- Full admin access, attempting to extract all data
- AWS insider -- Access to infrastructure but not encryption keys (envelope encryption prevents this)
Encryption Architecture
Encryption at Rest
+-------------------+
| AWS KMS |
| Master Key (CMK) |
+--------+----------+
|
Encrypts/Decrypts
|
+--------v----------+
| Data Encryption |
| Key (DEK) |
| Per-file unique |
+--------+----------+
|
Encrypts/Decrypts
|
+--------v----------+
| File Content |
| (S3 object) |
+-------------------+
Algorithm: AES-256-GCM (authenticated encryption)
Envelope encryption flow:
- For each file, a unique Data Encryption Key (DEK) is generated
- The DEK encrypts the file content (client-side)
- The DEK itself is encrypted using the KMS Customer Master Key (CMK)
- Both the encrypted file and encrypted DEK are stored in S3
- To read: retrieve encrypted DEK -> call KMS to decrypt DEK -> use DEK to decrypt file
Client-side encryption:
- File content is encrypted in the Obsidian plugin BEFORE transmission
- The backend never sees plaintext file content
- Even if S3 is breached, data is unreadable without KMS access
- File metadata (path, size, timestamps) is stored in DynamoDB and is NOT client-encrypted (needed for server-side permission checks)
Encryption in Transit
| Connection | Protocol | Notes |
|---|---|---|
| Plugin to API Gateway | TLS 1.3 | Standard TLS certificate validation (no additional pinning) |
| API Gateway to Lambda | AWS internal (encrypted) | Never leaves AWS network |
| Lambda to S3 | TLS 1.2+ via AWS SDK | Public AWS service endpoint over TLS (Lambdas are not VPC-attached) |
| Lambda to DynamoDB | TLS 1.2+ via AWS SDK | Public AWS service endpoint over TLS |
| Lambda to KMS | TLS 1.2+ via AWS SDK | Public AWS service endpoint over TLS |
Local At-Rest Encryption
Canonical reference: docs/AT-REST-ENCRYPTION.md. Read that for the file format, key hierarchy, recovery model, and threat-model details. The summary here is intentionally brief.
VaultGuard encrypts every vault file in place on the user's local
disk — opening the vault folder in Finder / Explorer / Spotlight shows
ciphertext, not notes. There is no separate "cache" file; the user's
own .md, attachments, etc. are written as AES-256-GCM ciphertext
inside the same paths Obsidian expects.
- Cipher: AES-256-GCM, fresh 12-byte nonce per write, magic header
VG1\0lets the cipher distinguish encrypted-on-disk from legacy plaintext (enabling lazy migration). - Local At-rest Key (LAK): 32 random bytes generated on first
plugin load on each device. Stored at
.obsidian/plugins/vaultguard/lak.envelopewrapped by ElectronsafeStorage(OS keychain — macOS Keychain / Windows DPAPI / Linux libsecret). Never sent to the server; never shared between users or devices. - Fallback: if
safeStorageis unavailable, the LAK is wrapped by a per-device key in Electron's localStorage. Defeats raw filesystem inspection but a full Electron-profile theft can recover the LAK; the settings UI surfaces a warning badge in this state. - Recovery: user-printed code (
VG1-XXXX-...-XXXX, hex with SHA-256 checksum) gated behind a Cognito password re-auth on export. See § Org recovery vs at-rest recovery for the detailed comparison with the admin-side recovery flow. - Excluded paths:
.obsidian/,.trash/, and the user's sync exclusion list. Obsidian reads its own config / plugin code before our plugin loads, so encrypting any of these would brick the install.
This layer is independent of the cloud-side envelope encryption
described above. The LAK never participates in sync; the cloud lease
key never touches local-disk files. Mixing them up is the most common
source of confusion in support — see the explicit two-layer diagram
in docs/AT-REST-ENCRYPTION.md.
Key Management Lifecycle
Key Hierarchy
Level 0: AWS KMS CMK (Customer Master Key)
|-- Managed by AWS, never leaves HSM
|-- Auto-rotated annually
|-- Access controlled by KMS key policy
|
Level 1: Organization Key (encrypted by CMK)
|-- Generated on org creation
|-- Used to encrypt per-user keys
|-- Rotated on admin request or security event
|
Level 2: Per-User Key (encrypted by Org Key)
|-- Generated on user creation
|-- Used to encrypt file DEKs for that user's access
|-- Destroyed on revocation
|
Level 3: Per-File DEK (encrypted by User Key)
|-- Generated on file creation/update
|-- Unique per file version
|-- Re-encrypted with new User Key on key rotation
────────────────────────────────────────────────────────────────────
Local-only key (does not participate in cloud sync)
────────────────────────────────────────────────────────────────────
Level L: Local At-rest Key (LAK)
|-- 32-byte AES key generated locally on first plugin load
|-- Wrapped by Electron safeStorage (OS keychain) per device
|-- Encrypts the user's vault files on local disk
|-- Recoverable via user-printed code; never shared, never escrowed
|-- See docs/AT-REST-ENCRYPTION.md for the full key hierarchy
Key Rotation
| Event | Keys Rotated | Impact |
|---|---|---|
| Annual auto-rotation | CMK | Transparent, no user impact |
| User offboarding | User Key + all their DEKs | User loses access, files re-encrypted |
| Security incident | Org Key + all User Keys + DEKs | Full re-encryption, all users re-auth |
| Admin request | Selected User Keys | Targeted re-encryption |
| Password change | User's device key | Local cache re-encrypted |
Key Destruction
When a key is destroyed:
- KMS
ScheduleKeyDeletionwith 7-day waiting period (minimum required by AWS) - Immediate: key is disabled, cannot be used for new operations
- After waiting period: key material is permanently deleted
- All data encrypted with that key becomes permanently unreadable
The Offboarding Flow
When an admin revokes a user's access, the following sequence executes:
Timeline
T+0s: Admin clicks "Revoke Access" and confirms
T+0.1s: API receives revocation request
T+0.5s: Cognito: All refresh tokens invalidated
T+0.5s: Cognito: User disabled (no new logins)
T+1s: DynamoDB: User status set to "revoked"
T+1s: DynamoDB: All active sessions marked invalid
T+2s: Lambda: Key rotation triggered for affected files
T+2s: Revocation flag set server-side (clients detect it on their next poll / lease refresh / heartbeat — VaultGuard does not use WebSocket push)
T+5s: Plugin (if online): Receives revoke signal
T+5s: Plugin: Clears local cache (secure wipe)
T+5s: Plugin: Deletes stored credentials
T+5s: Plugin: Shows "Access Revoked" screen
T+30s: Maximum time for offline clients to receive signal on next sync attempt
T+30s: Any API call with old token returns 401 -> triggers local wipe
T+5min: Key rotation complete for all affected files
T+7days: Old user keys scheduled for permanent deletion via KMS
What Happens to Shared Files
- Files the revoked user had access to are re-encrypted with new DEKs
- Other users with access to those files receive new DEKs transparently
- The revoked user's old DEKs become useless once their User Key is destroyed
- File history/versions encrypted with old keys remain accessible to authorized users (keys are re-wrapped, not re-encrypted for history)
Edge Cases
| Scenario | Handling |
|---|---|
| User offline at revocation time | Revoke signal queued; on next sync attempt, 401 triggers local wipe |
| User has uncommitted local changes | Changes are lost (by design -- security over data) |
| User was mid-sync during revocation | Partial sync is rolled back server-side |
| User has multiple devices | All devices receive independent revoke signals |
| User re-invited after revocation | New user identity, new keys, no access to old encrypted data |
Device Access Analysis
What an Attacker WITH Device Access CAN Do
Assuming attacker has physical access to an unlocked device with an active VaultGuard session:
| Action | Possible? | Conditions |
|---|---|---|
| Read currently synced files | YES | If vault is unlocked and session active |
| Read files NOT synced locally | NO | Server enforces permissions per request |
| Read files user lacks permission for | NO | Server-side enforcement |
| Export/copy visible files | YES | Standard OS clipboard/file copy |
| Take screenshots of content | YES | Cannot be prevented by application |
| Access files after session expires | NO | Cache encrypted, key cleared on lock |
| Modify permissions | NO | Requires admin role + MFA confirmation |
| Access other users' files | NO | Per-user encryption keys |
| Extract encryption keys from memory | YES* | Requires memory forensics tools (see Limitations) |
| Intercept future file syncs | NO | Requires the device's local session envelope + keys |
What an Attacker WITH Device Access CANNOT Do
Even with full disk access to a device (powered off or locked):
| Action | Why Not |
|---|---|
| Read cached vault data | Encrypted with device-bound key (cleared on lock) |
| Extract usable auth tokens | Tokens stored in encrypted keychain/credential store |
| Decrypt files without the device's key | At-rest key is wrapped by the OS keychain (or, if the optional PIN is enabled, a PBKDF2-derived key) |
| Access backend API | Tokens expired / server-side session invalidated |
| Replay captured network traffic | TLS 1.3, forward secrecy |
| Clone session to another device | Local session envelope is device-keyed (OS-keychain-wrapped) |
Comparison with Alternatives
| Feature | Obsidian VaultGuard | Obsidian Sync (Standard) | Notion | Confluence | Google Docs |
|---|---|---|---|---|---|
| Client-side encryption | Yes (E2E) | Yes (optional) | No | No | No |
| Per-file permissions | Yes | No | Yes (pages) | Yes (spaces) | Yes (files) |
| Permission inheritance | Yes (folder tree) | N/A | Limited | Yes | Limited |
| Audit logging | Full (every access) | No | Paid tier | Yes | Yes (admin) |
| Instant revocation | Yes (< 30s) | No mechanism | Yes (minutes) | Yes (minutes) | Yes (minutes) |
| Local cache destruction | Yes (on revoke) | No | N/A (web) | N/A (web) | N/A (web) |
| Offline access | Yes (encrypted cache) | Yes | Limited | No | No |
| Key rotation on offboarding | Yes (automatic) | N/A | N/A | N/A | N/A |
| Custom deployment | Yes (your AWS) | No (Obsidian servers) | No | Yes (Data Center) | No |
| Data residency control | Yes (choose region) | No | Limited | Yes (DC) | Limited |
| SSO/SAML | Yes | No | Yes (Business) | Yes | Yes |
| MFA | Yes (TOTP) | No | Yes | Yes | Yes |
| Open source | Yes | No | No | No | No |
| Self-hosted option | Yes (required) | No | No | Yes | No |
When to Choose VaultGuard Over Alternatives
- You need per-folder access control within a shared vault
- Compliance requires data residency in a specific AWS region
- You need provable instant access revocation (key destruction, not just session invalidation)
- You need audit trails for every file read (not just writes)
- Your team prefers Obsidian's local-first markdown workflow
- You need to prove that the hosting provider cannot read your data
Compliance Considerations
SOC 2 Type II
| Trust Service Criteria | VaultGuard Coverage |
|---|---|
| CC6.1 Logical access security | Cognito authentication, per-path authorization, MFA |
| CC6.2 User registration/deregistration | Admin-controlled invite flow, instant revocation |
| CC6.3 Role-based access | Role system (admin, editor, viewer) + custom rules |
| CC6.6 Encryption of data in transit | TLS 1.3 |
| CC6.7 Encryption of data at rest | AES-256-GCM, envelope encryption via KMS |
| CC7.1 Detection of unauthorized changes | File integrity hashing, audit log, version history |
| CC7.2 Monitoring | CloudWatch alerts, anomaly detection |
| CC8.1 Change management | Terraform infrastructure-as-code, deployment audit trail |
| A1.2 Recovery | S3 versioning, DynamoDB PITR |
Gap: SOC 2 audit requires a formal assessment by a CPA firm. VaultGuard provides the technical controls but you must engage an auditor for certification.
GDPR
| Requirement | Implementation |
|---|---|
| Lawful basis | Legitimate interest (employer-managed tool) or consent |
| Data minimization | Only store file content + minimal metadata |
| Right to access | Export API for user's own data |
| Right to erasure | User deletion removes all personal data + encrypted content |
| Data portability | Standard markdown format, exportable |
| Data breach notification | Monitoring + alerting can support legally required notification workflows |
| DPA with processor | AWS DPA covers infrastructure; you are the controller |
| Cross-border transfer | Deploy in an EU region and configure replication/subprocessors to match residency requirements |
| Privacy by design | Encryption, minimal logging of personal data |
GDPR-specific configuration:
- Set deployment region to
eu-west-1(Ireland) oreu-central-1(Frankfurt) - Keep data in the single deployed region — VaultGuard does not replicate cross-region
- Configure audit log to NOT store IP addresses (optional GDPR-strict mode)
- Set data retention policy in org settings
HIPAA
VaultGuard can support HIPAA compliance with additional configuration:
- Sign a BAA with AWS (required)
- Enable AWS CloudTrail for all KMS operations
- Set audit log retention to minimum 6 years
- Enable automatic session termination after 15 minutes
- Disable any file-content-based search features (PHI in search indexes)
- Document in your HIPAA policies that Obsidian markdown files may contain PHI
Note: HIPAA compliance is a shared responsibility. VaultGuard provides technical safeguards; administrative and physical safeguards must be implemented by your organization.
Known Limitations and Residual Risks
Cannot Prevent
| Risk | Explanation | Mitigation |
|---|---|---|
| RAM extraction | An attacker with physical access to an unlocked, running machine can dump process memory to extract decryption keys | Auto-lock timeout, full-disk encryption, device security policies |
| Screenshots | Standard OS screenshot tools capture any displayed content | DLP software, watermarking (not implemented), security training |
| Copy/paste exfiltration | User can copy content to clipboard and paste elsewhere | DLP software, monitoring, acceptable use policy |
| Shoulder surfing | Physical observation of screen content | Privacy screens, awareness training |
| Pre-revocation data copying | A user who knows they will be offboarded can copy files before revocation | Immediate revocation policy, access monitoring for anomalies |
| Metadata leakage | File paths, sizes, and access timestamps are visible to the backend | File paths may reveal project names; consider path obfuscation for sensitive projects |
| Compromised client | Malware on user's device can capture decrypted content | Endpoint security, device compliance checks (MDM integration) |
| Social engineering | Attacker convinces admin to grant access or reset credentials | Admin MFA, dual-approval for sensitive actions (roadmap) |
| Side-channel attacks | Timing analysis of API calls may reveal access patterns | Request padding, constant-time operations (partial) |
Accepted Risks
These are risks acknowledged in the design that are accepted as reasonable tradeoffs:
AWS as trusted infrastructure -- We trust AWS KMS HSMs and S3 durability. A catastrophic AWS failure could cause data loss (mitigated by S3 versioning and DynamoDB point-in-time recovery within the deployed region).
7-day KMS key deletion minimum -- AWS requires a minimum 7-day waiting period for key deletion. During this window, a compromised AWS insider could theoretically recover a "deleted" key. After 7 days, deletion is cryptographically irreversible.
Metadata visibility -- The server can see file paths, sizes, and access patterns. Full metadata encryption would prevent server-side permission enforcement. This is a conscious tradeoff for usability.
Single-region latency -- To ensure data residency, we deploy in one region. Users far from that region experience higher latency. CDN acceleration is not used because content is encrypted and per-user.
Defense-in-Depth Recommendations
VaultGuard provides application-layer security. For comprehensive protection, combine with:
1. Mobile Device Management (MDM)
Recommended for organizations with strict security requirements:
- Enforce device encryption (FileVault on macOS, BitLocker on Windows)
- Enforce screen lock timeout (maximum 5 minutes)
- Remote wipe capability for lost/stolen devices
- Compliance checks before allowing VaultGuard plugin to sync
- Certificate deployment for mutual TLS (advanced)
Recommended MDMs: Jamf (macOS), Intune (Windows), Kandji, Mosyle
2. Network Security
- VPN/ZTNA for accessing the VaultGuard API from untrusted networks
- IP allowlisting in API Gateway for office networks
- DNS filtering to prevent data exfiltration via DNS tunneling
- Network segmentation if self-hosting any components on-premises
3. Endpoint Security
- EDR (Endpoint Detection and Response) to detect memory scraping, keyloggers
- DLP (Data Loss Prevention) to monitor clipboard, file transfers, screenshots
- Application allowlisting to prevent unauthorized tools from accessing vault data
4. Identity Security
- Hardware security keys (FIDO2/WebAuthn) instead of TOTP for MFA
- Conditional access policies (deny from unmanaged devices, unknown locations)
- Just-in-time access for sensitive folders (request-approve workflow)
- Behavioral analytics to detect anomalous access patterns
5. Operational Security
- Security awareness training covering data handling, social engineering
- Incident response plan specific to VaultGuard (who to call, what to revoke)
- Regular access reviews (quarterly review of who has access to what)
- Penetration testing on a scheduled cadence against the API and plugin
6. Monitoring and Detection
┌─────────────────────────────────────────────────────────────┐
│ Detection Pipeline │
├─────────────────────────────────────────────────────────────┤
│ │
│ VaultGuard Audit Log ──> CloudWatch Logs ──> CloudWatch │
│ Metric Filters │
│ │ │
│ v │
│ Anomaly Detection (Lambda) ──> SNS Alert ──> SIEM/Slack │
│ │
│ Patterns to detect: │
│ - Bulk file downloads (> N files in M minutes) │
│ - Access outside business hours │
│ - Access from new geographic location │
│ - Permission escalation attempts │
│ - Repeated auth failures followed by success │
│ - File access patterns inconsistent with user's role │
│ │
└─────────────────────────────────────────────────────────────┘
Security Contact
For responsible disclosure of security vulnerabilities:
- Email: security@your-company.com
- PGP key: [link to public key]
- Expected response time: 24 hours
- Bug bounty: Contact for details
Document History
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0 | 2024-01-15 | Security Team | Initial security model |
| 1.1 | 2024-03-01 | Security Team | Added HIPAA section, updated threat model |
| 1.2 | 2024-06-15 | Security Team | Added device access analysis, comparison table |
| 1.3 | 2026-07-10 | Security audit (SD-01) | Marked historical/superseded by docs/SECURITY.md; corrected control claims (cert pinning, VPC endpoints, WebSocket revocation, device+IP binding, cross-region replication, SMS MFA, PBKDF2-by-default) to match the implementation |