# Security boundaries

- Uploaded files receive random UUID `.bin` names outside the document root. Original names are metadata only. Content is hashed; no upload is executed or served to visitors.
- A root-owned, non-login scanner account accepts a tiny JSON protocol over a group-restricted Unix socket. It validates file UUIDs, opens relative to a fixed directory with `O_NOFOLLOW`, rejects nonregular/hard-linked/oversized files, and passes an open FD to the real scanner binary. Scanner commands are argument arrays, never shell commands. Output, CPU, runtime, archive recursion/file counts and child concurrency are bounded.
- Scanner systemd isolation removes network/device access, capabilities and writable host/source paths. Quarantine is read-only to the service. The Laravel queue worker uses the cPanel account, has bounded memory and no privilege escalation, and reaches only configured services via its application code. Validate actual kernel/SELinux/group behavior on the VPS.
- Public URL input is restricted to HTTP(S), ports 80/443, no credentials/fragments/control characters, and public IP/DNS results. Mixed private/public DNS answers are rejected. IPv4 special ranges and IPv6 local/mapped/transition addresses are rejected. Crucially, this server never opens target URLs or follows their redirects; only a validated string is sent to VirusTotal. The provider's own fetch behavior is its responsibility. If adding local fetching later, implement DNS pinning and validate every redirect before enabling it.
- API origins are fixed and provider HTTP redirects are disabled. Provider credentials use encrypted casts and hidden serialization. Editing forms never rehydrate existing keys/passwords. Audit records contain changed field names, not old/new secret values.
- Policies enforce owner/session access for report pages, JSON endpoints, exports and deletion. Expired reports are denied. Registration cannot mass-assign admin or plan fields. Admin panel access requires a verified, unsuspended administrator. The web layer applies CSRF to state changes except the signature-verified Stripe webhook.
- Passwords are hashed; login attempts and submissions are throttled. Sessions regenerate on login and invalidate on logout/suspension. Verification links are signed/expiring; reset tokens use Laravel's broker. Email notifications are queued and encrypted. HTTPS secure/HTTP-only cookies must be enabled in production.
- Quota buckets use transactional row locking and unique keys, with actual MySQL concurrency tests. Plan/price selection is server-side. Signed Stripe events are stored once and reconciled against the API's canonical subscription/customer/price, rather than granting from a browser return URL or event status alone.
- Blade escaping and Alpine `x-text` avoid HTML rendering of target/provider strings. CSV formula prefixes are neutralized. No safety guarantee is inferred from missing/error/undetected results.

## Deliberate limitations and launch gates

This is application hardening, not an independent penetration-test certificate. Browser interaction/responsiveness/accessibility needs live review. Admin MFA, WAF/DDoS controls, mail reputation, host patching, host malware monitoring, full content-disarm/reconstruction and malware detonation are not included. Filament/Alpine use their framework script behavior; a custom strict CSP is not imposed without testing compatibility. Security headers are supplied for the public app; also apply host-level headers to static assets/admin responses as appropriate. Never disable browser/framework protection to resolve a test failure.

No live external API credentials, bank payments, delivery inbox, target WHM instance or enforced SELinux policy was available during this build. The build environment disallowed Unix sockets, so the actual socket service handshake is an explicit unpassed acceptance gate, even though direct binary detection and path-boundary tests passed. See ACCEPTANCE.md.

## Browser installation boundary

The standalone wizard works before Laravel has configuration. A private per-package setup key, HTTPS, a separate strict session, CSRF tokens, login throttling and an exclusive installation guard protect it. Existing `.env` or installation lock disables access; existing external APP_KEY configuration disables the public wizard as well. Connection fields are validated against DSN/configuration injection, .env values are serialized and round-trip parsed without variable interpolation, and secrets are not redisplayed. A first attempt requires an empty database; a private fingerprint/key checkpoint permits only its own same-database retry. The installer executes Laravel migrations and seeders through the framework, never a shell/root package command. It creates an owner administrator, atomically publishes a mode-0600 configuration without overwriting any existing .env, deletes setup keys and locks itself. Browser installation is not a production acceptance certificate.
