This page is what we do for security at WeSearch and how to report vulnerabilities. The honest baseline: WeSearch is a single-droplet single-developer project, and we don't claim enterprise-grade security posture. We do claim a small attack surface (we don't have data worth a major attack on), aggressive minimization, and a clear disclosure path.
What we hold
The set of data WeSearch can lose is intentionally small. We do not hold:
- Real names, email addresses (by default), addresses, or phone numbers.
- Credit card data (Stripe handles donation processing in its own iframe; we never see the card).
- A reading-history or behavioral profile tied to your reader key and used for ads or news ranking. Operational page measurement is disclosed separately.
- BYOK upstream-provider credentials (those forward through; we don't persist).
We do hold:
- Hashed local API keys (cannot be reversed to find the original key).
- Public comments and reactions linked to those hashes.
- Optional email-recovery hashes (if a user opted in).
- Push-subscription endpoints (opaque vendor URLs, no identity).
- Server access logs (IP + user-agent + path), rotated within 30 days.
How identity is protected
The local API key is sent over HTTPS in the Authorization header when you authenticate. The server hashes it on receipt, compares it with the stored SHA-256 value, and never persists the plaintext.
This means: even if our database were exposed, an attacker would have hashed keys and would have to brute-force each one to find the originals. The keys are 32 bytes of crypto-random hex, so brute-forcing is computationally prohibitive.
Application-layer hardening
- Hono
secureHeaders()middleware sets X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, X-XSS-Protection, and Strict-Transport-Security on every response. - CORS is configured per-route. The public read API allows cross-origin reads with rate limits; auth endpoints are tighter.
- Per-key rate limiting on comment posts, reactions, and notification fanout to prevent flood-style abuse.
- Input validation via Zod schemas on every endpoint that takes input.
- SQL via Drizzle ORM with parameterized queries. We don't construct queries via string concatenation.
- Server-side HTML escaping on all user-generated comment content.
Infrastructure-layer hardening
- fail2ban active, banning IPs that hit auth-failure thresholds.
- UFW firewall open only on the ports we serve (22 SSH, 80/443 HTTP/HTTPS).
- SSH key-only auth. Password auth is disabled.
- TLS via Let's Encrypt with auto-renewal.
- nginx as a reverse proxy in front of the Hono service, with standard hardening.
- Backups daily, encrypted, retained 30 days, stored separately.
What's deliberately NOT in our stack
- Advertising pixels and programmatic-ad SDKs—fewer JavaScript surfaces means fewer attack vectors. Limited operational analytics are disclosed separately.
- Payment data — Stripe handles all donation processing; we never see card data.
- Deliberate device fingerprinting or ad-retargeting identifiers. Delivery and analytics providers may still use their own cookies or similar identifiers as disclosed.
- Excessive admin-panel surface — there's one /admin page with strong cookie-secret auth.
Vulnerability disclosure
If you find a vulnerability:
- Email [email protected] (or /support with "SECURITY" in the subject).
- Include reproduction steps, the affected URL, and the impact you've assessed.
- Don't publicly disclose for at least 30 days while we work on a fix.
- We'll acknowledge within 24 hours, fix within a reasonable window for the severity, and credit you in this page's changelog if you want.
We don't currently run a paid bug-bounty program — we're a donation-funded project and the budget isn't there. We're happy to credit researchers and link to their disclosure write-ups after the fix lands.
Incidents
None to date. If a security incident occurs that affects user data, we'll publish a post-mortem on this page and notify any affected users via the email address they optionally provided for recovery.
Threat model in plain English
Our security work is shaped by what we hold and what an attacker might want. Since we don't store payment data, real names, addresses, phone numbers, or behavioral profiles, the value of compromising WeSearch is low — there's no card-data trove, no identity-theft surface, no dossier worth selling. The realistic attacker scenarios are: (a) someone who wants to deface or take the site offline (mitigated by infrastructure hardening, backups, and a static-fallback strategy); (b) someone who wants to abuse the API for bulk scraping or amplification (mitigated by rate limiting, fail2ban, and Cloudflare-tier filtering); (c) someone who wants to inject content into comment threads (mitigated by escaping, validation, and active moderation); (d) someone who wants to de-anonymize a specific commenter (mitigated by the hashed-key model, no email-by-default, and access-log rotation).
We don't pretend to be unhackable. We do design for graceful degradation — if a particular subsystem is compromised, the blast radius is small, and the data that an attacker could extract is intentionally less valuable than what they'd need to justify the effort.
What you can do as a reader
- Use a strong unique key. The local API key is generated automatically; don't share it across devices via insecure channels.
- Skip email recovery if you don't need it. If you don't enable email recovery, we hold zero-bytes of identifying data on you beyond the comments you choose to post.
- Use HTTPS only. The site only serves HTTPS; we redirect HTTP. If your browser accepts an HTTP version of WeSearch, something is wrong.
- Verify the certificate. The certificate is via Let's Encrypt. Browser warnings about cert issues should be taken seriously.
- Report suspicious behavior. If you see a comment thread that looks compromised (mass-bot output, account takeover) email [email protected].
Frequently asked
Do you have a SOC 2 / ISO 27001 attestation?
No. We're a small donation-funded project; formal attestations are expensive and not warranted by our scope or data.
Can I see the source code?
The project's source is publicly readable. Contact via support if you'd like a security review or want to contribute hardening patches.
What if my key gets compromised?
Reset your local key in Settings; the old key's hash and any associated comments stay public under the old handle, but the new key creates a new identity. There is no "account recovery" because there is no account in the traditional sense.
Do you log IP addresses?
Yes—server access logs include IP, user agent, and path and rotate within 30 days. We do not deliberately join them into a reader profile, but timestamps and request metadata can sometimes be correlatable.