Security Practices
How qwip Protects Your Privacy and Secures the Infrastructure
Last Updated: December 2025
Table of Contents
- Architecture Security
- Cryptographic Guarantees
- Transport Security
- Server Infrastructure
- API Authentication
- Threat Model
- Incident Response
- Open Source Verification
- Security Audits
- Reporting Security Issues
1. Architecture Security
Local-First Processing
All sensitive operations happen in your browser:
┌──────────────────────────────────────────┐
│ Your Browser (100% Local Processing) │
│ ┌────────────────────────────────────┐ │
│ │ 1. Image detected on webpage │ │
│ │ 2. ONNX model loaded into memory │ │
│ │ 3. Inference runs locally (WASM) │ │
│ │ 4. Result: "AI" or "Real" │ │
│ │ 5. Badge displayed on image │ │
│ └────────────────────────────────────┘ │
│ │
│ Images NEVER leave this sandbox │
└──────────────────────────────────────────┘
│
│ (Optional: Anonymous data only)
▼
┌──────────────────────────────────────────┐
│ qwip Server (No Images Ever) │
│ ┌────────────────────────────────────┐ │
│ │ Receives: │ │
│ │ - Cryptographic hashes (64 chars) │ │
│ │ - Anonymous session IDs │ │
│ │ - Detection results (AI/Real) │ │
│ │ │ │
│ │ NEVER receives: │ │
│ │ - Image pixels │ │
│ │ - URLs or browsing history │ │
│ │ - Personal information │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘Security Boundary
Extension Sandbox:
- All image processing isolated in browser content script
- No network access for image data
- Manifest V3 enforced permissions
Server Separation:
- Server has zero access to image content
- Only receives cryptographic hashes
- Cannot reconstruct images from hashes
2. Cryptographic Guarantees
Perceptual Hashing (One-Way Function)
Algorithm: Multiple hash types (Mean, Gradient, DoubleGradient, Block, DCT)
Security Properties:
Input: 1920×1080 image = 2,073,600 pixels × 3 channels (RGB)
= 6,220,800 values
Output: 64-bit hash = 8 bytes
= 18,446,744,073,709,551,616 possible values
Information Loss: 6,220,800 → 1 value (massive reduction)
Reversal: Impossible - infinite possible images map to same hashWhy It's Secure:
- One-way function - Cannot compute image from hash
- Information loss - 99.999% of image data discarded
- No rainbow table attacks - Same image → different hash with different algorithms
- Similar images → similar hashes - But dissimilar images can also have similar hashes (collision by design)
Mathematical Proof:
Hash space: 2^64 ≈ 1.8 × 10^19 possible hashes
Image space: (2^8)^(1920×1080×3) ≈ 256^(6,220,800) possible images
Number of images per hash: 256^(6,220,800) / 2^64 ≈ INFINITY
Therefore: Multiple images → Same hash (irreversible)BLAKE3 Content Hashing
Algorithm: BLAKE3 (cryptographically secure hash function)
Security Properties:
| Property | Description | Security Guarantee |
|---|---|---|
| Pre-image resistance | Given hash, cannot find original image | ✅ Computationally infeasible |
| Second pre-image resistance | Given image1, cannot find image2 with same hash | ✅ Collision-resistant |
| Avalanche effect | 1 pixel change → completely different hash | ✅ Yes |
Example:
Original Image: [2,073,600 pixels of data...]
↓
BLAKE3 Hash: "abc123def456789...abcdef" (64 hex characters)
↓
Server Storage: "abc123def456789...abcdef"
// Attacker with hash CANNOT:
// ❌ Recreate the image
// ❌ Determine any pixel values
// ❌ Identify the image (unless already in database)End-to-End Security Flow
User's Browser:
┌─────────────────────────────────┐
│ Image (2MB PNG) │
│ ↓ Local Processing │
│ BLAKE3 Hash (64 chars) │
│ Perceptual Hashes (5 × 64 bits) │
└─────────────────────────────────┘
│ HTTPS (TLS 1.3)
▼
qwip Server:
┌─────────────────────────────────┐
│ Stores: │
│ - BLAKE3: "abc123..." │
│ - Hashes: {mean: "0xA3F2..."} │
│ - Result: {ai: true, conf: 0.9} │
│ │
│ NEVER sees: │
│ - Original 2MB image │
│ - Any pixel data │
└─────────────────────────────────┘3. Transport Security
HTTPS Everywhere
Current (v1.0):
- All server communication uses HTTPS (TLS 1.3)
- No HTTP fallback (strict HTTPS-only)
- Certificate validation enforced by browser
Configuration:
// Extension code: server-api.js
const serverURL = 'https://api.qwip.io'; // HTTPS-only
fetch(serverURL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
// Browser automatically enforces:
// - TLS 1.3
// - Certificate validation
// - HSTS (HTTP Strict Transport Security)
});Future Enhancements (Planned)
Certificate Pinning (v1.2):
// Planned: Pin specific certificate to prevent MITM
const PINNED_CERT = 'sha256/AAAAAAAAAA...';Request Signing (v2.0):
- Sign requests with ephemeral keys
- Prevent replay attacks
- End-to-end encryption
4. Server Infrastructure
Current Deployment (v1.0)
Technology Stack:
| Component | Technology | Purpose |
|---|---|---|
| Application | Flask (Python) | API endpoints |
| Database | SQLite | Persistent storage |
| Cache | Redis | Real-time metrics |
| Web Server | Gunicorn (4 workers) | WSGI server |
| Container | Docker | Isolation |
| Orchestration | Docker Compose | Multi-service |
Security Measures:
| Measure | Implementation | Status |
|---|---|---|
| Secrets management | Environment variables (.env) | ✅ Active |
| Database encryption | SQLite file permissions (600) | ✅ Active |
| No public DB access | Firewall rules | ✅ Active |
| Rate limiting | Planned (Nginx) | 🚧 Planned |
| Request validation | Flask schema validation | ✅ Active |
| SQL injection protection | Parameterized queries | ✅ Active |
Example Secure Query:
# ✅ SECURE (Parameterized query)
db.session.execute(db.text("""
INSERT INTO user_sessions (session_id, images)
VALUES (:session_id, :images)
"""), {"session_id": session_id, "images": count})
# ❌ INSECURE (Would be vulnerable to SQL injection)
# db.execute(f"INSERT INTO ... VALUES ('{session_id}', {count})")Infrastructure Diagram
Internet
│
│ HTTPS (TLS 1.3)
▼
┌─────────────────────────────┐
│ Reverse Proxy (Nginx) │
│ - TLS termination │
│ - Rate limiting │
│ - Request filtering │
└─────────────────────────────┘
│
▼
┌─────────────────────────────┐
│ Docker Network (Isolated) │
│ ┌────────────────────────┐ │
│ │ Flask App (Gunicorn) │ │
│ │ - API endpoints │ │
│ │ - Request validation │ │
│ └────────────────────────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ ▼ ▼ │
│ ┌──────┐ ┌───────┐ │
│ │SQLite│ │ Redis │ │
│ │ (DB) │ │(Cache)│ │
│ └──────┘ └───────┘ │
└─────────────────────────────┘Server Hardening
Implemented:
- ✅ Minimal attack surface (only necessary ports open)
- ✅ Regular security updates (automated)
- ✅ Containerization (isolation)
- ✅ Least privilege principle (non-root user)
- ✅ No sensitive data in logs
Planned:
- 🚧 Web Application Firewall (WAF)
- 🚧 Intrusion Detection System (IDS)
- 🚧 Automated backups with encryption
5. API Authentication
Current Implementation (v1.0)
Method: Shared API key
Security Model:
Extension → Server
Header: Content-Type: application/json
Body: {
"session_id": "a3f2b1c4-...",
"images_analyzed": 47
}
// No authentication header in v1.0
// Rate limiting by IP address plannedWhy Acceptable for v1.0:
- Anonymous data only (low sensitivity)
- No personal information at risk
- Rate limiting planned for abuse prevention
Future Authentication (v1.2+)
Option 1: Per-Install API Keys
// Generate unique key per extension install
const installKey = await generateInstallKey();
fetch(serverURL, {
headers: {
'X-API-Key': installKey
}
});Benefits:
- Abuse tracking (ban specific installations)
- Still anonymous (key not linked to identity)
- Revocable if compromised
Option 2: Anonymous Tokens (v2.0)
// Zero-knowledge proof: "I'm a valid user, but you don't know who"
const anonymousProof = await generateZKProof();
fetch(serverURL, {
headers: {
'X-Anonymous-Proof': anonymousProof
}
});Benefits:
- Cryptographically anonymous
- Prevents Sybil attacks
- No tracking possible
6. Threat Model
What We Protect Against ✅
| Threat | Protection | Effectiveness |
|---|---|---|
| Image interception | Never transmitted | ✅ 100% |
| User tracking | Anonymous session IDs | ✅ High |
| Data breach impact | No personal data stored | ✅ Very low risk |
| Man-in-the-middle (MITM) | TLS 1.3 encryption | ✅ High |
| Database exposure | Only hashes, not images | ✅ Low impact |
| SQL injection | Parameterized queries | ✅ Protected |
| XSS attacks | Content Security Policy | ✅ Protected |
| CSRF attacks | No cookies, stateless API | ✅ N/A |
What We DON'T Protect Against ❌
| Limitation | Reason | Mitigation |
|---|---|---|
| Local malware on your device | Outside our control | User responsibility (antivirus) |
| Browser extensions reading memory | Browser security issue | Chrome Web Store review process |
| Physical access to device | User responsibility | Encrypt your device |
| Compromised browser | Outside our scope | Keep browser updated |
Attack Scenarios & Responses
Scenario 1: Server Breach
Attacker gains access to server database.
What they get:
- Anonymous session IDs (e.g.,
a3f2b1c4-5d6e-...) - Cryptographic hashes (e.g.,
abc123def456...) - Detection results (AI/Real labels)
- Aggregate statistics
What they DON'T get:
- ❌ User identities (no names, emails)
- ❌ Images (never stored)
- ❌ Browsing history (never tracked)
- ❌ Personal information (never collected)
Impact: Low - No personal data leaked, session IDs are random
Response:
- Immediately notify all users via extension update
- Rotate any API keys
- Publish transparency report
- Conduct forensic investigation
Scenario 2: Your Device Compromised
Malware on your computer/phone.
What attacker sees:
- Extension's local storage (session ID, stats)
- Detection results displayed on webpages
- Same as any other browser extension
What attacker DON'T see:
- Nothing worse than any other extension - we don't store images locally either
Impact: Same as any extension - not specific to qwip
Mitigation:
- Keep your device secure (antivirus, updates)
- Only install extensions from Chrome Web Store
- Review extension permissions regularly
Scenario 3: Network Eavesdropping
Attacker intercepts your internet traffic.
With TLS 1.3:
- ❌ Cannot see request/response content (encrypted)
- ✅ Can see you're connecting to
api.qwip.io(DNS/IP visible)
What they learn:
- "User is accessing qwip server"
- NOT: What hashes were sent, what results were returned
Impact: Very low - No meaningful data leaked
Mitigation:
- TLS 1.3 encryption (automatic)
- Optional: Use VPN for additional privacy
7. Incident Response
If Our Server Is Compromised
Immediate Actions (< 24 hours):
- Contain: Shut down affected servers
- Assess: Determine scope of breach
- Notify: Email all users (via extension update notification)
- Preserve: Forensic evidence for investigation
Within 7 Days:
- Publish detailed transparency report
- Notify relevant authorities (if required by law)
- Implement fixes to prevent recurrence
- Third-party security audit
Long-term:
- Enhanced security measures
- Regular penetration testing
- Bug bounty program (post-funding)
If You Discover a Vulnerability
See Reporting Security Issues below.
8. Open Source Verification
Don't Trust Us, Verify
All code is open source: GitHub Repository
What you can verify:
No image uploads:
bash# Search entire codebase for image uploads grep -r "fetch.*blob" qwip-extension/ # Result: Only hash-related fetches, no image uploadsSession ID generation:
bash# View session ID code cat qwip-extension/server-api.js | grep -A 5 "randomUUID" # Result: Uses crypto.randomUUID() (browser built-in)What data is sent to server:
bash# Check all server API calls cat qwip-extension/server-api.js # Result: Only hashes and session IDs, no image data
Build from Source
Verify nothing is hidden:
# Clone repository
git clone https://github.com/yourorg/qwip
cd qwip
# Install dependencies
cd qwip-extension
npm install
# Build extension
npm run build
# Load into Chrome
# chrome://extensions → Load unpacked → Select dist/ folderCompare with Chrome Web Store version:
- Check file sizes match
- Verify no additional tracking code
- Review manifest.json permissions
9. Security Audits
Current Status (v1.0)
Internal Review: ✅ Complete
- Code review by development team
- Automated security scanning (npm audit, Snyk)
- Manual penetration testing (basic)
Third-Party Audit: 🚧 Planned for Q1 2026
- Professional security firm
- Full code audit
- Penetration testing
- Public report
Automated Security Scanning
Current Tools:
# Run security scans
npm audit # Check for vulnerable dependencies
npm run security-check # Custom security linting
# Results (as of Dec 2025):
# 0 critical vulnerabilities
# 0 high vulnerabilities
# 2 moderate (false positives, ONNX Runtime)Future Security Measures
Planned:
- 🚧 Bug bounty program (after funding round)
- 🚧 Regular penetration testing (quarterly)
- 🚧 SOC 2 Type II certification (2026)
- 🚧 ISO 27001 certification (2027)
10. Reporting Security Issues
Responsible Disclosure
Found a vulnerability?
Email: security@qwip.io
Include:
- Description of vulnerability
- Steps to reproduce
- Potential impact
- Your contact information (optional for credit)
GPG Key: [Available on website]
Our Commitment
| Timeline | Action |
|---|---|
| < 48 hours | Acknowledge receipt |
| < 7 days | Fix critical vulnerabilities |
| < 30 days | Fix non-critical vulnerabilities |
Security Researcher Credits:
- Public acknowledgment (with your permission)
- Hall of fame on website
- Future: Monetary rewards via bug bounty program
What Qualifies
In Scope:
- ✅ Extension code vulnerabilities
- ✅ Server API vulnerabilities
- ✅ Privacy leaks (data exposure)
- ✅ Authentication bypass
- ✅ SQL injection, XSS, CSRF
Out of Scope:
- ❌ Social engineering
- ❌ Physical attacks
- ❌ DoS/DDoS attacks
- ❌ Issues in third-party dependencies (report to them)
Best Practices for Users
How to Maximize Your Security
Install from Official Sources Only
- ✅ Chrome Web Store (verified publisher)
- ✅ GitHub releases (check signatures)
- ❌ Third-party websites (could be modified)
Review Permissions
- Extension only needs:
storage,activeTab - No broad permissions like
<all_urls>orhistory - Review on install and updates
- Extension only needs:
Keep Extension Updated
- Auto-update enabled by default (recommended)
- Check for critical security updates
- We'll notify you of important updates
Disable Server Features If Paranoid
- Settings → "Server-Assisted Detection" OFF
- Settings → "Contribute to Database" OFF
- Result: 100% local operation, zero network calls
Monitor Network Activity
- Use browser DevTools → Network tab
- Verify only
api.qwip.iorequests (if server enabled) - Inspect request payloads (only hashes, no images)
Report Suspicious Behavior
- Email security@qwip.io immediately
- Include screenshots/logs
- We take all reports seriously
Questions?
- Privacy questions: Data Collection Practices
- Legal questions: Compliance
- Security concerns: security@qwip.io
- General inquiries: hello@qwip.io
Security is a continuous process. We're committed to improving qwip's security posture and maintaining transparency about our practices.
Last Security Review: December 2025 | Next Review: March 2026