Passli is engineered with an ephemeral, privacy-first access control architecture designed for secure, time-gated document sharing without master credential exposure or plaintext data retention.
Passli operates with complete architectural transparency:
- Not Zero-Knowledge: Passli is not zero-knowledge. Files are encrypted at rest server-side using AES-256-GCM with a master key held by the server. Because the server holds the key, the server can read documents.
- Server-Side Enforcement: Expiry, access control, and revocation are enforced by the server; there is no hardware-based key destruction.
- No Independent Audit: Passli has not been independently audited or certified by SOC 2 or any external security agency.
We actively support and release security updates for the following versions of Passli:
| Version | Supported | Security Maintenance | Cryptographic Engine |
|---|---|---|---|
1.3.x (Current Main) |
✅ | Active Security Patches & Threat Mitigation | AES-256-GCM + PBKDF2-HMAC-SHA256 |
1.2.x |
✅ | Bugfixes & Maintenance | AES-256-GCM Migration Compatible |
< 1.2.0 |
❌ | Deprecated | Legacy |
- Engine: Industry-standard AES-256-GCM (Galois/Counter Mode) with Authenticated Encryption with Associated Data (AEAD) via Python's
cryptographylibrary. - Storage Wire Format:
[12-byte Nonce][Ciphertext + 16-byte GCM Authentication Tag]. Total cryptographic overhead is exactly 28 bytes per stored file. - Nonce Uniqueness: Each document encryption operation generates a unique, non-repeating 12-byte CSPRNG nonce (
os.urandom(12)), preventing replay attacks and cryptographic pattern leakage across identical files. - Tamper Resistance: Any modification, bit-flip, or byte truncation of stored files triggers an immediate
VaultDecryptionErrorupon tag verification failure, preventing corrupted or tampered payloads from ever reaching application memory. - Key Management: Primary vault key is supplied via
VAULT_MASTER_KEY(32-byte hexadecimal key). In local/development environments without explicit configuration, a deterministic 256-bit key is derived using HKDF-SHA256 from Django'sSECRET_KEY.
- Owner previews, owner downloads, and verified recipient views decrypt ciphertext strictly in-memory using
io.BytesIOstreams. - No plaintext files are ever written to the physical file system or temp directories during inspection or streaming.
- Responses enforce defensive security headers:
X-Content-Type-Options: nosniff Cache-Control: no-store, no-cache, must-revalidate, private Pragma: no-cache
- Plaintext 8-character Share Keys (
XXXX-XXXX) are generated dynamically using cryptographically secure random sources (secrets.choicefrom a 31-character unambiguous alphabet excluding lookalike characters0/O,1/I/L). - Plaintext keys are never stored in the database or written to server logs; only salted PBKDF2-HMAC-SHA256 hashes are retained (
django.contrib.auth.hashers.make_password). - The server verifies submitted keys against the PBKDF2 hash using constant-time comparison to establish ephemeral, session-bound recipient access.
- Every uploaded vault document is processed through SHA-256 checksum hashing on the original plaintext on ingestion.
- The binary digest is preserved in the database for client and recipient verification against source documents, even while stored files are encrypted at rest.
- All vault access handlers strictly filter by
user=request.useror authenticated recipient session ID before serving document contents. - Direct object reference tampering across tenant boundaries is caught at the view boundary with HTTP 404/403 responses.
- Failed Share Key attempts trigger structured security logs and increment attempt counters.
- Five consecutive failed key attempts enforce immediate lockout and trigger an automated security notification email to the pass owner.
- Password reset workflows utilize time-sensitive, single-use cryptographic tokens generated by Django's
PasswordResetTokenGenerator. - Email verification codes utilize time-gated 6-digit numeric OTPs stored with expiration timestamps.
- Critical security events (password resets, failed passcode attempts, onboarding) trigger automated transactional emails via SMTP/TLS.
- Access events are recorded in an append-only relational audit table (
ShareAccessLog), capturing client IP, user agent, event type, and outcome timestamp for owner visibility. - Sensitive values (passcode characters, authorization tokens, full email addresses) are sanitized and masked before log persistence.
If you discover a potential security vulnerability within Passli, please do not open a public issue. Instead, follow our responsible disclosure procedure:
- Send an email with full reproduction steps to:
alinawaz.code@gmail.com - Include the following details in your report:
- Description of the vulnerability and its potential impact.
- Step-by-step instructions or proof-of-concept (PoC) code.
- Affected URLs, endpoints, or parameters.
- Suggestions for mitigation or fix (optional).
- Initial Acknowledgment: Within 24 hours.
- Vulnerability Assessment: Within 48 hours.
- Patch & Release: Within 7 business days for critical vulnerabilities.
We credit all responsible security researchers in our release notes and Hall of Fame.