Skip to content

Latest commit

 

History

History
173 lines (134 loc) · 9.62 KB

File metadata and controls

173 lines (134 loc) · 9.62 KB

Vulnerability Catalog

Purpose

This catalog records structural security risks observed during the CMS Nova case study.

Some entries describe baseline issues that have since been remediated; others may still be relevant. Each finding includes a status and is written in a research-friendly format (issue + failure mode).

Status legend:

  • Open: still present / not fully addressed.
  • Mitigated: reduced risk, but not a complete structural fix.
  • Remediated: fixed (or structurally blocked) in the current repo state.

Severity Scale

  • Critical: high-impact exposure with low barriers and direct compromise potential.
  • High: serious confidentiality or integrity risk that violates intended security policy.
  • Medium: meaningful weakness that increases exploitability, drift, or unsafe maintenance.
  • Low: weakness with limited immediate impact but relevant architectural significance.

Findings

VG-001 - Public detail route can expose unpublished content

  • Severity: High
  • Status: Remediated
  • Files: src/app/[typePath]/[slug]/page.tsx
  • Issue (baseline): the route resolved entries without an explicit status: 'published' filter and did not consistently enforce the intended public-route gate.
  • Why it matters: draft or internal content may be publicly accessible if the slug is known or guessed.
  • Remediation: enforced the public-typepaths gate and published-only lookups.
  • Failure mode: global publication policy weakened by local route logic.
  • Research link: Lack of Global Context

VG-002 - Public type-path feature flag is effectively broken

  • Severity: High
  • Status: Remediated
  • Files: src/app/[typePath]/page.tsx, src/app/api/plugins/public-typepaths/route.ts
  • Issue (baseline): the public page checked data.success instead of data.enabled, so disabled routes could still remain active.
  • Why it matters: a policy intended as a kill switch does not reliably disable public exposure.
  • Remediation: centralized the gate and enforced enabled semantics in shared logic.
  • Failure mode: policy check implemented, but interpreted incorrectly.
  • Research link: local correctness without policy correctness.

VG-003 - Content entry APIs expose data without published-only filtering

  • Severity: High
  • Status: Remediated
  • Files: src/app/api/content-types/[slug]/entries/route.ts, src/app/api/content-types/[slug]/entries/[id]/route.ts, src/app/api/content-entries/route.ts
  • Issue (baseline): unauthenticated GET handlers returned content entries without restricting results to published state.
  • Why it matters: internal CMS data can be enumerated outside intended public views.
  • Remediation: restricted admin-oriented entry APIs behind admin session checks.
  • Failure mode: route exposure drift.
  • Research link: Naming Bias and Lack of Global Context

VG-004 - Plans and experiences APIs expose unpublished inventory

  • Severity: High
  • Status: Remediated
  • Files: src/app/api/plans/route.ts, src/app/api/plans/[id]/route.ts, src/app/api/experiences/route.ts
  • Issue (baseline): public GET handlers returned plans and experiences without enforcing publication visibility.
  • Why it matters: unpublished business data and editorial state become observable through direct API access.
  • Remediation: required admin session for inventory APIs and moved handlers behind vertical-owned server paths.
  • Failure mode: public/private boundary erosion.
  • Research link: local feature convenience overriding system policy.

VG-005 - Public schema and template discovery aid enumeration

  • Severity: Medium
  • Status: Mitigated
  • Files: src/app/api/content-types/route.ts, src/app/api/content-types/[slug]/route.ts
  • Issue (baseline): content type metadata and template structure were exposed publicly.
  • Why it matters: schema discovery lowers the cost of targeted probing and content enumeration.
  • Remediation: schema discovery now requires an admin session (or a deliberate public-routing mode for dynamic nav), and returns a minimal shape.
  • Failure mode: information disclosure through convenience endpoints.
  • Research link: overexposure caused by feature-centric reasoning.

VG-006 - Media inventory and folder structure are publicly enumerable

  • Severity: High
  • Status: Remediated
  • Files: src/app/api/media/route.ts, src/app/api/media/folders/route.ts
  • Issue (baseline): GET endpoints exposed asset metadata, folder names, and search behavior without authentication.
  • Why it matters: internal organization and unpublished assets may become discoverable even if not linked publicly.
  • Remediation: restricted admin-oriented media inventory endpoints behind admin session checks.
  • Failure mode: metadata overexposure.
  • Research link: lack of sensitivity classification for asset infrastructure.

VG-007 - Plugin secret flow is structurally unsafe

  • Severity: Critical
  • Status: Mitigated
  • Files: src/app/api/plugins/[id]/route.ts, src/modules/plugins/utils.ts, src/modules/plugins/service.ts
  • Issue (baseline): plugin configuration and secrets were handled through filesystem-backed state and client caching patterns, collapsing the server/client boundary.
  • Why it matters: secrets stored outside a privileged and encrypted persistence layer can be leaked through local files, backups, logs, or accidentally reintroduced into client-facing surfaces.
  • Remediation: config is now DB-backed and client responses mask sensitive fields; sensitive config values can be encrypted at rest when ENCRYPTION_KEY is configured.
  • Failure mode: server/client boundary collapse.
  • Research link: strong evidence for the need for centralized policy enforcement.

Notes:

  • A concrete example of this class of failure is a plaintext plugin store containing API keys on disk (even if gitignored).
  • Full mitigation requires keeping secrets out of client-visible surfaces and configuring ENCRYPTION_KEY in production.

VG-008 - Server action exposes taxonomy hierarchy without auth

  • Severity: Medium
  • Status: Remediated
  • Files: src/modules/content/server/slug-actions.ts
  • Issue (baseline): getSlugHierarchy() did not require a session, while neighboring mutation actions did.
  • Why it matters: internal taxonomy can be queried from the browser even though the feature sits in an admin workflow.
  • Remediation: server actions now require an admin session for reads and mutations.
  • Failure mode: inconsistent authorization within the same domain surface.
  • Research link: local omission of trust-boundary checks.

VG-009 - Public rich-text rendering creates stored XSS risk

  • Severity: High
  • Status: Mitigated
  • Files: src/app/[typePath]/[slug]/page.tsx
  • Issue (baseline): rich text from database content was rendered via dangerouslySetInnerHTML without visible sanitization.
  • Why it matters: malicious or compromised editor content can execute in visitors' browsers.
  • Remediation: added a basic sanitizer (src/shared/security/html.ts) before public HTML injection.
  • Failure mode: unsafe content rendering.
  • Research link: feature completion prioritized over output safety.

VG-010 - Logging policy is inconsistent and may leak sensitive operational data

  • Severity: Medium
  • Status: Mitigated
  • Files: multiple route, action, and UI files
  • Issue (baseline): raw console.log and console.error calls were scattered across public, admin, and API surfaces.
  • Why it matters: identifiers, user details, route traces, and raw errors may leak through logs.
  • Remediation: introduced a centralized server logger with redaction; some legacy console.* usage remains (especially in UI code).
  • Failure mode: observability without sanitization policy.
  • Research link: local debugging convenience overriding operational security.

VG-011 - First-admin bootstrap can be claimed by the first external caller

  • Severity: High
  • Status: Mitigated
  • Files: src/app/api/admin/create-first-admin/route.ts
  • Issue (baseline): the route is intentionally public until setup is complete, but had weak initialization controls.
  • Why it matters: on a fresh deployment, whoever reaches the endpoint first may become the administrator.
  • Remediation: added rate limiting and optional setup-token enforcement (NOVA_SETUP_TOKEN) to reduce first-caller takeover risk.
  • Failure mode: insecure initialization workflow.
  • Research link: common AI blind spot around deployment-time trust assumptions.

Positive Controls Already Present

  • src/server/auth/session.ts provides a reusable admin-session helper used across privileged surfaces.
  • src/server/auth/config.ts centralizes Better Auth configuration and session semantics.
  • src/server/observability/logger.ts redacts common sensitive keys and reduces production log noise.
  • src/server/policy/api-visibility.js codifies “default private” for /api/*.
  • scripts/security/check-api-policy.js enforces API visibility policy at build/check time.
  • src/lib/encryption.ts provides AES-GCM helpers for encrypting sensitive fields when configured.
  • .gitignore excludes .env.
  • several privileged routes already apply rate limiting.

Interpretation

The project demonstrates why AI-assisted systems need structural verification, not only file-level review.

The highest-risk failures were policy failures (route exposure, authorization drift, secret boundaries), which are hard to catch when changes are made with local context only.

Remaining Priorities

  1. Replace the basic HTML sanitizer with a strict allowlist-based sanitizer.
  2. Keep reducing raw server-side console.* usage in favor of centralized logging.
  3. Extend policy checks beyond /api/* (e.g., Server Actions + publication invariants).
  4. Treat NOVA_SETUP_TOKEN and ENCRYPTION_KEY as required production hardening settings.