Security & Encryption
How SafeGuard protects your backups, migrations, and credentials with modern cryptography and defense-in-depth security.
Security Overview
SafeGuard is designed with a security-first philosophy. Every feature — from backups to migrations to cloud storage — is built on the principle that your data should be protected at rest, in transit, and at every point in between.
Key security properties across SafeGuard:
| Layer | Protection |
|---|---|
| Backups | Optional AES-256 encryption at rest |
| Migrations | End-to-end AEAD encryption (ChaCha20-Poly1305 / AES-256-GCM) |
| Cloud relay | Zero-knowledge design — relay never sees plaintext |
| OAuth tokens | AES-256-CBC encrypted in the database, keyed to your WordPress salts |
| REST API | WordPress capability checks + license validation on all write operations |
| Migration codes | IP-based rate limiting to prevent brute-force attacks |
Backup Encryption
SafeGuard supports encrypting backup archives before they are stored locally or uploaded to a remote provider.
Enabling Backup Encryption
Navigate to SafeGuard → Settings → Advanced and toggle Encrypt Backups on.
curl -X POST /wp-json/safeguard/v1/storage/settings \
-H "X-WP-Nonce: <nonce>" \
-d '{"encryptBackups": true}'What Gets Encrypted
When backup encryption is enabled, the entire backup archive is encrypted before it leaves your server. This includes:
- Database exports — all SQL dump files containing your posts, users, options, and custom tables.
- File archives — themes, plugins, uploads, and WordPress core files.
- Incremental diffs — changed files in incremental backups are encrypted identically to full backups.
If you lose your encryption key (your WordPress authentication salts in wp-config.php), encrypted backups cannot be recovered. Always keep a secure copy of your wp-config.php file separate from your backups.
How It Works
Backup encryption uses AES-256-CBC with a key derived from your WordPress authentication salts via SHA-256. Each backup archive gets a unique random initialization vector (IV), ensuring that identical backups produce different ciphertext.
SafeLink Migration Encryption
SafeLink is SafeGuard's site-to-site migration protocol. It implements a full cryptographic chain inspired by modern secure messaging protocols, ensuring that migration data is protected even if the network is compromised.
Cryptographic Chain Overview
Source Site Destination Site
─────────── ────────────────
1. Generate ECDH keypair (prime256v1)
2. Send public key + migration code ──────► 3. Generate ECDH keypair
◄────── 4. Return public key + nonce
5. Derive shared secret (ECDH) 5. Derive shared secret (ECDH)
6. HKDF-SHA256 → auth_key + enc_key 6. HKDF-SHA256 → auth_key + enc_key
7. Encrypt data (ChaCha20-Poly1305)
8. Sign request (HMAC-SHA256) ──────► 9. Verify HMAC signature
10. Verify sequence number
11. Decrypt data (ChaCha20-Poly1305)ECDH Key Exchange
Both the source and destination sites generate ephemeral Elliptic Curve Diffie-Hellman (ECDH) keypairs on the prime256v1 (P-256) curve. The public keys are exchanged during the handshake, and each side independently derives the same shared secret — without ever transmitting it over the network.
This means even if an attacker captures the handshake, they cannot reconstruct the shared secret without one of the private keys.
HKDF Key Derivation
The raw ECDH shared secret is never used directly for encryption. Instead, SafeGuard uses HKDF-SHA256 (HMAC-based Key Derivation Function) to derive two separate 32-byte keys:
- Authentication key — used for HMAC-SHA256 request signing (context:
safeguard-safelink-auth-v1) - Encryption key — used for AEAD encryption (context:
safeguard-safelink-enc-v1)
A per-session nonce is used as the HKDF salt, ensuring that even if the same two sites migrate multiple times, the derived keys are always different.
AEAD Encryption
All migration data is encrypted with Authenticated Encryption with Associated Data (AEAD):
- Preferred cipher: ChaCha20-Poly1305 — fast on all hardware, including servers without AES-NI acceleration.
- Fallback cipher: AES-256-GCM — universally available across PHP OpenSSL builds.
SafeGuard probes at runtime to confirm the preferred cipher supports AEAD tags correctly, and automatically falls back if needed. The cipher selection is transparent and requires no configuration.
Each encrypted message is packed as a binary blob:
| Field | Size | Description |
|---|---|---|
| Cipher ID | 1 byte | 0x01 = ChaCha20-Poly1305, 0x02 = AES-256-GCM |
| IV | 12 bytes | Sequence number (8 bytes) + random bytes |
| Auth tag | 16 bytes | AEAD authentication tag (Poly1305 or GMAC) |
| Ciphertext | Variable | Encrypted payload |
The authentication tag ensures that any tampering with the ciphertext, IV, or cipher ID is detected and rejected before decryption.
Anti-Replay Protection
Each encrypted message includes a monotonically increasing sequence number packed into the first 8 bytes of the IV. The receiver tracks the expected sequence number and rejects any message where the embedded sequence does not match.
This prevents an attacker from capturing and replaying legitimate migration packets to corrupt or duplicate data on the destination site.
HMAC-SHA256 Request Signing
Every migration request is signed with HMAC-SHA256 using the derived authentication key. The receiver verifies the signature using a constant-time comparison (hash_equals) before processing any data.
This provides two guarantees:
- Authenticity — the request genuinely originated from a site that holds the shared secret.
- Integrity — the request body has not been modified in transit.
Zero-Knowledge Design
The source and destination negotiate encryption keys directly via ECDH. No intermediate server — including SafeGuard's cloud relay — ever has access to the shared secret or derived keys. Even if the relay infrastructure were fully compromised, an attacker would see only encrypted ciphertext with no way to recover plaintext.
Cloud Relay Security
When the destination site cannot accept direct connections (firewall, NAT, Cloudflare, shared hosting), SafeGuard routes migration data through its cloud relay at safeguard.verdelic.com. The relay is designed as a dumb pipe:
- No decryption — the relay forwards raw encrypted bytes. It does not hold encryption keys and cannot decrypt any payload.
- License-gated access — only active SafeGuard licenses can establish relay sessions, preventing unauthorized use.
- SSRF protection — the relay validates destination URLs to prevent internal network scanning.
- Auto-expiring sessions — relay sessions expire after 1 hour. No migration data is persisted on the relay.
The relay activates automatically when the destination is unreachable directly. If direct connectivity is available, it is always preferred. No configuration is required.
Storage Security
OAuth Token Encryption
When you connect a cloud storage provider (Google Drive, Dropbox, OneDrive), SafeGuard stores your OAuth tokens encrypted in the WordPress database:
- Algorithm: AES-256-CBC with a random 16-byte IV per token.
- Key derivation: The encryption key is derived via SHA-256 from your WordPress
authsalt combined with a SafeGuard-specific context string (safeguard_oauth_token_v1). - Storage location: Encrypted tokens are stored in WordPress user meta, scoped to the user who authorized the connection.
- Automatic cleanup: Expired tokens are automatically purged.
Your OAuth tokens are only as secure as your WordPress authentication salts. Never share or commit your wp-config.php file to version control. If you suspect your salts have been compromised, regenerate them and reconnect your storage providers.
Provider-Specific Security
| Provider | Credential Type | Storage Method |
|---|---|---|
| Amazon S3 | Access key + secret | Encrypted in wp_options |
| Google Drive | OAuth 2.0 tokens | Encrypted in user meta |
| Dropbox | OAuth 2.0 tokens | Encrypted in user meta |
| OneDrive | OAuth 2.0 tokens | Encrypted in user meta |
| MEGA | Email + password | Encrypted in wp_options |
| FTP/SFTP | Host + credentials | Encrypted in wp_options |
| SMTP credentials | Encrypted in wp_options |
All provider credentials are encrypted at rest using AES-256. Plain-text credentials are never stored in the database.
Access Control
WordPress Capabilities
All SafeGuard REST API endpoints require the manage_options capability, which is restricted to WordPress Administrators by default. Non-admin users cannot access any SafeGuard functionality, including viewing backups, running restores, or modifying settings.
License Enforcement
Write operations — creating backups, running restores, creating schedules, initiating migrations, and managing staging sites — additionally require an active SafeGuard license. This is enforced via a shared License_Check trait used across all REST API controllers:
- Read operations (listing backups, viewing settings) require
manage_optionsonly. - Write operations require
manage_optionsand an active license.
If your license expires or is deactivated, existing backups remain accessible but no new operations can be performed until the license is reactivated.
Staging Site Access Control
Staging site operations (create, delete, push to live) require both manage_options and an active license. This prevents unauthorized users from deploying staging changes to your production site.
File Quarantine
When SafeGuard restores a backup, it does not blindly overwrite your existing files. Instead, the Pruning Service identifies files that exist on your server but are not present in the backup being restored.
Rather than deleting these files immediately, SafeGuard moves them to a quarantine directory:
wp-content/safeguard-quarantine/20260328-143022/Each restore operation creates a timestamped quarantine folder. This provides a safety net: if the restore removes files your site depends on, you can recover them from quarantine.
SafeGuard never prunes its own directories (safeguard-backups, safeguard-quarantine) or critical WordPress cache and upgrade directories. These are protected by built-in preservation policies.
Managing Quarantined Files
Navigate to SafeGuard → Quarantine to view, restore, or permanently delete quarantined files.
# List quarantined files
wp safeguard quarantine list
# Restore a quarantined file
wp safeguard quarantine restore <file>
# Delete all quarantined files
wp safeguard quarantine cleanRate Limiting
Migration handshake endpoints are protected by IP-based rate limiting to prevent brute-force attempts against migration codes:
- Limit: 3 handshake attempts per IP address per hour.
- Storage: Rate limit counters are stored in WordPress transients with automatic expiration.
- Response: Requests exceeding the limit receive a
429 Too Many Requestsresponse.
This prevents an attacker from rapidly guessing migration codes, even if they know a migration session is active.
Privacy & Data Handling
SafeGuard respects your privacy and your users' privacy:
Telemetry
- Opt-in only — SafeGuard displays a consent notice on first use. Telemetry is never sent unless you explicitly opt in.
- Anonymous — if you opt in, SafeGuard sends only anonymous, aggregated usage statistics (PHP version, WordPress version, backup counts, enabled features). No personal data, site content, or backup contents are ever transmitted.
- Revocable — you can disable telemetry at any time from SafeGuard → Settings.
What SafeGuard Does NOT Collect
- Site content, posts, pages, or user data.
- Backup file contents.
- Database contents.
- OAuth tokens or storage provider credentials.
- Personally identifiable information.
Third-Party Data Sharing
SafeGuard does not share any data with third parties. The only external communication is:
- License validation — your license key and domain are verified against
api.safeguard.verdelic.com. - Cloud relay — encrypted migration data may route through
safeguard.verdelic.comwhen direct connections fail (the relay cannot decrypt this data). - Telemetry (opt-in only) — anonymous usage statistics sent to
api.safeguard.verdelic.com.
Best Practices
Enable backup encryption
Turn on Encrypt Backups in SafeGuard → Settings → Advanced if your backups contain sensitive data. This is especially important when storing backups on third-party cloud providers.
Secure your WordPress salts
Your wp-config.php authentication salts are the root key for both backup encryption and OAuth token encryption. Store a copy of your wp-config.php in a secure location separate from your backups.
Use unique migration codes
Each migration generates a unique code. Never reuse or share migration codes. They expire automatically after use.
Keep SafeGuard updated
Security patches and cryptographic improvements are delivered through plugin updates. Enable auto-updates or check for updates regularly.
Restrict admin access
SafeGuard operations require the manage_options capability. Limit the number of WordPress administrators on your site to reduce the attack surface.
Review quarantined files after restores
After restoring a backup, check the quarantine directory for any files that were removed. Delete quarantined files once you have confirmed your site is working correctly.