# Security Hardening Changelog

## Release: 1.9.1

This release continues the security/maintenance pass over the purchased WhatsApp Gateway source. The original source is preserved separately as the rollback baseline.

### Authentication & session security

- Added `User.TokenVersion`.
- JWTs carry `token_version` and are invalidated after password changes/resets.
- Deactivated users remain blocked even when an old JWT is presented.
- Email verification links expire after 24 hours and are single-use.
- Password reset links expire after 1 hour and are single-use.
- Password reset and email verification bearer tokens are now stored as SHA-256 hashes; legacy plaintext tokens remain readable only for migration compatibility.
- Added database-backed throttling for forgot-password and resend-verification endpoints.

### REST API key protection

- Newly created API keys are stored as SHA-256 hashes.
- Legacy plaintext API keys migrate to hash storage after successful use.
- Only a non-secret key prefix/hint is exposed to the dashboard.
- API query-string authentication is disabled by default (`API_ALLOW_QUERY_TOKEN=false`) because URLs are commonly recorded by logs, browser history, proxies, and analytics.
- Legacy integrations can temporarily enable the flag while migrating to `Authorization: Bearer <API_KEY>`.
- Existing per-agent token-bucket rate limiting remains enabled.

### Webhook security

- Webhook delivery uses the shared public-network HTTP client with DNS validation and dial-time IP pinning.
- Private, loopback, link-local, multicast, unspecified, CGNAT and other non-public destination IPs are rejected.
- Webhook secrets generated by the secured release are encrypted at rest using the existing AES-256-GCM secretbox.
- Existing plaintext webhook secrets remain backward compatible.
- Webhook delivery now sends additive V2 signature headers:
  - `X-Signature-Version: 2`
  - `X-Signature-Timestamp: <unix>`
  - `X-Signature-V2: sha256=<HMAC(timestamp + "." + payload)>`
- The original `X-Signature` header remains for backward compatibility. Receivers should migrate to V2 and reject stale timestamps to obtain replay protection.
- Test webhook and runtime webhook delivery both use the decrypted secret only in memory.

### SSRF / outbound HTTP hardening

- Added `backend/services/public_http.go` as the shared guard for user-controlled HTTP(S) requests.
- DNS answers are validated and the actual TCP connection is pinned to a validated public IP.
- Redirect targets are validated again.
- Embedded URL credentials are rejected.
- Applied to API media downloads, AI link enrichment, link previews, and webhook delivery.

### AI / privacy hardening

- Removed raw customer message and raw AI reply content from production AI logs.
- AI logs now use short SHA-256 fingerprints plus lengths/metadata so operators can correlate repeated events without storing conversation text in normal logs.
- Existing diagnostic/simulation persistence keeps its metadata-only default and credential redaction behavior.

### Browser security

Added low-risk global headers:

- `X-Content-Type-Options: nosniff`
- `X-Frame-Options: DENY`
- `Referrer-Policy: strict-origin-when-cross-origin`
- `Permissions-Policy`
- `Cross-Origin-Opener-Policy`
- HSTS in production

No CSP was added blindly; the frontend needs a dedicated CSP compatibility pass before enabling one.

### Database / operations

- MySQL connection pool limits remain configurable through environment variables.
- Production environment template uses a dedicated database account instead of `root`.
- Added production preflight validation.
- Added a minimal unauthenticated `/api/healthz` endpoint for process/database monitoring without exposing application data.
- Added a production build script that produces a backend binary plus `frontend/dist` after dependencies and tests are available.
- Added production installation/rollback documentation.

### License architecture

The license subsystem remains intact in this release. A separate `LICENSE-ARCHITECTURE-REVIEW.md` documents the current remote verification/heartbeat dependency and the discrepancy between the buyer-provided certificate and the source package's own license/EULA wording. No silent entitlement bypass was introduced.

## Validation

- Modified Go files formatted with `gofmt`.
- SSRF/public-IP guard has an independent unit test from the previous secured pass.
- Frontend and backend full builds require the exact declared toolchains and dependency installation.
- The audit environment has Go 1.23.2 while the project requires Go 1.25.8; automatic toolchain download is blocked by the environment's DNS/network policy.
- Frontend dependency installation is also unavailable in the audit environment, so the final production build must be executed on the deployment/build server.
