Tested Security Features
Comprehensive list of security features covered by automated tests
On this page
This document lists all security features that are covered by automated tests in SveltyCMS.
Security Policy: SveltyCMS follows a strict no-backdoor policy. All security tests must pass through real security guards without any mocked permission checks or test bypass mechanisms.
Overview
SveltyCMS has comprehensive security test coverage across multiple test suites:
- Unit Tests: ~180+ tests for middleware and utilities
- Integration Tests: ~80+ tests for API endpoints
- E2E Tests: ~40+ tests for user flows
Security Vulnerabilities Fixed
1. Localhost Rate Limit Bypass (Protected March 2026)
Issue: Localhost (127.0.0.1, ::1) was exempt from rate limiting, allowing SSRF attacks to bypass rate limits.
Fix: Restricted localhost exemption to dev mode or TEST_MODE=true integration tests in src/hooks/handle-rate-limit.ts. In production builds, all requests are rate-limited regardless of source IP.
Tests: tests/unit/hooks/rate-limit.test.ts
2. Firewall Bypass (Protected March 2026)
Issue: Setting TEST_MODE=true would completely bypass the firewall security checks.
Fix: Restricted TEST_MODE bypass in src/hooks/handle-security.ts:167 to local requests only and to explicit test environments — if (isLocal && IS_TEST_MODE && !forceSecurity) return resolve(event). A validated x-test-secret alone is not sufficient, so benchmark runs still exercise the full WAF/firewall path. In production, the firewall is always active unless explicitly disabled via settings.
Tests: tests/unit/security/handle-waf-guard.test.ts, tests/unit/hooks/defense-in-depth.test.ts
3. Missing POST-Authentication Authorization Gap (Resolved April 2026)
Issue: Authenticated users could access various /api/ endpoints within their tenant without granular permission checks.
Fix: Implemented a Fail-Closed API Dispatcher in src/routes/api/[...path]/+server.ts using an exhaustive ENDPOINT_PERMISSIONS mapping. Any route not explicitly authorized is denied by default.
Tests: tests/unit/hooks/authorization.test.ts, tests/unit/api/dispatcher-body-limit.test.ts, tests/unit/api/dispatcher-security-matrix.test.ts
UI: Added “Access Denied” feedback logic in user-management.svelte to handle 403 status codes.
4. September 2026 Enterprise Security & Performance Hardening
Assessment Outcome: Enhanced A++ Enterprise Security with constant-time cryptographic normalization, AST-level batch size verification, and reverse-proxy spoof-proofing.
Hardened Defenses & Fixes (September 2026) {#september-2026-hardened-defenses}
- Timing-Attack Defense on Login (CWE-208): Neutralized user enumeration by executing
verifyDummyPassword()against a pre-computed Argon2id hash (DUMMY_ARGON2_HASH) inAuthNamespace.loginwhenever a user is not found. Response latency for invalid accounts matches valid-user password hashing (~50–80ms). - Reverse Proxy IP Spoofing Elimination: Enforced
getClientIp(event)across all authentication hooks, password reset flows, audit logging, and WebSocket rate limits. Direct access to rawX-Forwarded-Forheaders is blocked and scanner-enforced viascripts/scan-security-risk.ts. - AST Batch Payload Guard (
batch-size-unbounded): Added context-aware AST security analysis inscripts/scan-security-risk.tsusing the TypeScript Compiler API. Inspects all API handlers for batch processing and asserts an upper-bound length assertion (<= 100) to prevent memory exhaustion and event loop starvation. - Non-Blocking Redis Key Scanning: Replaced synchronous, blocking
redis.keys()in dashboard metrics with non-blockingredis.scanIterator()and bounded counts, protecting Redis event-loop throughput under high load. - Deterministic SSR Hydration & Localization: Replaced render-time
crypto.randomUUID()in UI primitives with Svelte 5’s$props.id()rune, and consolidated 52+ unpinned date/number formatting call sites into@utils/format-datewith scanner enforcement (slop-scanner.ts). - API Error Handling Uniformity: Migrated all remaining handlers in
src/routes/api/[...path]/handlers/to the canonicalraise(status, message, code)pattern.
Tests: tests/unit/auth/timing-defense.test.ts, tests/unit/scripts/scan-security-risk.test.ts, tests/unit/scripts/slop-scanner.test.ts, tests/unit/hooks/ws-ratelimit.test.ts, tests/unit/utils/format-date.test.ts.
5. Native Field-Level Encryption at Rest (September 2026)
Control: Collection fields flagged encrypt: true are stored as AES-256-GCM envelopes (v1:iv:tag:ciphertext) using ENCRYPTION_KEY. Writes fail closed without the key. Tamper / AAD mismatch decrypts that field to null. Filter/sort on encrypted fields returns 400 ENCRYPTED_FIELD_NOT_QUERYABLE.
Tests: tests/unit/utils/field-encryption.test.ts, tests/unit/services/field-encryption-pipeline.test.ts, tests/unit/content/schema-contract.test.ts (encrypt+unique warning).
6. Collection Weak ETags & DB-free 304 (September 2026)
Control: Collection find/entry GET responses carry W/"cv1|{tenant}|{collection}|{epoch}|{reprHash}". Matching If-None-Match returns 304 before the handler (no DB). Epoch bumps on write; repr hash includes user id so publication/FLAC views do not cross-validate. refresh / nocache / bypassCache skip the 304.
Tests: tests/unit/services/collection-etag.test.ts.
7. August 2026 Lean-Code Security Assessment & Audit Remediation
Assessment Outcome: Maintained A++ Security Grade with self-healing isolation.
Hardened Defenses & Fixes:
- Multi-Tenant Test Gate (
T1): Gatedx-tenant-idandx-test-tenant-idheader resolution strictly toisTestMode, closing header-based tenant switching in production. - Permission Retention Elimination (
T2): Added theinvalidateRoleBitsetandsetRolePermissionshelpers insrc/databases/auth/permissions.tsto purge cached role bitsets. No role-edit path calls them yet, so automatic bitset invalidation on role edits is not active; wiring is tracked in the roadmap. - Cryptographic Content-ETag (
T15): Replaced timestamp weak ETags with content hashes (generateContentEtag), preventing false 304s on content updates and deletions. - Open Redirect Defense (
T25): CentralizedsafeRedirect()engine blocking protocol-relative URLs (//evil.com) and unvalidated domains. - Multi-Variant Session Cookie Purge (
T6): Consolidated multi-variant cookie revocation (__Host-,__Secure-, plain) insession-cookie.ts. - SQL
LIKEWildcard Escaping (T24): AddedescapeLikehelper escaping%,_, and\with explicitESCAPE '\\'. - Commerce Security Hardening (
T27,T28,T29,T33,T34):- Gated
variants/applyto admin callers. - Bound PaymentIntent ID directly to verified order records.
- Fail-closed order listing by customer identity.
- Capped variant matrix generation to 500 combinations to prevent Cartesian DoS attacks.
- Protocol-validated
trackingUrl(onlyhttps?://allowed).
- Gated
Tests: tests/unit/security/safe-redirect.test.ts, tests/unit/plugins/commerce.test.ts, tests/unit/databases/escape-like.test.ts, tests/unit/auth/sessions/session-cookies.test.ts.
8. April 2026 Security Assessment & Hardening
Assessment Outcome: Achieved A++ Security Grade.
Key Implemented Features:
-
✅ Robust Path Normalization: Hardened
src/routes/files/against directory traversal using strictpath.relativeboundary checks. -
✅ Fail-Closed Dispatcher Verification: Every unhandled route now strictly returns 403.
-
✅ Argon2id Memory-Hardness Audit: Confirmed 64MB memory cost for resistance against quantum/ASIC speedup.
-
✅ SHA-256 Audit Chaining: Implemented tamper-evident chaining for all file-backed security logs.
-
✅ Middleware Sequence Lockdown: Verified that security headers and firewall scan are executed before any logic layers.
-
✅ Resource Exhaustion Immunity (Load Shedding): Verified that mutation requests are rejected (503) when memory usage exceeds 90%, protecting read-availability.
-
✅ Graceful Shutdown: Confirmed clean teardown of DB and Cache connections on
SIGTERM. -
✅ Timing-Safe Cryptographic Handshake: Verified that
x-test-secretcomparison uses constant-time logic.
Tests: tests/benchmarks/security-audit.test.ts (added April 2026), tests/unit/security/handle-waf-guard.test.ts.
9. May 2026 Enterprise Security Hardening
Assessment Outcome: Defense-in-depth hardening across all API and page action layers.
Key Implemented Features:
-
✅ Cookie Prefix Enforcement:
__Host-prefixed cookies only accepted on secure connections. Insecure connections (localhost/dev) never accept prefixed cookies, preventing subdomain cookie tossing (src/hooks/handle-authentication.ts). -
✅ Setup Completion Gating: All
/api/setupendpoints blocked (403) after setup completes. Bootstrap route redirects enforced at middleware level (src/hooks/handle-system-state.ts,src/routes/api/[...path]/handlers/setup.ts). -
✅ Handler-Level Admin Verification:
handleSettingsRoutes,handleSystemMgmtRoutes, andhandleAutomationRoutesinsystem.tsnow verify admin status for all mutating operations. -
✅ Media Mutation Permissions: Defense-in-depth RBAC checks added to
handleMediaUpload(media:write) andhandleMediaPostDelete(media:delete) inmedia.ts. -
✅ Centralized Permission Guards:
requireCollectionBuilderPermission()helper eliminates duplicated authorization logic across all Collection Builder actions (src/routes/(app)/config/collectionbuilder/+page.server.ts). -
✅ Critical Bug Fixes: Restored missing
initSystemFastimport in setup seed flow. Fixed adapter disconnect-before-use race condition in setup completion handler.
Files Modified: src/hooks/handle-authentication.ts, src/hooks/handle-system-state.ts, src/routes/api/[...path]/handlers/setup.ts, src/routes/api/[...path]/handlers/system.ts, src/routes/api/[...path]/handlers/media.ts, src/routes/(app)/config/collectionbuilder/+page.server.ts, src/routes/(admin)/admin/tenants/+page.server.ts.
Tests: tests/unit/hooks/authentication.test.ts, tests/unit/hooks/authorization.test.ts, tests/unit/api/dispatcher-security-matrix.test.ts.
10. AI Bot Defense & Crypto Hardening
Assessment Outcome: Enhanced AI crawler defenses, zero-bias tokens, and cross-origin isolation headers.
-
AI Bot Detection: Proactive User-Agent fingerprinting blocks 28 known AI crawler/reconnaissance bot patterns in
src/hooks/handle-security.ts. -
Expanded Honeypot Grid: 45+ decoy routes (WordPress, Drupal, AWS metadata, config files) trigger IP blacklisting.
-
Honeypot IP Flagging + Response Poisoning: Immediate decoy 200 + IP flagging (no socket-holding tarpit) plus fake JSON payloads waste bot resources.
-
Cross-Origin Isolation Headers:
Cross-Origin-Opener-Policy,Cross-Origin-Embedder-Policy,Cross-Origin-Resource-Policyon all API responses insrc/hooks/handle-security-headers.ts. -
Zero-Bias Token Generation:
generateRandomTokenuses rejection sampling eliminating modulo bias insrc/databases/auth/constants.ts. -
Setup Session Cookie Fix: Consistent
__Host-prefix logic in setup handler (src/routes/api/[...path]/handlers/setup.ts).
Files: src/hooks/handle-security.ts, src/hooks/handle-security-headers.ts, src/databases/auth/constants.ts, src/routes/api/[...path]/handlers/setup.ts.
Tests: All 134 security regression tests pass.
11. Comprehensive Security Audit & Hardening
Assessment Outcome: Closed 6 security gaps identified through full-stack codebase audit against dependency stack, security architecture docs, and CVE landscape.
Key Implemented Features:
-
✅ SVG Polyglot Upload Sanitization: Server-side
sanitizeSvg()function strips script tags, foreignObject elements, inline event handlers, javascript:/data: URIs, CDATA blocks, XML PIs, and DOCTYPE declarations from uploaded SVG files before storage (src/utils/media/media-service.server.ts). -
✅ SVG large-file streaming bypass fixed: SVGs always take
bufferAndSanitizeSvg(never the ≥5MB pure-stream path).MAX_SVG_BYTESrejects oversized SVGs. File server adds CSPscript-src 'none'forimage/svg+xmlresponses. -
✅ User attribute privilege escalation fixed:
handleUpdateUserAttributesRouterequires auth, restricts non-admins to self, and stripsrole/isAdmin/permissions viastripPrivilegedUserFields(src/utils/security/user-attribute-policy.ts). -
✅ User creation privilege escalation fixed:
POST /api/user(bare namespace root) no longer inherits the auth path exemption — the dispatcher requiresuser:writefor creates anduser:readfor listings (GET /api/user), matching the strictPOST /api/user/create-usersibling; bareGET /api/authstays a named self-service read, and public login/2FA/OIDC/SAML actions remain exempt. Non-admin create payloads are stripped ofrole/roles/isAdmin/roleIds/permissionsviasanitizeClientUserAttributePatch(src/routes/api/[...path]/handlers/auth.ts). Coverage:tests/unit/api/rbac-endpoint-integration.test.ts,tests/unit/api/user.test.ts,tests/unit/security/user-attribute-policy.test.ts. -
✅ Token namespace positive allowlist:
/api/token/*no longer inherits a public-route deny-list — onlyGET /api/token/validate-token/{value}is public. List/create/resolve/batch andPUT/DELETErequire an admin session or the mappedapi:tokenpermission (Website Tokens stay admin-only), unauthenticatedGET /api/token/{value}returns 401, andPUT /api/token/{id}is field-allowlisted toexpires/blocked/consumed(admins additionallyemail/role; neveruser_id,type,token,_id,tenantId). Coverage:tests/unit/api/token.test.ts,tests/integration/api/token.test.ts,tests/unit/api/authz-bypass-guard.test.ts. -
✅ GraphQL APQ hash binding:
extensions.persistedQuerykeys must be exactly 64 hex characters andsha256(query)is compared withtimingSafeEqualbefore the query is registered, so a client cannot plant a query under a hash another client will request (PERSISTED_QUERY_HASH_INVALID/PERSISTED_QUERY_HASH_MISMATCH). Coverage:tests/unit/api/graphql-apq.test.ts. -
✅ Central page-size ceiling:
MAX_PAGE_SIZE = 200in@utils/api-paramsclamps REST parsers, the SDKfindfunnel and the GraphQL fast path + resolver, so a client-suppliedlimitcan no longer reach adapters unbounded. Coverage:tests/unit/utils/api-params.test.ts,tests/unit/core/page-utils.test.ts,tests/unit/graphql/fast-path.test.ts. -
✅ Uniform 15 MB body ceiling (chunked included) and incremental media abort: the dispatcher counts
Transfer-Encoding: chunkedbodies through a zero-copy stream and stops atAPI_MAX_BODY_SIZE_BYTES(15 MB) exactly likeContent-Lengthbodies (413PAYLOAD_TOO_LARGE); the media stream route passes the same cap toparseMultipartStreamand aborts oversize parts incrementally instead of buffering. Coverage:tests/unit/api/dispatcher-body-limit.test.ts,tests/unit/media/streaming-upload.test.ts. -
✅ Authorization bypass guardrail suite:
tests/unit/api/authz-bypass-guard.test.ts(27 tests) enumerates every/api/<namespace>root and every public-route exemption against a reasoned contract, so a new authorization bypass fails a unit test instead of shipping. -
✅ Remote media upload SSRF fixed: Gallery remote upload uses
MediaService.saveRemoteMedia→validateEgressUrl+safeFetch(private IPs, localhost, metadata, DNS rebinding, redirect re-validation). -
✅ S3 Endpoint SSRF Prevention:
validateS3Endpoint()blocks private IP ranges (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16), IPv6 loopback/link-local, cloud metadata hosts, and non-HTTP protocols before S3Client creation (src/utils/media/storage-adapters.ts:42). -
✅ Ollama RAG Prompt Injection Defense: Remote knowledge-base context relocated from
systemtousermessage role with<rag_context>XML delimiters. Control characters stripped from RAG results. System prompt hardened with explicit instruction-override rejection (src/services/core/ai-service.ts). -
✅ GraphQL Introspection Explicit Blocking:
NoSchemaIntrospectionCustomRuleadded to production validation plugin, preventing unauthenticated schema enumeration (src/routes/api/graphql/+server.ts). -
✅ Tiptap Link Protocol Hardening:
Link.configure()now enforces protocol allowlist["http", "https", "mailto", "tel"], blockingjavascript:anddata:URI injection at editor level (src/widgets/core/rich-text/tiptap.ts). -
✅ Rate Limiter Dependency Hygiene: Moved
sveltekit-rate-limiterfromdevDependenciestodependenciesto ensure production build inclusion (package.json).
Files Modified: src/utils/media/media-service.server.ts, src/utils/media/storage-adapters.ts, src/services/core/ai-service.ts, src/routes/api/graphql/+server.ts, src/widgets/core/rich-text/tiptap.ts, package.json.
Tests: All 64 defense-in-depth security regression tests pass. 0 lint errors. 0 type errors.
12. Performance Sprint — Security Preservation
Assessment Outcome: 19-file multi-phase performance optimization sprint completed with zero security regressions. All 4 defense-in-depth layers preserved. 70/70 regression tests pass.
Key Security-Preserving Changes:
- ✅ Fire-and-Forget Audit Logging: Audit context (
userId,tenantId,path,method) captured beforeawait resolve(event). Log written in detachedPromise.resolve().then(...)— no blocking writes on the mutation hot path. SHA-256 chain integrity preserved (src/hooks/handle-audit-logging.ts). - ✅ Turbo Auth Skip Guard:
__turboAuthflag prevents duplicate audit on turbo-served mutations without bypassing any auth checks. Turbo path still requires valid session + absolute-expiry auth cache (src/hooks/handle-turbo-get.ts). - ✅ Hook Timing Gate:
HOOK_TIMING_ENABLEDgate disables per-request instrumentation in production. No security hooks are skipped — only timing/tracing overhead is removed (src/hooks.server.ts).
13. August 2026 Security & Cookie Parity Hardening
Assessment Outcome: Full cookie flag alignment, non-fatal transaction isolation, and translation catalog integrity verification.
- ✅ Logout Cookie Attribute Parity:
clearSessionCookies()insrc/routes/api/[...path]/handlers/auth.tsexplicitly enforces matchingpath: "/",httpOnly: true,sameSite, andsecuredeletion flags aligned withsetSessionCookie(). - ✅ Transaction Read Isolation: PostgreSQL and MariaDB
transaction-module.tsadapters respectrollback: false, ensuring non-fatal query misses do not abort outer transactions. - ✅ Media Stream Abort Teardown: Attached
request.signalabort listener to destroyed file streams on HTTP client disconnects (src/routes/api/[...path]/handlers/media.ts). - ✅ Translation Catalog Integrity: Automated
scripts/check-translations.tschecks locale JSON files insrc/messages/for key parity, empty values, and duplicate catalog keys.
Files Modified: src/routes/api/[...path]/handlers/auth.ts, src/databases/postgresql/transaction-module.ts, src/databases/mariadb/transaction-module.ts, src/routes/api/[...path]/handlers/media.ts, scripts/check-translations.ts.
Tests: tests/unit/routes/cookie-logout.test.ts, tests/unit/databases/transaction-read-isolation.test.ts.
- ✅ Pre-Compressed Cache: Compression utilities operate on response bodies only — never touch authentication, authorization, or input validation. No bypass paths introduced.
- ✅ Batch Relational Upserts:
setMany+bulkUpdateuse parameterized Drizzle ORM queries — no SQL injection risk. Tenant isolation preserved via existingtenantIdscoping. - ✅ CDN Purge Fast-Path: Cached
_cdnActiveflag reduces invalidation overhead without changing the purge security model. Fire-and-forget Cloudflare API calls unchanged. - ✅ OpenAPI Pre-Warm:
generateFullSpec()uses existing admin-gated endpoint. No new API surface. No permission bypass.
Security Tests: All 70 defense-in-depth regression tests pass across 4 files (defense-in-depth.test.ts, authentication.test.ts, authorization.test.ts, role-permission-access.test.ts). 0 regressions from any hook, cache, or adapter change.
Files Modified: src/hooks.server.ts, src/hooks/handle-compression.ts, src/hooks/handle-turbo-get.ts, src/hooks/handle-api-requests.ts, src/hooks/handle-audit-logging.ts, src/hooks/handle-local-context.ts, src/databases/cache/cache-service.ts, src/databases/core/relational-content.ts, src/databases/core/relational-system.ts, src/databases/postgresql/adapter-core.ts.
14. Threat Modeling & Gating Hardening
Assessment Outcome: Resolved critical race conditions in setup gating and corrected CSRF constraints for stateless external API integrations.
- Setup Wizard DB-Level Fallback Gate: Implemented a deep unseeded database validation check in
handleSeedDatabaseandhandleCompleteSetup(src/routes/api/[...path]/handlers/setup.ts). Before seeding or completion, the handler queries the database to check if any user with theadminrole is already registered. If present, it throws a403 SETUP_ALREADY_COMPLETEerror. This blocks setup hijacking attempts even ifconfig/private.tsis deleted or corrupted on the server filesystem. - CSRF Bypass for Header-Authenticated APIs: Updated SveltyCMS dispatcher in
src/routes/api/[...path]/+server.tsto bypass CSRF token validation if the request is authenticated viauser.isApiKeyoruser.isApiToken. Cookie-based admin dashboard sessions remain fully protected, while decoupled integration clients can execute write operations cleanly. - Vite Compilation OOM Protection: Configured chunk-splitting in
vite.config.tsto outputdrizzle-ormin a dedicated bundle, preventing Vite/rollup compiler memory exhaustion on low-memory servers.
Security Tests: Added unit and integration tests confirming deep setup wizard gating and CSRF token bypass on Bearer auth. All 65 defense-in-depth regression tests pass successfully.
Files Modified: src/routes/api/[...path]/handlers/setup.ts, src/routes/api/[...path]/+server.ts, vite.config.ts.
15. Global Security Risk Audit & Pre-Auth Fixes (August 2026)
Assessment Outcome: A global static risk audit now runs on every commit, and the first full-src/ pass found and fixed two pre-authentication vulnerabilities.
New commit gate (.githooks/pre-commit → bun run risk:audit, ~5s):
scripts/security/scan-security-risk.ts— global static scan of the entiresrc/tree (2917 files): SQL value/concat interpolation across all 4 adapters, MongoDB$where/$function/$accumulator,eval(/new Function(sinks, shell command interpolation, fs path interpolation, SSRF on request-derived URLs, DOM XSS sinks, regex interpolation, SvelteKit CSRF/cookie config. Guard-aware: identifier-validation files, path-guard helpers, escape idioms, and configured endpoints pass.scripts/security/scan-secret-misuse.ts— hardcoded credentials / comparison backdoors.scripts/security/slop-scanner.ts— XSS/RTL/security architecture rules.bun audit— GitHub Advisory DB for the npm tree (SvelteKit/Svelte/Vite advisories included).scripts/security/scan-osv.ts— OSV.dev global database (GHSA + NVD + 20+ feeds) queried from CycloneDX SBOM purls, 24h cache.
Found & fixed (both on the pre-authentication setup wizard):
- Pre-auth DDL SQL injection —
CREATE/DROP DATABASE IF EXISTS \${db.name}`interpolated operator-supplied database names into raw DDL without validation (src/routes/setup/setup.server.ts,setup-service.server.ts). Fixed with anassertSafeSqlIdentifier` allowlist so only plain identifiers can reach DDL. - Pre-auth shell interpolation —
exec(\${pm} add ${packageName}`)built installer commands via a shell. Fixed withexecFile(pm, [“add”, packageName])args-array calls (setup/+page.server.ts,setup.remote.ts`) — input can never reach a shell.
Tests: tests/unit/scripts/scan-security-risk.test.ts (SQL, Mongo, eval, shell, path, SSRF, XSS, regex, CSRF/cookie rules), tests/unit/scripts/scan-osv.test.ts (batch + parse), tests/unit/scripts/scan-secret-misuse.test.ts. The scanner reports 0 findings on the current codebase.
Files Modified: scripts/security/scan-security-risk.ts, scripts/security/scan-osv.ts, scripts/security/risk-audit.ts, .githooks/pre-commit, src/routes/setup/setup.server.ts, src/routes/setup/setup-service.server.ts, src/routes/setup/+page.server.ts, src/routes/setup/setup.remote.ts.
16. Pen-Test Hardening Batch (August 2026)
External penetration-test findings closed with regression coverage in tests/unit/security/login-hardening.test.ts, tests/unit/api/auth-2fa.test.ts, tests/unit/auth/totp/totp-encryption.test.ts, and tests/unit/security/egress-guard.test.ts:
- Passwordless API login blocked (Critical) —
AuthNamespace.loginrequires a password andhandleLoginvalidates the body withloginFormSchema; email-only bodies return 401 without a session. - Passwordless 2FA verify closed (High) —
verify2FA(form + API) accepts the TOTP code only together with a short-lived signed pending-2FA token minted after a successful password login, plus per-client rate limiting. - Blocked users rejected on the form path (High) —
Auth.authenticatenow checksuser.blocked(parity withAuthNamespace.login). - API login enforces 2FA (High) —
handleLoginreturnsrequires2FA+ pending token instead of a session; 2FA-enabled accounts get no session from the password step (AuthNamespace.loginreturnssession: nulloutside the test harness). - GraphQL RBAC parity with REST (High) —
users/mediaresolvers requireuser:read/media:readinstead of any logged-in user. - Global-admin requires the admin role (High) —
isGlobalAdmin = isAdmin(user) && !user.tenantId(previously any null-tenant user was treated as global admin). - Open redirect after login closed (High) —
safeRedirect(input.redirect)on the login success path. - Trusted-device cookie rebound to IP/UA at skip time (Medium) — the 30-day 2FA-skip cookie is now validated against the presenting device’s fingerprint; this also fixed a latent parsing bug where a colon-bearing fingerprint (ip prefix + UA hash) bypassed the expiry check.
- SSRF egress-guard coverage completed (Medium) — IPv6 ULA
fc00::/7is fully blocked (bothfc00:andfd00:hextets), CGNAT100.64.0.0/10added, and bracketed IPv6 literals ([::1]) are now recognized as IPs instead of falling through to DNS.
17. Off-request patches (October 2026)
Helpers covered by unit tests. The write-path ownership check and the scheduler’s execute path are in the source and described in the security index. They do not have their own integration test yet.
- Guarded filter and sort:
stripGuardedFilterandstripGuardedSortdrop a name the caller may not read, including a nested$andthat becomes empty. Admins and unguarded schemas get the same object back.tests/unit/utils/guarded-query.test.ts. - CSV formula prefix: text cells that start with
=,+,-,@, tab, or carriage return are prefixed. Numbers and booleans are not.tests/unit/utils/export-encode.test.ts. - Status-transition allow-list:
acceptStatusTransitionJobkeepscollectionId,entryId,targetStatus, andentryPath, overwritesscheduledBywith the authenticated user, and rejects an unknown task or status.tests/unit/services/scheduler-job.test.ts. - WebSocket Origin host:
websocketOriginAllowedallows an empty Origin, matches the host (default port omitted), and rejects a foreign or malformed Origin. Same file.
No Backdoor Policy
SveltyCMS follows a strict no-backdoor policy with cryptographically-gated test support:
- ✅ Cryptographically-gated test bypass — The
__testBypassflag requires a timing-safetimingSafeEqual()cryptographic handshake against a runtime-generated secret, gated behindTEST_MODE/BENCHMARKenvironment variables. In production builds without these env vars, the bypass path is unconditionally blocked. - ✅ No static test API keys — Test secrets are generated at runtime via CSPRNG and never hardcoded.
- ✅ No mocked permissions — RBAC tested with real role checks; the bypass only skips middleware when cryptographically verified in test environments.
- ✅ No shortcuts — Encryption tested with real key derivation; auth paths excluded from turbo bypass, always using real credentials.
- ✅ CI-enforced backdoor closure — Every PR runs a deploy build (
bun run buildwithoutCOMPILE_ALL_ADAPTERS) and verifies the testing handler is stripped viaverify-prod-build-backdoor.ts --mode=deploy(CI task07-deploy-backdoor). A live probe then confirms/api/testingreturns 401/404 with no secret, wrong secret, and hardcoded secret. - ✅ Benchmark build gating — Bench builds (
COMPILE_ALL_ADAPTERS=true) are verified to include the testing handler viaverify:bench-build. Thesecurity-audit.tsscript includes a dedicated--only=backdoormode for OWASP A01 testing. - ✅ No backdoor in production — Normal
bun run buildstrips/api/testingto a static 404 viatestBackdoorStripperPlugininvite.config.ts. Thesecret-misuseCI task (06-secret-misuse) scans all source files for hardcoded secrets on every PR.
Authentication & Sessions
| Feature | Test Location | Status |
|---|---|---|
| User login | tests/unit/hooks/authentication.test.ts |
✅ |
| User logout | tests/unit/hooks/authentication.test.ts |
✅ |
| Session creation | tests/integration/databases/auth-session-amr-contract.test.ts |
✅ |
| Session validation | tests/unit/auth/sessions/session-manager.test.ts |
✅ |
| Session deletion | tests/unit/auth/sessions/session-manager.test.ts |
✅ |
| Session cookie hardening | tests/unit/auth/sessions/session-cookies.test.ts |
✅ |
| Session timeout handling | tests/unit/hooks/authentication.test.ts |
✅ |
| Password hashing (Argon2) | tests/unit/utils/security.test.ts | ✅ |
| Password verification | tests/unit/utils/security.test.ts | ✅ |
| Timing attack resistance | tests/unit/utils/security.test.ts | ✅ |
| OAuth/Google signup | tests/e2e/oauth-signup-firstuser.spec.ts | ✅ |
| SAML authentication | tests/unit/auth/sso/saml.test.ts | ✅ |
Authorization & Access Control
| Feature | Test Location | Status |
|---|---|---|
| Role-based access control (RBAC) | tests/unit/hooks/authorization.test.ts |
✅ |
| Permission checking | tests/unit/auth/roles/role-permission-access.test.ts |
✅ |
| Public route access | tests/unit/hooks/authorization.test.ts |
✅ |
| Protected route redirect | tests/unit/hooks/authorization.test.ts |
✅ |
| Admin-only endpoints | tests/integration/api/token.test.ts |
✅ |
| Unauthorized access blocked | tests/integration/api/collections.test.ts | ✅ |
| Plugin sandbox isolation | tests/unit/plugins/sandbox.test.ts | ✅ |
Two-Factor Authentication (2FA)
| Feature | Test Location | Status |
|---|---|---|
| TOTP setup | tests/integration/api/auth-2fa.test.ts |
✅ |
| TOTP validation | tests/integration/api/auth-2fa.test.ts |
✅ |
| Recovery codes | tests/integration/api/auth-2fa.test.ts |
✅ |
| 2FA enforcement for admins | tests/integration/api/auth-2fa.test.ts |
✅ |
Security Middleware
| Feature | Test Location | Status |
|---|---|---|
| Content Security Policy (CSP) | tests/unit/hooks/security-headers.test.ts |
✅ |
| HSTS header | tests/unit/hooks/security-headers.test.ts |
✅ |
| X-Frame-Options | tests/unit/hooks/security-headers.test.ts |
✅ |
| X-Content-Type-Options | tests/unit/hooks/security-headers.test.ts |
✅ |
| Referrer-Policy | tests/unit/hooks/security-headers.test.ts |
✅ |
| CORS configuration | tests/unit/hooks/security-headers.test.ts |
✅ |
| Rate limiting (IP-based) | tests/unit/hooks/rate-limit.test.ts | ✅ |
| Rate limiting (session-based) | tests/unit/hooks/rate-limit.test.ts | ✅ |
Threat Detection & Prevention
| Feature | Test Location | Status |
|---|---|---|
| SQL injection detection | tests/unit/security/handle-waf-guard.test.ts |
✅ |
| XSS attack detection | tests/unit/security/handle-waf-guard.test.ts |
✅ |
| Path traversal detection | tests/unit/security/handle-waf-guard.test.ts |
✅ |
| Prototype pollution detection | tests/unit/security/handle-waf-guard.test.ts |
✅ |
| Header splitting detection | tests/unit/security/handle-waf-guard.test.ts |
✅ |
| Credentials in query strings | tests/unit/security/threat-scan.test.ts |
✅ |
Input Validation
| Feature | Test Location | Status |
|---|---|---|
| Password strength validation | tests/integration/routes/login/signup.test.ts |
✅ |
| Email format validation | tests/integration/routes/login/signup.test.ts |
✅ |
| Password mismatch rejection | tests/integration/routes/login/signup.test.ts |
✅ |
| Invalid OAuth data rejection | tests/integration/routes/login/signup.test.ts |
✅ |
| Input sanitization | docs/reference/security/richtext-security.mdx |
✅ |
API Security
| Feature | Test Location | Status |
|---|---|---|
| Fail-Closed Dispatcher | src/routes/api/[...path]/+server.ts |
✅ |
| TBAC Role Isolation | src/hooks/handle-authentication.ts |
✅ |
| Informative 403 UI | user-management.svelte |
✅ |
| Authentication required for APIs | tests/unit/hooks/api-requests.test.ts | ✅ |
| Valid session required | tests/integration/api/collections.test.ts | ✅ |
| Admin-only API access | tests/integration/api/token.test.ts | ✅ |
| CSRF protection | tests/integration/api/user.test.ts | ✅ |
| Token creation/validation | tests/integration/api/token.test.ts | ✅ |
| GraphQL auth enforcement | tests/integration/api/graphql.test.ts | ✅ |
| GraphQL password field blocking | tests/integration/api/graphql.test.ts | ✅ |
Widget & Plugin Security
| Feature | Test Location | Status |
|---|---|---|
| Widget sandbox isolation | tests/unit/plugins/sandbox.test.ts |
✅ |
| Protected collection access denied | tests/unit/plugins/sandbox.test.ts |
✅ |
| File upload restrictions | docs/reference/security/widget-security.mdx |
✅ |
| XSS prevention in widgets | docs/reference/security/widget-security.mdx |
✅ |
| Widget permission system | tests/unit/hooks/authorization.test.ts |
✅ |
E2E Security Tests
| Feature | Test Location | Status |
|---|---|---|
| Login flow | tests/e2e/routes/login/login.spec.ts |
✅ |
| Role-based access | tests/e2e/routes/system/permission-enforcement.spec.ts |
✅ |
| User CRUD operations | tests/e2e/routes/user/management.spec.ts |
✅ |
| Permission changes | tests/e2e/routes/system/permissions.spec.ts |
✅ |
| OAuth signup flow | tests/e2e/routes/login/oauth.spec.ts |
✅ |
| Password change | tests/e2e/routes/user/profile.spec.ts |
✅ |
| Accessibility (axe) | tests/e2e/routes/login/accessibility.spec.ts |
✅ |
Test Commands
# Security-focused unit subset (hooks, authz, egress, WAF, SVG, scanners)
bun run test:security
# Middleware pipeline tests
bun run test:unit -- tests/unit/hooks/
# Authentication tests
bun run test:unit -- tests/unit/hooks/authentication.test.ts
# Authorization tests
bun run test:unit -- tests/unit/hooks/authorization.test.ts
# WAF / threat detection tests
bun run test:unit -- tests/unit/security/handle-waf-guard.test.ts tests/unit/security/threat-scan.test.ts
# Security headers tests
bun run test:unit -- tests/unit/hooks/security-headers.test.ts
# Integration API security tests (builds the harness first)
bun run test:integration
# E2E security tests
bun run test:e2e -- --grep="(Authentication)"
# Run all tests (unit + integration)
bun run test:all
Security Test Statistics
| Category | Test Count |
|---|---|
| Authentication | 50+ |
| Authorization | 40+ |
| Input Validation | 80+ |
| XSS Prevention | 30+ |
| Injection Prevention | 40+ |
| Security Headers | 20+ |
| File Upload Security | 20+ |
| Total | 280+ |
Related Documentation
- Security Index - Main security documentation
- No Backdoor Policy - Testing security philosophy
- Black-Box Testing - Test architecture
- Widget Security - Widget security guidelines
- RichText Security - Rich text editor security