Session 19 — Security Hardening: RLS, XSS, Auth

M5 — Security May 22, 2026 @resist @shift

What I Did

Professor security review identified 3 issues: broken RLS policies, XSS vulnerabilities in innerHTML templates, and auth hygiene (guest mode creating an unauthenticated surface). Fixed all three. Platform is now security-hardened and auth-only.

Security Issues Fixed

Issue 1: Broken RLS Policies

The RLS policies on all three tables (test_results, users, sessions) were written correctly in logic but failing silently due to a type mismatch: user_id was stored as TEXT, but auth.uid() returns UUID. In PostgreSQL, UUID = TEXT evaluates to false without throwing an error — so every policy evaluation silently failed. The fix: add an explicit UUID cast.

-- Before (broken — silent false every time)
USING (auth.uid() = user_id)

-- After (fixed — explicit cast)
USING (auth.uid() = user_id::uuid)

This was diagnosable because of the understanding built in Session 11. Without that conceptual model, the type mismatch would have been invisible.

Issue 2: XSS via innerHTML Templates

The history page used innerHTML to render test results from the database — user-controlled data interpolated directly into HTML strings. If a user had stored a result with a script tag in the metadata field, it would execute on the history page.

Fix: escapeHtml() helper function applied to every interpolated database value. 51 values escaped across 4 templates.

function escapeHtml(str) {
  if (str === null || str === undefined) return '';
  return String(str)
    .replace(/&/g, '&')
    .replace(//g, '>')
    .replace(/"/g, '"')
    .replace(/'/g, ''');
}

// Applied to every interpolated DB value:
<td>${escapeHtml(result.test_type)}</td>

Issue 3: Guest Mode Removed

Guest mode allowed unauthenticated users to take tests. This created a surface for unauthenticated requests to the database. Removed entirely — Baseline is now auth-only.

@shift — Auth as Product Requirement, Not Just Security

Removing guest mode wasn't just a security fix — it aligned the product with its own value proposition. Baseline's core value is "trackable over time." You can't track over time without an account. Guest mode created a version of Baseline that looked like the product but didn't deliver the product's value. Removing it made the platform's identity clearer: this is a tool for tracking, not for one-off measurement.

AI Interactions

@resist — Deferred Password Complexity

AI suggested adding password complexity requirements (minimum 8 characters, at least one uppercase, one number, one special character) as part of the auth hardening. I deferred it. Reason: at current scale (a course project with a handful of users), password complexity requirements are friction without proportionate benefit. The users taking this test are not managing sensitive health data — they're tracking hand coordination scores. Adding auth friction reduces the chance they'll complete registration. Password complexity can be added when user data security becomes a real concern. Security measures should be proportionate to the actual risk.

What I Learned

Security vulnerabilities often hide in the gap between working and correct. The RLS type mismatch: the code ran, no errors were thrown, policies appeared to be in place. The system looked secure. It wasn't. Knowing the difference requires understanding the underlying type system, not just running the code.

XSS is a reminder that database values are user-controlled inputs. Just because data came from your database doesn't mean it's safe to render without escaping. Any value a user could have provided — directly or indirectly — needs to be escaped before rendering.

Quarter Question Connection

The security work in this session is directly connected to the quarter question. "Track human physical and cognitive function" requires storing personal health-adjacent data. That data deserves to be protected. RLS, XSS escaping, and auth-only architecture are the minimum viable security for a platform that stores longitudinal health data about real people.

What's Next

M6: documentation, artist statement, Five Questions, disclosure, process book. The platform is live, secure, and ready to document.

Process Book Documentation

In parallel with platform security hardening, I built and refined the Baseline Process Book — a comprehensive documentation of the entire 10-week project arc from exploration through deployment. The process book serves as both a record of decision-making and an artifact showing how a platform grows from quarter question to working product.

Initial Process Book Structure (M1–M5)

Created the foundational process book architecture with the following pages:

  • index.html — Homepage showing project stats, milestones timeline, and navigation to all process materials
  • process-blog.html — Chronological listing of all 20 sessions (Sessions 1–20) organized by milestone
  • system-maps.html — Five system architecture diagrams: complete system overview, auth flow, data pipeline, unified test architecture, deployment
  • records-of-resistance.html — Documentation of all 53 deliberate design decisions where I pushed back on AI suggestions or made intentional creative choices
  • leverage-points.html — Analysis of system leverage points and where small interventions create large effects
  • m6-final.html — Final M6 documentation, artist statement, Five Questions, disclosure statement
  • sessions/session-1.html through session-20.html — Detailed individual session documentation with what was built, AI interactions, learnings, and connections to quarter question

M6 Integration & Adjustments (May 22–25, 2026)

Updated the process book to accurately reflect the complete project through M6 (20 sessions, 6 milestones). Changes made:

index.html: Updated project statistics from "19 Sessions, 3 Deployed Tests, 18 Records of Resistance, 5 Milestones" to "20 Sessions, 18 Records of Resistance, 6 Milestones" (removed Deployed Tests count as it's implicit in the 3 tests mentioned). Added M6 timeline item marking "Process Book Documentation" for Session 20. Updated Process Blog card description from "19 sessions" to "20 sessions" and "Sessions 1–19" to "Sessions 1–20". Updated About section from "across 19 sessions" to "across 20 sessions".

process-blog.html: Added entire M6 section with Session 20 entry. Updated page header from "19 Sessions, March–May 2026" to "20 Sessions, March–May 2026" and changed description from "From first prototype to deployed platform" to "From first prototype to presented platform."

sessions/session-20.html: Created new session documentation for Session 20 (Presenting Work) — the capstone presentation of the entire 10-week project to class and faculty.

style.css: Added M6 milestone color definition (purple #8b5cf6) to support M6 timeline marker styling.

system-maps.html: Updated Map 1 heading from "Complete System Architecture (M5 Deployed)" to "Complete System Architecture (M6 Final)" and added "Documented and presented in M6" to the intro text.

records-of-resistance.html: Comprehensively rebuilt to show all 53 Records of Resistance organized by milestone (M1–M6) with one-paragraph explanations for each record. Each record includes title, session reference, date, tag indicator (@resist, @shift, @default), and concise explanation. Changed from showing only 6 featured records to displaying all records with clear milestone organization, making the full decision-making arc visible across the entire project.

Why the Process Book Matters

The process book is itself a design artifact. It demonstrates that the quarter question — "What happens when I use AI to turn everyday devices into tools that test, teach, and track human physical and cognitive function?" — shaped not just the platform, but every decision and refinement along the way. By documenting the arc from exploration → prototyping → testing → security hardening → presentation, the process book shows how intentional design decisions compound. The 53 Records of Resistance, organized by milestone, reveal the patterns: accuracy over convenience, explicit over implicit, understanding before building, standardization enabling scale, and proportional solutions. These aren't lessons *about* the platform; they're lessons *evident in* the platform's architecture.

← Session 18 Session 20 →