Production readiness checklist
For web apps and AI-built apps, before you ship.
AI coding tools — Cursor, Lovable, Bolt, Replit, v0, Windsurf — make it fast to build and ship, and just as fast to launch with leaked keys, an open database, or a missing defence. This checklist walks the 198things UseShipReady checks on a live site, grouped in the order you’d work through them before launch. Each item links to a page explaining what it means and how to fix it. For why these particular failures recur in generated apps, see vibe coding security.
It’s generated from the scanner itself, so it always matches exactly what runs against your site. Start at the top — secrets and database access are where the launch-day disasters live.
If you run a formal production readiness review, this covers the externally observable half of it — what your software exposes to the internet on launch day. It does not cover capacity planning, on-call rotation or rollback procedure, which no scanner can see from outside.
Copy the checklist as a template
Markdown task list, ready to paste into an issue, a PR description or a doc. Select all and copy.
Production readiness checklist — 198 checks Generated from the UseShipReady scanner. https://useshipready.dev/checklist ## Secrets & API keys - [ ] Anthropic API Key Exposed - [ ] AWS Access Key Exposed - [ ] Cloudinary API Secret Exposed - [ ] Database Connection String Exposed - [ ] Exposed environment file (.env) - [ ] GitHub Token Exposed - [ ] Groq API Key Exposed - [ ] Hugging Face Token Exposed - [ ] npm Access Token Exposed - [ ] OpenAI API Key Exposed - [ ] OpenRouter API Key Exposed - [ ] Perplexity API Key Exposed - [ ] Private Key Exposed - [ ] PyPI API Token Exposed - [ ] Replicate API Token Exposed - [ ] Resend API Key Exposed - [ ] SendGrid API Key Exposed - [ ] Slack API Token Exposed - [ ] Stripe Secret Key Exposed - [ ] Stripe Webhook Signing Secret Exposed - [ ] Supabase Secret Key Exposed - [ ] xAI API Key Exposed - [ ] Mapbox Secret Token Exposed - [ ] Slack Incoming Webhook URL Exposed - [ ] Stripe Restricted Key Exposed - [ ] Potential Secret or Private Token Exposed ## AI coding-tool exposure - [ ] Secret published through a browser-exposed environment variable - [ ] AI provider client is configured to run in the browser - [ ] Exposed AI tooling config that can contain credentials - [ ] MCP server is reachable without authentication - [ ] AI system prompt is hardcoded in the browser bundle - [ ] Exposed AI Tooling Config File - [ ] AI builder fingerprint exposed - [ ] AI widget missing SRI - [ ] AI endpoints are reachable from your client code ## Database & backend access - [ ] Firebase Realtime Database is publicly readable - [ ] Firebase Storage bucket is publicly listable - [ ] Anyone can sign up with an email address they do not own - [ ] Anyone can make your project send an SMS - [ ] Anyone can obtain a signed-in session without an account - [ ] Public Supabase Storage bucket - [ ] Supabase table is publicly readable ## HTTPS & TLS - [ ] HTTP is not redirected to HTTPS - [ ] TLS certificate does not validate - [ ] TLS certificate expiring - [ ] Server still accepts a deprecated TLS version ## Security headers - [ ] Missing Content-Security-Policy header - [ ] CSP allows 'unsafe-eval' - [ ] CSP allows 'unsafe-inline' scripts - [ ] CSP script-src allows an overly permissive source - [ ] Missing or permissive X-Frame-Options header - [ ] Missing Strict-Transport-Security header - [ ] Invalid Referrer-Policy value - [ ] Missing or invalid X-Content-Type-Options header - [ ] Missing Referrer-Policy header - [ ] Response header discloses a software version - [ ] Strict-Transport-Security is missing includeSubDomains - [ ] Weak Strict-Transport-Security max-age ## Cookies & sessions - [ ] Session Cookie Missing 'HttpOnly' Flag - [ ] Session Cookie Missing 'Secure' Flag - [ ] Session Cookie Missing 'SameSite' Attribute - [ ] Session Cookie Uses 'SameSite=None' Without 'Secure' ## Information disclosure - [ ] Exposed .git Directory - [ ] Exposed docker-compose file - [ ] Overly Permissive CORS with Credentials - [ ] Directory Listing Enabled - [ ] Error page leaks a stack trace - [ ] Exposed Debug or Config Endpoint - [ ] GraphQL introspection is enabled in production - [ ] Exposed .DS_Store file - [ ] Exposed JavaScript Source Map ## Payments - [ ] A payment form submits over an unencrypted http:// connection - [ ] Card details are collected by your own page, not a hosted payment field - [ ] Payment test mode key - [ ] Working discount codes are compiled into the browser bundle - [ ] A PayPal order is priced in the browser - [ ] Both live and test Stripe keys are shipped to the browser - [ ] Checkout price is submitted from a hidden form field - [ ] Checkout request sends an amount built in the browser ## Email deliverability & anti-spoofing - [ ] More than one DMARC record is published - [ ] Multiple SPF records published - [ ] MX record points to a hostname with no address - [ ] SPF explicitly authorizes any server to send mail - [ ] BIMI logo could not be fetched - [ ] BIMI record has no usable logo location - [ ] DKIM key is published but revoked - [ ] DKIM public key is not valid base64 - [ ] DMARC record has no usable policy - [ ] Domain sends email but cannot receive it - [ ] Email configuration incomplete - [ ] MTA-STS policy file could not be fetched - [ ] MTA-STS policy file is malformed - [ ] No DKIM signature configured - [ ] No DMARC record found - [ ] No SPF record found - [ ] SPF record contains an unrecognized term - [ ] SPF record exceeds the 10 DNS-lookup limit - [ ] SPF record says nothing about servers it does not list - [ ] BIMI logo does not look like an SVG - [ ] DKIM record declares an unrecognized key type - [ ] DMARC has no aggregate reporting address - [ ] DMARC policy applies to only part of your mail (pct < 100) - [ ] DMARC policy is set to 'none' - [ ] DMARC reports are sent to a domain that has not authorised them - [ ] DMARC treats subdomains more leniently than the domain itself - [ ] Eligible for BIMI but not configured - [ ] Eligible for MTA-STS but not configured - [ ] MX host has no reverse DNS (PTR) record ## Launch readiness - [ ] A development build is being served to real visitors - [ ] Missing Basic HTML Metadata - [ ] Page says it does not exist but returns a success status - [ ] Placeholder template content is still live on the site - [ ] Production build points at localhost - [ ] Production build references a staging or preview environment - [ ] Shipped JavaScript logs sensitive data to the browser console - [ ] Unedited Scaffold Branding - [ ] Missing Proper 404 Status Code - [ ] Missing robots.txt - [ ] No sitemap is discoverable - [ ] The site has no browser-tab icon ## SEO & AI visibility - [ ] Your robots.txt tells search engines to stay out of the whole site - [ ] Your site tells search engines not to index it - [ ] AI assistants are blocked from reading your site - [ ] Canonical URL points to a different domain - [ ] Page declares more than one canonical URL - [ ] Page title tag is empty - [ ] Sitemap is published but lists no URLs - [ ] Sitemap is served but cannot be parsed - [ ] Sub-page canonicalises to the homepage - [ ] Your CDN blocks AI crawlers before they reach your site - [ ] Article does not declare its author or publication date - [ ] Meta description is long enough to be truncated - [ ] No canonical URL declared - [ ] No mobile viewport declared - [ ] No social preview image - [ ] No structured data found - [ ] Page has no H1 heading - [ ] Page title is long enough to be truncated in search results - [ ] Sitemap has not been updated in over a year ## More checks - [ ] Exposed git credentials file - [ ] Exposed SQL database dump - [ ] Subdomain takeover - [ ] A redirect parameter sends visitors to any URL it is given - [ ] A response sets a session cookie and allows shared caching - [ ] A sign-in form puts the password in the URL - [ ] A sign-in form sends passwords over an unencrypted connection - [ ] AI assistant response text left in the page - [ ] Broken internal link - [ ] Exposed config file containing credentials - [ ] Exposed internal/monitoring endpoint - [ ] Exposed version-control directory - [ ] Legal page placeholder - [ ] Pricing contradiction - [ ] The contact address on your site cannot receive mail - [ ] Unrendered template variable on the page - [ ] A device-fingerprinting script is present - [ ] A form collecting personal data submits via GET - [ ] A JavaScript bundle is large enough to make the page feel slow - [ ] A placeholder contact address is published on the site - [ ] An image is large enough to be slowing the page down - [ ] Dead link target - [ ] Embedded frames have no title - [ ] Form fields have no associated label - [ ] Image buttons have no text alternative - [ ] Images have no text alternative - [ ] Insecure (http) resources loaded on a secure page - [ ] No privacy policy link found - [ ] Real visitors wait too long to see your main content - [ ] Session-replay or behaviour-recording script is present - [ ] Several pages share the same title - [ ] The page does not declare a language - [ ] The page is served without compression - [ ] The page is slow to respond when people tap or click - [ ] The page moves under people while it loads - [ ] The page prevents pinch-to-zoom - [ ] The page refreshes or redirects itself on a timer - [ ] Third party script missing SRI - [ ] Tracking cookie is set before the consent banner can be answered - [ ] Tracking cookie is set on the first response - [ ] Unremoved builder attribution - [ ] Your API documentation is publicly reachable - [ ] A stylesheet loads without an integrity check - [ ] Analytics or advertising tracker loads without a detected consent step - [ ] Build assets are served without caching - [ ] Fonts are loaded from Google's servers - [ ] Heading levels are skipped - [ ] Headings have no text - [ ] Images have no width and height - [ ] No terms of service link found - [ ] Outbound links lead to pages that are gone - [ ] Several pages share the same meta description - [ ] Several scripts block the page from rendering - [ ] Stale copyright year - [ ] The page is reached through a chain of redirects - [ ] Third-party content is embedded on the page - [ ] Your privacy policy does not appear to name a service the site uses - [ ] Your privacy policy gives no way to contact you - [ ] Your app calls routes that cost money per request
01Secrets & API keys26
The most common and most damaging mistake in AI-built apps: a real credential shipped into client JavaScript or a committed .env served publicly. Treat anything found here as already compromised — rotate it, then move it server-side.
- Anthropic API Key Exposedcritical
- AWS Access Key Exposedcritical
- Cloudinary API Secret Exposedcritical
- Database Connection String Exposedcritical
- Exposed environment file (.env)critical
- GitHub Token Exposedcritical
- Groq API Key Exposedcritical
- Hugging Face Token Exposedcritical
- npm Access Token Exposedcritical
- OpenAI API Key Exposedcritical
- OpenRouter API Key Exposedcritical
- Perplexity API Key Exposedcritical
- Private Key Exposedcritical
- PyPI API Token Exposedcritical
- Replicate API Token Exposedcritical
- Resend API Key Exposedcritical
- SendGrid API Key Exposedcritical
- Slack API Token Exposedcritical
- Stripe Secret Key Exposedcritical
- Stripe Webhook Signing Secret Exposedcritical
- Supabase Secret Key Exposedcritical
- xAI API Key Exposedcritical
- Mapbox Secret Token Exposedhigh
- Slack Incoming Webhook URL Exposedhigh
- Stripe Restricted Key Exposedhigh
- Potential Secret or Private Token Exposedmedium
02AI coding-tool exposure9
Files and keys AI builders leave behind — tool config and instruction files served to the public, and provider keys inlined into the browser bundle. They map your stack for an attacker and hand over working credentials.
- Secret published through a browser-exposed environment variablecritical
- AI provider client is configured to run in the browserhigh
- Exposed AI tooling config that can contain credentialshigh
- MCP server is reachable without authenticationhigh
- AI system prompt is hardcoded in the browser bundlemedium
- Exposed AI Tooling Config Filemedium
- AI builder fingerprint exposedlow
- AI widget missing SRIlow
- AI endpoints are reachable from your client codeinfo
03Database & backend access7
Whether your Supabase or Firebase backend actually enforces access control. A missing Row Level Security policy or a public storage bucket means anyone with the public key in your JavaScript can read — or change — your data. Building on Supabase? See the focused Supabase checklist. Supabase security checklist →
- Firebase Realtime Database is publicly readablecritical
- Firebase Storage bucket is publicly listablecritical
- Anyone can sign up with an email address they do not ownhigh
- Anyone can make your project send an SMSmedium
- Anyone can obtain a signed-in session without an accountmedium
- Public Supabase Storage bucketmedium
- Supabase table is publicly readablemedium
04HTTPS & TLS4
That connections are encrypted, modern and forced. Deprecated TLS versions and a missing HTTP→HTTPS redirect leave traffic open to downgrade and interception.
05Security headers12
The response headers browsers rely on to contain attacks — Content-Security-Policy, HSTS, X-Content-Type-Options and more. Rarely exploitable alone, but their absence weakens every other defence.
- Missing Content-Security-Policy headerhigh
- CSP allows 'unsafe-eval'medium
- CSP allows 'unsafe-inline' scriptsmedium
- CSP script-src allows an overly permissive sourcemedium
- Missing or permissive X-Frame-Options headermedium
- Missing Strict-Transport-Security headermedium
- Invalid Referrer-Policy valuelow
- Missing or invalid X-Content-Type-Options headerlow
- Missing Referrer-Policy headerlow
- Response header discloses a software versionlow
- Strict-Transport-Security is missing includeSubDomainslow
- Weak Strict-Transport-Security max-agelow
06Cookies & sessions4
That session cookies carry the flags keeping them out of JavaScript and off unencrypted connections. Missing HttpOnly, Secure or SameSite turns an XSS or CSRF bug into a full session takeover.
07Information disclosure9
Internal files and endpoints that should never be reachable in production — an exposed .git directory or source map, a debug endpoint, a stack trace, a directory listing, or CORS that trusts any origin. Each hands an attacker reconnaissance or data.
- Exposed .git Directoryhigh
- Exposed docker-compose filehigh
- Overly Permissive CORS with Credentialshigh
- Directory Listing Enabledmedium
- Error page leaks a stack tracemedium
- Exposed Debug or Config Endpointmedium
- GraphQL introspection is enabled in productionmedium
- Exposed .DS_Store filelow
- Exposed JavaScript Source Maplow
08Payments8
That a live site charges through live payment credentials. A test-mode Stripe key on production means real checkouts look like they work but silently collect no money.
- A payment form submits over an unencrypted http:// connectionhigh
- Card details are collected by your own page, not a hosted payment fieldhigh
- Payment test mode keyhigh
- Working discount codes are compiled into the browser bundlehigh
- A PayPal order is priced in the browsermedium
- Both live and test Stripe keys are shipped to the browsermedium
- Checkout price is submitted from a hidden form fieldmedium
- Checkout request sends an amount built in the browsermedium
09Email deliverability & anti-spoofing29
The DNS records that let your transactional email arrive and stop others forging your domain — SPF, DKIM, DMARC and MX. Missing records send password resets to spam and let anyone phish your users from your own address.
- More than one DMARC record is publishedhigh
- Multiple SPF records publishedhigh
- MX record points to a hostname with no addresshigh
- SPF explicitly authorizes any server to send mailhigh
- BIMI logo could not be fetchedmedium
- BIMI record has no usable logo locationmedium
- DKIM key is published but revokedmedium
- DKIM public key is not valid base64medium
- DMARC record has no usable policymedium
- Domain sends email but cannot receive itmedium
- Email configuration incompletemedium
- MTA-STS policy file could not be fetchedmedium
- MTA-STS policy file is malformedmedium
- No DKIM signature configuredmedium
- No DMARC record foundmedium
- No SPF record foundmedium
- SPF record contains an unrecognized termmedium
- SPF record exceeds the 10 DNS-lookup limitmedium
- SPF record says nothing about servers it does not listmedium
- BIMI logo does not look like an SVGlow
- DKIM record declares an unrecognized key typelow
- DMARC has no aggregate reporting addresslow
- DMARC policy applies to only part of your mail (pct < 100)low
- DMARC policy is set to 'none'low
- DMARC reports are sent to a domain that has not authorised themlow
- DMARC treats subdomains more leniently than the domain itselflow
- Eligible for BIMI but not configuredlow
- Eligible for MTA-STS but not configuredlow
- MX host has no reverse DNS (PTR) recordlow
10Launch readiness12
The basics that signal a finished product rather than a preview: a real 404 page, a robots.txt and sitemap, page metadata, and no leftover starter-template branding.
- A development build is being served to real visitorsmedium
- Missing Basic HTML Metadatamedium
- Page says it does not exist but returns a success statusmedium
- Placeholder template content is still live on the sitemedium
- Production build points at localhostmedium
- Production build references a staging or preview environmentmedium
- Shipped JavaScript logs sensitive data to the browser consolemedium
- Unedited Scaffold Brandingmedium
- Missing Proper 404 Status Codelow
- Missing robots.txtlow
- No sitemap is discoverablelow
- The site has no browser-tab iconlow
11SEO & AI visibility19
Whether search engines and AI assistants can reach your pages at all — a stray noindex, a rule blocking AI crawlers, a canonical pointing at the wrong page, or a sitemap that no longer parses can each make a finished site invisible.
- Your robots.txt tells search engines to stay out of the whole sitehigh
- Your site tells search engines not to index ithigh
- AI assistants are blocked from reading your sitemedium
- Canonical URL points to a different domainmedium
- Page declares more than one canonical URLmedium
- Page title tag is emptymedium
- Sitemap is published but lists no URLsmedium
- Sitemap is served but cannot be parsedmedium
- Sub-page canonicalises to the homepagemedium
- Your CDN blocks AI crawlers before they reach your sitemedium
- Article does not declare its author or publication datelow
- Meta description is long enough to be truncatedlow
- No canonical URL declaredlow
- No mobile viewport declaredlow
- No social preview imagelow
- No structured data foundlow
- Page has no H1 headinglow
- Page title is long enough to be truncated in search resultslow
- Sitemap has not been updated in over a yearlow
12More checks59
Additional checks UseShipReady runs.
- Exposed git credentials filecritical
- Exposed SQL database dumpcritical
- Subdomain takeovercritical
- A redirect parameter sends visitors to any URL it is givenhigh
- A response sets a session cookie and allows shared cachinghigh
- A sign-in form puts the password in the URLhigh
- A sign-in form sends passwords over an unencrypted connectionhigh
- AI assistant response text left in the pagehigh
- Broken internal linkhigh
- Exposed config file containing credentialshigh
- Exposed internal/monitoring endpointhigh
- Exposed version-control directoryhigh
- Legal page placeholderhigh
- Pricing contradictionhigh
- The contact address on your site cannot receive mailhigh
- Unrendered template variable on the pagehigh
- A device-fingerprinting script is presentmedium
- A form collecting personal data submits via GETmedium
- A JavaScript bundle is large enough to make the page feel slowmedium
- A placeholder contact address is published on the sitemedium
- An image is large enough to be slowing the page downmedium
- Dead link targetmedium
- Embedded frames have no titlemedium
- Form fields have no associated labelmedium
- Image buttons have no text alternativemedium
- Images have no text alternativemedium
- Insecure (http) resources loaded on a secure pagemedium
- No privacy policy link foundmedium
- Real visitors wait too long to see your main contentmedium
- Session-replay or behaviour-recording script is presentmedium
- Several pages share the same titlemedium
- The page does not declare a languagemedium
- The page is served without compressionmedium
- The page is slow to respond when people tap or clickmedium
- The page moves under people while it loadsmedium
- The page prevents pinch-to-zoommedium
- The page refreshes or redirects itself on a timermedium
- Third party script missing SRImedium
- Tracking cookie is set before the consent banner can be answeredmedium
- Tracking cookie is set on the first responsemedium
- Unremoved builder attributionmedium
- Your API documentation is publicly reachablemedium
- A stylesheet loads without an integrity checklow
- Analytics or advertising tracker loads without a detected consent steplow
- Build assets are served without cachinglow
- Fonts are loaded from Google's serverslow
- Heading levels are skippedlow
- Headings have no textlow
- Images have no width and heightlow
- No terms of service link foundlow
- Outbound links lead to pages that are gonelow
- Several pages share the same meta descriptionlow
- Several scripts block the page from renderinglow
- Stale copyright yearlow
- The page is reached through a chain of redirectslow
- Third-party content is embedded on the pagelow
- Your privacy policy does not appear to name a service the site useslow
- Your privacy policy gives no way to contact youlow
- Your app calls routes that cost money per requestinfo
Check your site against the whole list
UseShipReady runs every check here across up to ten pages of your live site and reports what it finds, with a paste-ready fix for each. Free, no signup.