Skip to content

Security: KappaThetaPiUTD/KTPWebsite

docs/SECURITY.md

KTP Website Security Operations

This document covers the minimum security practices for maintaining the KTP website. Never place passwords, API secrets, private keys, personal member data, or service-account credentials in GitHub.

Immediate action required: rotate Cloudinary credentials

The Cloudinary API secret was previously committed to Git history. Removing it from the current file does not invalidate the exposed credential.

  1. Sign in to the KTP Cloudinary account.
  2. Rotate or regenerate the API secret.
  3. Put the new values in the local .env file:
CLOUDINARY_CLOUD_NAME=dha44tosd
CLOUDINARY_API_KEY=...
CLOUDINARY_API_SECRET=...
  1. Do not put these values in Vercel unless a deployed server route actually needs Cloudinary write access. The public site currently only reads image URLs.
  2. Test the headshot uploader with --dry-run before performing a real upload.

Immediate action required: rotate KTP Portal Supabase keys

The legacy KTP Portal service_role and related JWT secrets were committed in Git history. A July 2026 read-only audit confirmed that the historical service-role key remained active. Because service-role bypasses RLS:

  1. Run supabase/portal-emergency-lockdown.sql in the KTP Portal project.
  2. Rotate the legacy JWT secret/API keys in Supabase Project Settings.
  3. Do not copy the old keys from Git history into Vercel or local files.
  4. Install the replacement portal_* schema from supabase/portal-schema.sql.
  5. Use only the new Portal anon/publishable value in NEXT_PUBLIC_PORTAL_SUPABASE_ANON_KEY.
  6. Keep secret/service-role values server-only, and only add one if a reviewed server operation truly requires it.

Environment files

  • .env and .env.* are ignored by Git.
  • .env.example contains variable names and safe defaults only.
  • .env.production is the one exception. It may contain only browser-public NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY values as a deployment fallback. Never add a private value to it.
  • Production variables belong in Vercel: Project Settings > Environment Variables.
  • Public browser-safe values may start with NEXT_PUBLIC_.
  • Secrets must never start with NEXT_PUBLIC_.

Credential ownership

Use chapter-owned accounts whenever possible. At least two current officers should have recovery access to GitHub, Vercel, Supabase, Cloudinary, EmailJS, Resend, Google Analytics, the chapter Gmail, and the domain registrar.

At every officer transition:

  1. Remove former officers who no longer need access.
  2. Add the incoming VP of Technology and Director of Web Systems.
  3. Confirm recovery email and multifactor authentication.
  4. Review billing pages and payment methods.
  5. Rotate any credential that was shared in chat, email, screenshots, or code.

Member data

Only publish information members knowingly provided for the public website. Do not upload phone numbers, personal email addresses, emergency contacts, medication details, allergies, resumes, transcripts, schedules, or birth years. The birthday feature stores month and day only.

Member portal

  • Keep the KTP Portal Supabase project separate from the public KTP Blog project.
  • Browser anon keys may use NEXT_PUBLIC_; service-role keys never may.
  • Protect portal pages with server-verified sessions. A client-side redirect is not an authorization control.
  • Enforce event visibility, attendance edits, strikes, and admin access through Supabase row-level security or trusted server routes.
  • Store official roles in a protected database table or custom claims. Never authorize from user-editable Auth metadata.
  • Disable open signups in Supabase Auth. Add members through invitations or a trusted officer-only provisioning flow.
  • Do not restore the archived access-code cookies, arbitrary profile-update endpoint, fake QR token, or localhost-only Express API.

Incident response

If a credential is exposed:

  1. Rotate or revoke it immediately.
  2. Remove it from the current branch.
  3. Check service logs for unexpected use.
  4. Update Vercel/local environment values.
  5. Redeploy and test affected features.
  6. Notify the President and relevant account owners.
  7. Consider Git history rewriting only with organization-owner approval because it disrupts every clone and open branch.

If the site is broken:

  1. Check the latest Vercel deployment and build logs.
  2. Revert the failing pull request through a new pull request or Vercel rollback.
  3. Test the live routes and dynamic APIs.
  4. Record the cause, resolution, and prevention step in the transition log.

There aren't any published security advisories