# GitHub Copilot pre-launch checklist

From BuildThenTested (https://buildthentested.com/built-with/copilot/). 52 checks in the order we run them, most severe first. Each check links to a page with what it looks like, a self-check and a fix direction.

Defaults referenced are from GitHub's documentation, verified 2026-09-21. Tick a box only after you have seen the result yourself.

## Secrets and keys

- [ ] **NEXT_PUBLIC_ prefix on a secret** (critical). In your hosting dashboard (Vercel: Project, Settings, Environment Variables) or your .env files, list every variable whose name starts with NEXT_PUBLIC_.
  https://buildthentested.com/patterns/next-public-env-var-exposes-secret/

- [ ] **Secrets committed to the code repository** (critical). Open your project on GitHub (or the code view in your builder) and look at the file list for .env, .env.local, .env.production, serviceAccountKey.json or firebase-adminsdk files.
  https://buildthentested.com/patterns/secrets-committed-to-repo/

- [ ] **Service-role key shipped in the browser bundle** (critical). Open your live app in Chrome, right-click anywhere and choose Inspect, then open the Sources tab.
  https://buildthentested.com/patterns/service-role-key-in-browser-bundle/

## Data access

- [ ] **Firebase rules left in test mode** (critical). Open the Firebase console, choose your project, then Firestore Database (or Realtime Database, or Storage) and open the Rules tab.
  https://buildthentested.com/patterns/firebase-rules-open-test-mode/

- [ ] **Record ids accepted without an ownership check** (critical). Create two accounts in your app and add one record, such as an order or a note, in each.
  https://buildthentested.com/patterns/idor-on-record-ids/

- [ ] **Inverted policy logic** (critical). In the Supabase dashboard, open Authentication, then Policies, and read every policy on a table that holds customer data.
  https://buildthentested.com/patterns/inverted-policy-logic/

- [ ] **Any signed-in user can read every row** (critical). In the Supabase dashboard open Authentication, then Policies. Row Level Security (RLS) is the per-row access rule set Postgres applies to each query, and this page shows each policy's expression.
  https://buildthentested.com/patterns/rls-any-authenticated-user-reads-all/

- [ ] **Row Level Security disabled on a table** (critical). In the Supabase dashboard open Table Editor. Tables without Row Level Security (RLS, the per-row access rules Postgres applies to each query) show an RLS disabled or Unrestricted label next to the name.
  https://buildthentested.com/patterns/rls-disabled-on-table/

- [ ] **RLS policy that allows everything with using (true)** (critical). In the Supabase dashboard open Authentication, then Policies. Row Level Security (RLS) is the per-row access rule set Postgres applies to each query, and this page lists every policy per table.
  https://buildthentested.com/patterns/rls-policy-using-true/

## Login and permissions

- [ ] **Admin routes without any login check** (critical). Open a private browsing window so you are signed out.
  https://buildthentested.com/patterns/admin-routes-without-auth/

- [ ] **Authorization enforced only in the browser** (critical). Sign in as a normal user and open developer tools (right-click, Inspect), then the Network tab.
  https://buildthentested.com/patterns/authorization-only-in-browser/

- [ ] **Default admin credentials left in place** (critical). In the builder's code view, search the whole project for admin@, password, seed and demo.
  https://buildthentested.com/patterns/default-admin-credentials/

- [ ] **Tokens trusted without server verification** (critical). Sign in, open developer tools (right-click, Inspect), go to the Network tab and pick a request to your own API that carries an Authorization header or a session cookie.
  https://buildthentested.com/patterns/jwt-accepted-without-server-verification/

- [ ] **Role chosen by the client at signup** (critical). Open your signup page, open developer tools (right-click, Inspect) and the Network tab, then submit the form with a test email.
  https://buildthentested.com/patterns/role-chosen-by-client-at-signup/

## Payments

- [ ] **Stripe webhook accepted without signature verification** (critical). In the Stripe Dashboard, open Developers, then Webhooks, and copy the endpoint URL your app uses. It usually ends in something like /api/stripe/webhook or /functions/v1/stripe-webhook.
  https://buildthentested.com/patterns/stripe-webhook-without-signature-verification/

## AI features

- [ ] **LLM API key exposed to the client** (critical). Open your live app, press F12, select the Network tab, and use the AI feature once.
  https://buildthentested.com/patterns/llm-api-key-exposed-to-client/

- [ ] **No output validation before actions** (critical). List the things your AI feature can do beyond replying with text: run queries, call APIs, send messages, change records, fetch URLs, run code.
  https://buildthentested.com/patterns/no-output-validation-before-actions/

## Deploy and config

- [ ] **AI agent with production credentials** (critical). Open the folder the agent works in and look for .env, .env.local or similar files; note whether any value starts with sk_live_, contains the word prod, or is a service-role or admin key.
  https://buildthentested.com/patterns/ai-agent-with-production-credentials/

## Mobile

- [ ] **Secrets in the mobile app bundle** (critical). Open the project's .env files and app.json or app.config.js; list every variable whose name starts with EXPO_PUBLIC_ or that sits under extra.
  https://buildthentested.com/patterns/secrets-in-mobile-app-bundle/

## Secrets and keys

- [ ] **Third-party API key in the JavaScript bundle** (high). Open your live app in Chrome, right-click, choose Inspect, then open the Sources tab.
  https://buildthentested.com/patterns/api-key-in-javascript-bundle/

- [ ] **Secrets and internals in error messages and logs** (high). Open your live app, right-click, choose Inspect, then the Network tab. Trigger an error on purpose: submit a form with a field left blank, or visit an address like /api/anything-made-up.
  https://buildthentested.com/patterns/secrets-in-error-messages-and-logs/

## Data access

- [ ] **Uploaded files in a public storage bucket** (high). In the Supabase dashboard open Storage and look for the Public label on each bucket; in Firebase open Storage, then the Rules tab.
  https://buildthentested.com/patterns/storage-bucket-public/

## Login and permissions

- [ ] **Password reset links that never expire** (high). Request a password reset for your own test account and keep the email.
  https://buildthentested.com/patterns/password-reset-tokens-never-expire/

- [ ] **Sessions that survive logout and password changes** (high). Sign in, open developer tools (right-click, Inspect), go to the Network tab and use Copy as cURL on a request that returns your account data.
  https://buildthentested.com/patterns/sessions-never-invalidated/

## Payments

- [ ] **No idempotency on payment handlers** (high). In the Stripe Dashboard, open Developers, then Webhooks, select your endpoint and open a recent invoice.paid or checkout.session.completed event for a test account.
  https://buildthentested.com/patterns/no-idempotency-on-payment-handlers/

- [ ] **Price or plan taken from the client** (high). Open your app's pricing page in Chrome, press F12 to open developer tools (the browser's built-in inspector), and select the Network tab.
  https://buildthentested.com/patterns/price-or-plan-taken-from-client/

- [ ] **Subscription state trusted from local storage** (high). Sign in to your app with a free account, press F12 to open developer tools, select the Application tab, then Local Storage on the left.
  https://buildthentested.com/patterns/subscription-state-trusted-from-local-storage/

- [ ] **Stripe test keys in production** (high). Open your live app's checkout, press F12, select the Network tab, and start a checkout. Look for requests to stripe.com or js.stripe.com and read their URLs and payloads for a key beginning pk_test_ or a session ID beginning cs_test_.
  https://buildthentested.com/patterns/test-keys-in-production/

## AI features

- [ ] **No spend cap on model calls** (high). Sign in to your model provider's console and open the billing or limits page (OpenAI: Limits; Anthropic: Settings, then Billing). Note whether a monthly spend limit and a spend alert are set.
  https://buildthentested.com/patterns/no-spend-cap-on-model-calls/

- [ ] **Prompt injection through user content** (high). List every place where text from a user, a webpage, an uploaded file or an email reaches the model: chat boxes, ticket forms, document upload, URL summarisers.
  https://buildthentested.com/patterns/prompt-injection-through-user-content/

## Reliability

- [ ] **No rate limiting on sensitive routes** (high). Open your app's login or "forgot password" page in Chrome, press F12 and choose the Network tab.
  https://buildthentested.com/patterns/no-rate-limiting/

## Data integrity

- [ ] **Deletes with no soft delete or audit trail** (high). In a test account, create a record in the app, then delete it using the app's own button.
  https://buildthentested.com/patterns/deletes-without-soft-delete-or-audit/

- [ ] **Race conditions on counters and balances** (high). Open the app in two browser tabs signed in to the same test account that has a limited balance, seat count or single-use coupon.
  https://buildthentested.com/patterns/race-conditions-on-counters-and-balances/

## Deploy and config

- [ ] **CORS open to any origin with credentials** (high). Sign in to the live app, open browser devtools, go to the Network tab and click any request to your API.
  https://buildthentested.com/patterns/cors-wildcard-with-credentials/

- [ ] **Dependencies with known vulnerabilities** (high). If your builder shows a package.json file or lets you export the code, open a terminal in that folder and run npm audit (or pnpm audit or yarn audit).
  https://buildthentested.com/patterns/dependencies-with-known-vulnerabilities/

## Mobile

- [ ] **Offline state corrupting data** (high). On two phones (or a phone and the simulator) signed into the same account, put one in airplane mode and edit the same record on both.
  https://buildthentested.com/patterns/offline-state-corrupting-data/

## AI features

- [ ] **Unbounded input length to the model** (medium). Open the AI feature in your app and paste an unusually long text, for example a whole book chapter copied several times, then submit.
  https://buildthentested.com/patterns/unbounded-input-length-to-model/

## Reliability

- [ ] **Background jobs that fail silently** (medium). List every scheduled or background task your app has: on Vercel open Settings then Cron Jobs; on Supabase open Integrations then Cron, and Edge Functions; on Replit look for a Scheduled deployment.
  https://buildthentested.com/patterns/background-jobs-without-failure-handling/

- [ ] **Errors swallowed, spinner never stops** (medium). Open your app in Chrome and sign in as a normal user.
  https://buildthentested.com/patterns/errors-swallowed-ui-spins-forever/

- [ ] **Retries with no pause and no cap** (medium). Open your app in Chrome, press F12 and choose the Network tab.
  https://buildthentested.com/patterns/retries-without-backoff/

- [ ] **One process, one machine, nothing restarts it** (medium). Find out where the app runs. In Replit, open the Publishing pane and read the deployment type. On a server or container host, open the provider's dashboard and look for "restart policy", "health check" or "process manager".
  https://buildthentested.com/patterns/single-instance-no-restart-policy/

## Performance

- [ ] **No index on the columns you filter by** (medium). In the Supabase dashboard open Advisors, then Performance Advisor, and read the list of suggestions.
  https://buildthentested.com/patterns/missing-indexes-on-filtered-columns/

- [ ] **One database query per list item** (medium). Open a page in your app that shows a list (orders, projects, customers) in Chrome, press F12, choose the Network tab and filter by "Fetch/XHR".
  https://buildthentested.com/patterns/n-plus-one-queries/

- [ ] **List endpoints that return everything** (medium). Open your app's main list page in Chrome, press F12, choose the Network tab, filter by "Fetch/XHR" and reload.
  https://buildthentested.com/patterns/unpaginated-list-endpoints/

- [ ] **Whole table downloaded, filtered in the browser** (medium). Sign in to your app as a normal user, open a page that lists your own items, press F12, choose the Network tab, filter by "Fetch/XHR" and reload.
  https://buildthentested.com/patterns/whole-table-fetch-then-client-filter/

## Data integrity

- [ ] **Migrations that cannot be undone** (medium). Open the project's files (in the builder's code view or the synced GitHub repository) and find the supabase/migrations folder.
  https://buildthentested.com/patterns/migrations-not-reversible/

- [ ] **Timestamps stored without a time zone** (medium). In a test account, create a booking or event for a specific clock time tomorrow and note it.
  https://buildthentested.com/patterns/timezone-naive-timestamps/

## Deploy and config

- [ ] **Debug mode left on in production** (medium). On the live site, open a page address that does not exist, then open an API route with a broken parameter, for example a letter where an id is expected.
  https://buildthentested.com/patterns/debug-mode-on-in-production/

- [ ] **Missing security headers** (medium). Open your published app in Chrome or Firefox, press F12 and choose the Network tab.
  https://buildthentested.com/patterns/missing-security-headers/

- [ ] **No automated checks before deploy** (medium). Open the project's GitHub repository; if the builder has a GitHub sync, connect it first so the code is visible there.
  https://buildthentested.com/patterns/no-ci-pipeline/

- [ ] **Every change goes straight to production** (medium). Open your hosting dashboard (Vercel: the Deployments tab) or the builder's publish panel and look at the recent deployments.
  https://buildthentested.com/patterns/pushes-straight-to-production/

## Mobile

- [ ] **Certificate pinning absent** (medium). Search the project for pinning-related words: pin, sha256, certificate, network_security_config, NSPinnedDomains, trustkit.
  https://buildthentested.com/patterns/certificate-pinning-absent/

---

We test against a defined checklist and report what we find. We do not guarantee that an app is free of vulnerabilities. We are not a certified penetration-testing firm and do not issue compliance attestations. We do not rebuild your app; fixes are yours or your developer's, and we re-check them.

Questions: hello@buildthentested.com
