Skip to content

Security

Security overview

What Vukem does by default to protect applications, mapped to the OWASP Top 10:2025, and what remains your responsibility.

Last updated:

Vukem's security defaults are a design contract. Each default lands in a phase (P = Prototype, A = ALPHA, B = BETA) and is not "done" until a test named TestSecurity_<Category>_<Behaviour> asserts it. Report vulnerabilities in Vukem itself through the repository's security policy.

Principles#

  1. Secure by default, explicit to loosen. Unsafe behaviour needs an opt-out with a visible name (InsecureSkipX), never a missing opt-in.
  2. Fail closed. If a check cannot be performed (store down, key missing, policy not registered), the request is denied.
  3. Refuse to boot when misconfigured. Missing APP_KEY in production, debug in production, wildcard CORS with credentials: boot error, not a warning.
  4. Standard library crypto only. crypto/* and golang.org/x/crypto; no custom algorithms.
  5. Small dependency surface so supply-chain risk stays auditable.

Implemented today#

DefaultOWASP
Boot refuses a missing APP_KEY in production or with APP_ENV unset (with an explicit development/test, key-derived features fail closed on use) or a short one, APP_DEBUG=true in production and an invalid portA02
NewHTTPServer always sets read, write, header and idle timeouts and MaxHeaderBytesA02
SecureHeaders: CSP with per-request nonce, HSTS on HTTPS, nosniff, X-Frame-Options: DENY, COOP, Referrer and Permissions policiesA02
CORS deny by default; "*" with credentials refused at constructionA01 / A02
Static files through os.Root; dotfiles and directory listings never servedA01
c.Back and web.SafeRedirect ignore off-site targets (open redirect)A01
c.IP() honours X-Forwarded-For only from trusted proxiesA01
config.Secret redacts secrets in fmt, JSON, text and slogA04
APP_KEY sub-keys derived with HKDF-SHA256 per purposeA04
Request bodies capped (10 MiB default, BodyLimit per route); JSON trailing data rejectedA06
Request ids validated (safe characters, max 128) before loggingA09
Structured slog request logs; web.SecurityEvent logs security events at WARN, web.AuditEvent routine audit records at INFOA09
Central error handler; 5xx details never sent to clients unless debugA10
Recover converts panics to 500 and logs stacks server-side onlyA10

OWASP Top 10:2025 mapping#

A01 Broken Access Control (includes SSRF)#

DefaultPhase
Routes are public unless wrapped in auth.Required(); route:list shows the middleware of every routeP / A
Unregistered policy = deny; DenyAsNotFound() against IDOR enumerationA
Mass assignment impossible: models filled from explicit request structsP
CORS deny-by-default; * with credentials refusedP
Static files and uploads through os.Root; dotfiles never servedP
Signed URLs (HMAC, expiry)A
SSRF: httpclient.Safe() rejects loopback, private, link-local and metadata addresses after DNS resolutionA

A02 Security Misconfiguration#

DefaultPhase
Boot refuses insecure configurationP
Server timeouts always setP
Security headers on by default; strict CSP with noncesP / B
Debug details only in developmentP
vukem about prints effective security settings, secrets redactedP
Destructive commands require --force in productionP

A03 Software Supply Chain Failures#

Core depends only on the standard library and an allowlist; go.sum verification; govulncheck in CI, pre-push and weekly; Dependabot; releases with checksums and SBOM, signatures in BETA; depguard blocks non-allowlisted imports.

A04 Cryptographic Failures#

argon2id passwords (A); crypto/rand only; AES-256-GCM cookies with HKDF keys (P); hashed API tokens (A); constant-time comparisons; key rotation (B); config.Secret redaction (P).

A05 Injection#

Bound parameters only, identifiers validated against model metadata (P); allowlisted API query conventions (A); html/template auto-escaping (P); encoding/json escaping; no shell execution with user input; invalid UTF-8 and control characters rejected by the validator (P).

A06 Insecure Design#

Reviewed auth flows from install:auth / install:api (A); rate limits on login, reset and token issuance (A); body size limits on every route (P); transactions with rollback on error or panic (P).

A07 Authentication Failures#

Session id regenerated on login; cookies HttpOnly, Secure, SameSite=Lax, __Host-; idle and absolute timeouts (P); timing-safe credential checks, generic messages, throttling, token expiry and abilities (A).

A08 Software or Data Integrity Failures#

Signed and encrypted cookies (P); CSRF with http.CrossOriginProtection (P); signed URLs and webhook signature helper (A); queue payloads never deserialised by reflection (B); migrations tracked with checksums (P).

A09 Security Logging and Alerting Failures#

Structured request logs with request id (P); stable security events such as auth.login_failed, csrf.rejected, ratelimit.exceeded (P / A); secrets and Authorization/Cookie headers never logged (P); slog attribute encoding prevents log injection (P).

A10 Mishandling of Exceptional Conditions#

Central error handler (P); Recover middleware (P); fail closed on authorization, session and CSRF errors (P / A); RFC 9457 problems without internals (P); explicit 400/422 instead of silent zero values (P); timeouts and rate limits against resource exhaustion (P / A).

Your responsibility#

  • Terminate TLS (or run behind a proxy that does), set APP_URL to the https origin and set TRUSTED_PROXIES (plus TRUST_FORWARDED_PROTO=true behind a TLS-terminating proxy).
  • Authorize every handler that touches owned data and scope queries by tenant or user.
  • Keep running govulncheck, review dependency updates and protect CI secrets.
  • Ship logs to durable storage and alert on security events.