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.
The Cloudinary API secret was previously committed to Git history. Removing it from the current file does not invalidate the exposed credential.
- Sign in to the KTP Cloudinary account.
- Rotate or regenerate the API secret.
- Put the new values in the local
.envfile:
CLOUDINARY_CLOUD_NAME=dha44tosd
CLOUDINARY_API_KEY=...
CLOUDINARY_API_SECRET=...
- 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.
- Test the headshot uploader with
--dry-runbefore performing a real upload.
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:
- Run
supabase/portal-emergency-lockdown.sqlin the KTP Portal project. - Rotate the legacy JWT secret/API keys in Supabase Project Settings.
- Do not copy the old keys from Git history into Vercel or local files.
- Install the replacement
portal_*schema fromsupabase/portal-schema.sql. - Use only the new Portal anon/publishable value in
NEXT_PUBLIC_PORTAL_SUPABASE_ANON_KEY. - Keep secret/service-role values server-only, and only add one if a reviewed server operation truly requires it.
.envand.env.*are ignored by Git..env.examplecontains variable names and safe defaults only..env.productionis the one exception. It may contain only browser-publicNEXT_PUBLIC_SUPABASE_URLandNEXT_PUBLIC_SUPABASE_ANON_KEYvalues 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_.
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:
- Remove former officers who no longer need access.
- Add the incoming VP of Technology and Director of Web Systems.
- Confirm recovery email and multifactor authentication.
- Review billing pages and payment methods.
- Rotate any credential that was shared in chat, email, screenshots, or code.
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.
- 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.
If a credential is exposed:
- Rotate or revoke it immediately.
- Remove it from the current branch.
- Check service logs for unexpected use.
- Update Vercel/local environment values.
- Redeploy and test affected features.
- Notify the President and relevant account owners.
- Consider Git history rewriting only with organization-owner approval because it disrupts every clone and open branch.
If the site is broken:
- Check the latest Vercel deployment and build logs.
- Revert the failing pull request through a new pull request or Vercel rollback.
- Test the live routes and dynamic APIs.
- Record the cause, resolution, and prevention step in the transition log.