Securing scsiwyg: What an Audit Found and What We Did About It
#security#devlog#building-in-public#testing#scsiwyg
David Olssonscsiwyg was extracted from an existing monorepo and shipped fast. That's a feature, not a bug — a platform that never launches never matters. But shipping fast means the codebase grows organically, and organic growth has a way of creating the kind of technical debt that becomes a security liability before it becomes a performance problem.
So we audited it.
What we looked at
The audit covered five domains: authentication and authorization patterns, API route behavior, database access, UI components, and parity between the REST API and the MCP server. The goal wasn't to find exploits — it was to find the structural gaps that tend to produce exploits over time.
47 findings. Four severity tiers. Here's what the picture looked like at a theme level.
The dominant finding: duplication
The single loudest signal across every domain was duplication without abstraction. The same logic — ownership checks, plan gating, input validation, database lookups — written inline, repeatedly, in slightly different ways across different parts of the codebase.
This is the kind of thing that reads as a code quality problem. It is. But it's also a security problem. When the same rule is implemented in five places, it will eventually drift. One version gets updated. The others don't. The gap between them becomes exploitable.
The fix isn't clever — it's just centralization. Shared helpers, a data access layer, a single source of truth for validation rules. Engineering work, not security research. But unglamorous as it is, it's the work that keeps a platform consistent as it grows.
Auth and input handling
Two smaller clusters in the security-relevant findings:
Auth coverage — the platform's dual-auth design (session cookies for the web UI, Bearer tokens for the API) is correctly separated and consistently applied. What the audit found were a small number of places where that coverage wasn't complete — session-mutation operations that were missing a protection that others had, role infrastructure that existed in the code but wasn't being enforced. Neither were live exploits, but both were the kind of thing that becomes a live exploit when someone looks.
Input handling — several routes lacked defensive handling for malformed requests, and validation rules weren't applied uniformly across equivalent paths. The REST API and the MCP server, in particular, had diverged on how they validated the same inputs, including different size limits for the same content field. An API with two interfaces should behave identically from both.
Database
The audit found common query patterns duplicated widely across the codebase and flagged some data consistency risks related to how user inputs were being normalized before storage. Both are correctness issues before they're performance issues — and performance issues before they're reliability issues.
We also reviewed index coverage against the actual query patterns. That work is underway.
What we're doing about it
The action plan runs in four phases:
- Security and data integrity first — closing the specific auth gaps, hardening input handling, fixing data consistency, aligning behavior between the REST and MCP interfaces
- Centralize shared logic — data access layer, shared validators, extracted auth helpers that apply the same rules everywhere instead of inline in each handler
- UI component extraction — the frontend has the same duplication problem; shared components rather than copy-pasted patterns
- Polish and consistency — response shape standardization, accessibility gaps, dead code removal
Phases 1 and 2 are in progress. The security and correctness work goes first; the structural cleanup follows.
The takeaway
An audit on a young platform is mostly an exercise in finding where the scaffolding was left in. You build fast, you make pragmatic choices, and then you look back and see where "I'll clean this up later" turned into a dozen slightly different versions of the same function. The answer is to look before those inconsistencies harden into bugs.
scsiwyg is a small platform that handles auth, billing, and user-generated content. That's enough surface area to take seriously. We do.