This guide covers security considerations and privacy best practices when building and deploying Mau applications.
Mau’s security is built on several foundational principles:
| Property | Implementation | Protection Against |
|---|---|---|
| Identity | PGP public keys | Impersonation, fake accounts |
| Authentication | Digital signatures | Forged content, tampering |
| Confidentiality | PGP encryption | Eavesdropping, data leaks |
| Integrity | Cryptographic hashes | Corruption, modification |
| Non-repudiation | Signature verification | Denial of authorship |
Mau uses a web of trust model:
┌──────────────┐
│ You (A) │──────────┐
└──────────────┘ │
│ │
│ trust │ direct
│ │ connection
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Friend (B) │◄───│ Peer (C) │
└──────────────┘ └──────────────┘
│
│ transitively
│ trust?
▼
┌──────────────┐
│ Friend's │
│ Friend (D) │
└──────────────┘
Key principles:
✅ Eavesdropping: All content is encrypted end-to-end
✅ Impersonation: Signatures verify sender identity
✅ Tampering: Modified content fails signature verification
✅ Man-in-the-middle: TLS + certificate fingerprint validation
✅ Unauthorized access: Only recipients can decrypt files
✅ Data exfiltration: No central server to compromise
❌ Compromised endpoints: If your device is hacked, keys are exposed
❌ Malicious recipients: Recipients can leak content after decryption
❌ Traffic analysis: Metadata (who talks to whom) may be observable
❌ Key compromise: Lost/stolen private keys compromise all past content
❌ Social engineering: Users can be tricked into trusting wrong keys
❌ Quantum computers: RSA and current PGP may be vulnerable in future
Scenario 1: Network Attacker
Scenario 2: Malicious Peer
Scenario 3: Storage Access
~/.mau directoryYour private key is the crown jewel of your Mau identity. If compromised, attackers can:
When creating an account, the private key is encrypted with your password:
1# Strong password required
2mau init myaccount
3Password: ************ # At least 12 characters recommended
Password requirements:
Default location: ~/.mau/<account>/account.pgp
File permissions should be restrictive:
1# Check permissions
2ls -la ~/.mau/myaccount/account.pgp
3# Should be: -rw------- (0600) or -rw-r----- (0640)
4
5# Fix if needed
6chmod 600 ~/.mau/myaccount/account.pgp
Backup strategy:
1# Encrypted backup to external drive
2cp ~/.mau/myaccount/account.pgp /media/backup/mau-backup-$(date +%F).pgp
3
4# Or use tar with encryption
5tar czf - ~/.mau/myaccount | gpg -c > mau-backup.tar.gz.gpg
If you suspect key compromise:
1# Create new account
2mau init myaccount-new
3
4# Export new public key
5mau export-key myaccount-new > new-public-key.asc
6
7# Manually share with friends, then delete old account
8rm -rf ~/.mau/myaccount
Every file in Mau is both signed and encrypted:
When receiving content, always verify the signature:
1// Automatic verification in Mau
2file, err := account.GetFile(friendFingerprint, "post.json")
3if err != nil {
4 log.Fatal(err)
5}
6
7// This automatically verifies:
8// 1. File is signed
9// 2. Signature is valid
10// 3. Signer matches expected friend
11err = file.VerifySignature(account, friendFingerprint)
12if err != nil {
13 log.Fatal("Signature verification failed:", err)
14}
What this prevents:
Files are encrypted only for specified recipients:
1// Encrypt for specific friends
2recipients := []Fingerprint{
3 alice.Fingerprint(),
4 bob.Fingerprint(),
5}
6
7err := account.SaveFile("secret.json", content, recipients)
Best practices:
Verify who can read a file:
1recipients, err := file.Recipients(account)
2if err != nil {
3 log.Fatal(err)
4}
5
6fmt.Println("File is encrypted for:")
7for _, friend := range recipients {
8 fmt.Printf("- %s (%s)\n", friend.Name(), friend.Fingerprint())
9}
Mau uses self-signed certificates with fingerprint pinning:
1// Automatic in Mau: TLS cert must match PGP key fingerprint
2// This prevents MITM even with compromised CA
How it works:
This prevents:
Default ports:
Firewall configuration:
1# Allow Mau traffic
2sudo ufw allow 8080/tcp
3
4# Or restrict to specific IPs
5sudo ufw allow from 192.168.1.0/24 to any port 8080
Development:
1# Localhost only (default)
2mau serve --address 127.0.0.1:8080
Production:
1# Public internet (use with TLS!)
2mau serve --address 0.0.0.0:8443 --tls
Best practices:
The DHT exposes your peer presence:
Information leaked:
Mitigation strategies:
1// Disable DHT discovery
2client := mau.NewClient(dir)
3client.DisableDHT()
Regular rm may leave data recoverable:
1# Use secure deletion (overwrites data)
2shred -u ~/.mau/myaccount/files/sensitive.json.pgp
3
4# Or on whole directory
5find ~/.mau/myaccount/files -type f -exec shred -u {} \;
In code:
1// Delete file versions too
2file, _ := account.GetFile(friendFp, "data.json")
3for _, version := range file.Versions() {
4 os.Remove(version.Path)
5}
6os.Remove(file.Path)
7
8// Optionally securely wipe
9// (requires external tool or library)
Implement automatic cleanup:
1// Delete files older than 30 days
2cutoff := time.Now().AddDate(0, 0, -30)
3
4files, _ := account.ListFiles(friendFingerprint)
5for _, file := range files {
6 info, _ := os.Stat(file.Path)
7 if info.ModTime().Before(cutoff) {
8 os.Remove(file.Path)
9 }
10}
⚠️ Mau does not provide forward secrecy
Alternative for high-security needs:
What’s exposed:
Network observer can see:
- You connected to peer X at time T
- File Y was transferred (size, timing)
- DHT queries reveal interests
What’s hidden:
Encrypted and not observable:
- File contents
- File names (encrypted)
- Number of recipients
- Actual relationships (who is whose friend)
Mau prioritizes accountability over anonymity:
For true anonymity:
Example: Anonymous forums
1// Create anonymous post
2post := map[string]interface{}{
3 "@type": "SocialMediaPosting",
4 "author": map[string]interface{}{
5 "@type": "Person",
6 "identifier": account.Fingerprint().String()[:8], // Short hash
7 // No name, email, or identifying info
8 },
9 "headline": "Anonymous thought...",
10}
Example: Ephemeral messaging
1// Auto-delete after reading
2msg, _ := file.Reader(account)
3content, _ := io.ReadAll(msg)
4fmt.Println(string(content))
5
6// Delete immediately
7os.Remove(file.Path)
For regulated environments:
1// Log all access
2func AuditLog(event string, details map[string]string) {
3 log.Printf("[AUDIT] %s: %v", event, details)
4}
5
6// Track file access
7file, err := account.GetFile(fp, name)
8AuditLog("file_access", map[string]string{
9 "user": account.Fingerprint().String(),
10 "peer": fp.String(),
11 "file": name,
12 "timestamp": time.Now().Format(time.RFC3339),
13})
If building EU-facing application:
1// GDPR export
2func ExportUserData(account *Account) error {
3 archive := createZip()
4
5 // Include all files
6 files, _ := account.ListAllFiles()
7 for _, file := range files {
8 content, _ := file.Reader(account)
9 archive.Add(file.Name(), content)
10 }
11
12 // Include friend list
13 friends, _ := account.ListFriends()
14 archive.Add("friends.json", marshalJSON(friends))
15
16 return archive.Save("user-data-export.zip")
17}
If you discover a security issue in Mau:
Security is a shared responsibility:
Remember: The most secure system is useless if users don’t trust it. Balance security with usability, and always document the threat model clearly.
For implementation details, see: