Skip to content

Security principles

Anvil is designed for environments that are audited, e.g. against ISO/IEC 27001. A library cannot be certified on its own, but it can provide the technical controls an audit expects and make the secure way the easy way.

  1. Security
  2. Performance
  3. Stability

When these goals conflict, the higher one wins.

Principle Implementation
Deny by default The gate denies unknown permissions. Every endpoint action and API endpoint needs a permission. Tenant scoped data fails closed without a tenant.
No internal identifiers on the client Only UUIDs leave the server (Config\Anvil::$internalFields), see data rules.
The client knows nothing about the server One endpoint per panel with encrypted, session bound tokens; no class names in requests.
Least privilege Permissions are generated per panel, resource, action, relation action, export and page (php spark anvil:permissions); roles grant them per tenant, see Users and roles. Policies restrict single records.
Traceability Every change and every security event is written to a tamper evident audit log.
Purpose bound keys All keys are derived from encryption.key via HKDF, one per purpose (Anvil\Security\KeyRing); the key must have at least 32 bytes and can be rotated (encryption.previousKeys, anvil:rekey). The audit log can have a key of its own.
No third-party CDNs All assets (CSS, JS, fonts, Chart.js) are bundled and served by the application with integrity hashes, see Styling.
Strict CSP No inline scripts, event attributes or style attributes; htmx without eval, Alpine in its CSP build, see Styling.
Secure defaults Insecure options must be enabled explicitly and are documented as such.
Area Protection
Headers Panel pages and endpoint answers carry X-Frame-Options: DENY, X-Content-Type-Options: nosniff and Referrer-Policy: same-origin (Anvil\Security\SecurityHeaders); headers set by the application are kept, and CodeIgniter’s secureheaders filter, which runs later, turns the frame header into SAMEORIGIN. Framing by other sites is refused by the CSP (frame-ancestors 'none'), so keep the CSP enabled. CSP and HSTS stay with the application, see Deployment and Styling.
Rate limits Component endpoint: Config\Anvil::$endpointRateLimit (120 per minute and IP); single sign-on: 30 per minute and IP; API: $apiRateLimit per client and $apiIpRateLimit per IP. Exceeded limits answer 429 and are recorded as security events.
Login Two-factor authentication with lockout, single sign-on with signed tokens and assertions, panels restricted to login methods (Panel::authMethods()).
Escalation Users can only grant permissions they hold themselves, see Users and roles.
Links and redirects Redirects of components only accept relative, same-origin paths (Anvil\Support\SafeUrl). External links only lead to the systems in Config\Anvil::$links, over HTTPS and with noopener unless a system is trusted (Anvil\Support\Link).
Uploads Allowed types are checked against the content, files are stored outside the web root and can be scanned for viruses, see Files.
API Hashed tokens, IP allow lists, optional request signatures, expiry and review notices, see API.

Do not open a public issue. Report vulnerabilities by e-mail as described in SECURITY.md of the repository.