Skip to content

Security Practices

How qwip Protects Your Privacy and Secures the Infrastructure

Last Updated: December 2025


Table of Contents

  1. Architecture Security
  2. Cryptographic Guarantees
  3. Transport Security
  4. Server Infrastructure
  5. API Authentication
  6. Threat Model
  7. Incident Response
  8. Open Source Verification
  9. Security Audits
  10. 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 hash

Why It's Secure:

  1. One-way function - Cannot compute image from hash
  2. Information loss - 99.999% of image data discarded
  3. No rainbow table attacks - Same image → different hash with different algorithms
  4. 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:

PropertyDescriptionSecurity Guarantee
Pre-image resistanceGiven hash, cannot find original image✅ Computationally infeasible
Second pre-image resistanceGiven image1, cannot find image2 with same hash✅ Collision-resistant
Avalanche effect1 pixel change → completely different hash✅ Yes

Example:

javascript
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:

javascript
// 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):

javascript
// 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:

ComponentTechnologyPurpose
ApplicationFlask (Python)API endpoints
DatabaseSQLitePersistent storage
CacheRedisReal-time metrics
Web ServerGunicorn (4 workers)WSGI server
ContainerDockerIsolation
OrchestrationDocker ComposeMulti-service

Security Measures:

MeasureImplementationStatus
Secrets managementEnvironment variables (.env)✅ Active
Database encryptionSQLite file permissions (600)✅ Active
No public DB accessFirewall rules✅ Active
Rate limitingPlanned (Nginx)🚧 Planned
Request validationFlask schema validation✅ Active
SQL injection protectionParameterized queries✅ Active

Example Secure Query:

python
# ✅ 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 planned

Why 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

javascript
// 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)

javascript
// 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 ✅

ThreatProtectionEffectiveness
Image interceptionNever transmitted✅ 100%
User trackingAnonymous session IDs✅ High
Data breach impactNo personal data stored✅ Very low risk
Man-in-the-middle (MITM)TLS 1.3 encryption✅ High
Database exposureOnly hashes, not images✅ Low impact
SQL injectionParameterized queries✅ Protected
XSS attacksContent Security Policy✅ Protected
CSRF attacksNo cookies, stateless API✅ N/A

What We DON'T Protect Against ❌

LimitationReasonMitigation
Local malware on your deviceOutside our controlUser responsibility (antivirus)
Browser extensions reading memoryBrowser security issueChrome Web Store review process
Physical access to deviceUser responsibilityEncrypt your device
Compromised browserOutside our scopeKeep 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:

  1. Immediately notify all users via extension update
  2. Rotate any API keys
  3. Publish transparency report
  4. 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):

  1. Contain: Shut down affected servers
  2. Assess: Determine scope of breach
  3. Notify: Email all users (via extension update notification)
  4. Preserve: Forensic evidence for investigation

Within 7 Days:

  1. Publish detailed transparency report
  2. Notify relevant authorities (if required by law)
  3. Implement fixes to prevent recurrence
  4. Third-party security audit

Long-term:

  1. Enhanced security measures
  2. Regular penetration testing
  3. 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:

  1. No image uploads:

    bash
    # Search entire codebase for image uploads
    grep -r "fetch.*blob" qwip-extension/
    # Result: Only hash-related fetches, no image uploads
  2. Session ID generation:

    bash
    # View session ID code
    cat qwip-extension/server-api.js | grep -A 5 "randomUUID"
    # Result: Uses crypto.randomUUID() (browser built-in)
  3. 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:

bash
# 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/ folder

Compare 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:

bash
# 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

TimelineAction
< 48 hoursAcknowledge receipt
< 7 daysFix critical vulnerabilities
< 30 daysFix 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

  1. Install from Official Sources Only

    • ✅ Chrome Web Store (verified publisher)
    • ✅ GitHub releases (check signatures)
    • ❌ Third-party websites (could be modified)
  2. Review Permissions

    • Extension only needs: storage, activeTab
    • No broad permissions like <all_urls> or history
    • Review on install and updates
  3. Keep Extension Updated

    • Auto-update enabled by default (recommended)
    • Check for critical security updates
    • We'll notify you of important updates
  4. Disable Server Features If Paranoid

    • Settings → "Server-Assisted Detection" OFF
    • Settings → "Contribute to Database" OFF
    • Result: 100% local operation, zero network calls
  5. Monitor Network Activity

    • Use browser DevTools → Network tab
    • Verify only api.qwip.io requests (if server enabled)
    • Inspect request payloads (only hashes, no images)
  6. Report Suspicious Behavior

    • Email security@qwip.io immediately
    • Include screenshots/logs
    • We take all reports seriously

Questions?


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

Open source and privacy-first