Use code SUMMERCODING at checkout for one month free Get Started →
All posts
SecurityJun 24, 202610 min read

How to Audit Your GitHub Repo Before Launch

Shipping soon? Here is the pre-launch audit checklist to catch exposed secrets, missing error handling, and security gaps before your repo goes live.

Launch day has a particular feeling to it. You are checking that the app loads, that payments go through, that the sign-up flow works. You are not thinking about whether a .env file got committed six weeks ago, or whether the admin route you built in hour two of the project has any authentication on it. Those things are not on the critical path in your head. They are background noise.

That is exactly the problem. The hour before launch is when your attention is on features working, not on failure modes. It is the highest-leverage moment to catch the gaps that will matter most after you ship, and it is also the moment when developers are least likely to go looking for them. The checklist below is designed for that window. Run it before the repo goes live.

This is not about being paranoid. It is about the fact that the things that go wrong in production are almost never the things you were worried about. They are the ones you forgot to worry about. A fast audit before launch is how you close that gap.

Why Pre-Launch Is the Highest-Risk Moment

When a project is live, you have ongoing visibility. Users report bugs. Monitors alert on errors. You are watching. Before launch, you are in sprint mode, moving fast, and trusting that you caught everything during development because you have been looking at this code for weeks.

The urgency trap works like this: shipping feels like the goal, and anything that delays shipping feels like friction. So the checklist items that would catch a critical issue get skipped because they do not feel urgent. But the moment the repo is public, the calculus flips entirely. A secret that was accidentally committed becomes exploitable. An unprotected route becomes accessible. A verbose error message starts leaking server details to anyone who hits the right endpoint.

Real attackers and bots do not wait for you to notice. Scanning for exposed credentials on newly public repositories is automated. Probing common unprotected routes is automated. The assumption that you have time to fix things after launch is usually wrong. The audit needs to happen before.

The Audit Checklist

Secrets and Credentials

This is the one to take most seriously. A single exposed API key can mean a drained account, a compromised service, or a bill you did not expect.

  • Hardcoded API keys and tokens. Search the entire repository history, not just the current files, for patterns like sk_live_, AKIA, ghp_, and common secret prefixes. Git history preserves deleted files. A key you removed from the code three commits ago is still in the history and still exploitable.
  • .env files accidentally committed. Run git log --all --full-history -- .env to check whether any .env file has ever been committed. Also check .env.local, .env.production, and similar variants. If any appear, the secret values in them need to be rotated immediately, not just the file removed.
  • Exposed .git/config. If your app is served from the same directory where the repo lives, the .git folder may be publicly accessible. Check that your web server configuration blocks access to .git/. An exposed .git/config leaks your remote URL and can allow someone to reconstruct your entire codebase.
  • Leftover test credentials. API keys, passwords, or tokens used during development that are different from production credentials. Check for strings like test_, sandbox_, or dev_ that might indicate credentials that were never meant to ship but made it in anyway.
  • Secrets in config files or build output. Check your build output directory for any compiled files that might have inlined environment variables. Some bundler configurations inline process.env values at build time, which ends up shipping secrets in client-side JavaScript.

Error Handling

Errors in production are unavoidable. What matters is how they fail. An unhandled exception that crashes a server process is a reliability problem. An error response that leaks a stack trace or database schema is both a reliability problem and a security one.

  • Unhandled exceptions in server code. Look for async functions that are not wrapped in try/catch, promise chains without .catch(), and routes that do not handle the case where a downstream call throws. An unhandled rejection in Node.js will crash the process or produce a 500 with no meaningful response.
  • Verbose error responses leaking stack traces. Check every error handler and confirm that it does not return the raw error object or stack trace to the client. The error message a user sees should never include file paths, line numbers, database query text, or server internals. Log those things server-side; return a generic message to the client.
  • Missing fallback states in the UI. What does the user see when an API call fails? If the answer is nothing, or a white screen, or a JavaScript error, that needs a fallback. Check every data-fetching component and confirm there is an error state that actually renders something useful.
  • No timeouts on external calls. If your app calls an external API, payment processor, or AI service without a timeout, a slow or hung response will block the user-facing request indefinitely. Set explicit timeouts on every outbound HTTP call.

Access Control

Access control bugs are easy to miss because they require thinking about what a malicious user would do, not what a normal user would do. Run through these with an adversarial mindset.

  • Auth checks on every protected route. Go through every API route and page that requires authentication and confirm that the auth check happens at the route level, not just in the UI. Hiding a button in the frontend does not protect the route it calls. Test each protected endpoint directly with no session cookie or token and confirm it returns 401 or 403, not the data.
  • IDOR gaps (one user accessing another's data). Look for any endpoint that accepts a resource ID in the URL or request body and returns or modifies a resource by that ID. If the only check is that the user is authenticated, but not that the resource belongs to them, any authenticated user can access any other user's data by changing the ID. Every resource lookup needs a check that the requesting user owns that resource.
  • Admin routes properly locked down. Check every admin or internal route and confirm it validates that the authenticated user has admin privileges, not just that they are authenticated. A regular user who discovers an admin route URL should get a 403, not admin functionality.
  • Password reset and account modification flows. Confirm that password reset tokens are single-use and expire, that email change flows require verification of the new address, and that account deletion or privilege changes require re-authentication. These flows are targeted in credential stuffing attacks specifically because they are often under-tested.

Dependencies

  • Outdated packages with known CVEs. Run npm audit or yarn audit and look at the results. High and critical severity issues in packages on the direct dependency path should be resolved before launch. Not all of them will be exploitable in your specific usage, but you should know which ones are present.
  • Unused dependencies bloating the attack surface. Every package you ship is a potential vector. Packages you installed to test something and never removed are still in your dependency tree and still subject to supply chain attacks. Check package.json and remove anything that is not actually used in production code.
  • Packages pulling in unexpected transitive dependencies. Run npm ls and spot-check packages that seem heavier than expected. An innocuous utility package that pulls in a network-capable transitive dependency is worth noticing.

Production Config

Configuration mistakes are easy to make and easy to miss because they often look correct in development but behave differently in production.

  • Debug mode disabled. Confirm that any debug flags, verbose logging modes, or development-only middleware are disabled in the production environment. Development error overlays, debug endpoints, and verbose query logging should not be active when the app is live.
  • CORS not wide open. If your API uses CORS, check the configuration and confirm that Access-Control-Allow-Origin: * is not set on endpoints that return authenticated data or accept state-changing requests. CORS wildcard is fine for truly public read-only APIs. It is not fine for anything that touches user data.
  • Rate limiting in place. Without rate limiting, your login endpoint, signup flow, password reset, and any expensive compute endpoint are open to brute force or abuse. Confirm that rate limiting is configured before launch, not added reactively after the first incident.
  • Logging configured correctly. Check that your logging setup captures errors and important events, but is not logging sensitive data: passwords, tokens, full request bodies that might contain PII, or database query results. Logs are often less protected than databases and more broadly accessible within an organization.
  • HTTPS enforced. Confirm that HTTP traffic is redirected to HTTPS and that your TLS configuration is current. Check that cookies are set with the Secure and HttpOnly flags and that session tokens are not exposed to JavaScript unnecessarily.

The 10-Minute Version

If you are not going to run the full audit, run at least these. They are the four checks with the highest probability of catching something that will cause a real incident:

  1. Search git history for secrets. Run git log -p | grep -i "api_key\|secret\|password\|token" and scan the output. Anything that looks like a real credential needs to be rotated before you ship.
  2. Test every protected route without auth. Pick five of your most sensitive API endpoints and call them with no authentication headers. They should all return 401 or 403. If any return data, you have an access control gap.
  3. Run npm audit. Check for high and critical severity vulnerabilities. Resolve or consciously accept each one before launch.
  4. Check one error path end-to-end. Trigger a real error in your app and look at what the user sees and what gets logged. If the user sees a stack trace, fix the error handler. If nothing gets logged, fix the logging.

What Happens If You Skip This

Skipping the audit is not a low-probability risk. It is a matter of timing. The things this checklist catches are the things that get found after launch, not if.

An exposed API key in a public repository gets scraped by bots within minutes of the repo going live. This is not hypothetical. There are services that continuously monitor GitHub for newly pushed credentials. The key gets used before most people would even notice it was there.

An IDOR vulnerability does not require a sophisticated attacker. A curious user who changes a numeric ID in a URL and finds someone else's data will report it. Or they will not report it. Either way, the data was accessible.

A verbose error response that includes a stack trace or database schema tells an attacker exactly where to look next. It turns a general probe into a targeted one. These are not dramatic, movie-hacker scenarios. They are the boring, routine ways that production applications get compromised, and they are all preventable with an hour of work before launch.

The gap between "this probably works" and "I confirmed this is safe" is exactly where production incidents live.

Closing

The checklist in this post takes about an hour to run properly. That is worth it. The alternative is spending significantly more time cleaning up after something that was preventable.

If you want to move faster on this, GitDoctor can automate most of the mechanical parts: scanning your repository for exposed secrets and credentials, flagging security gaps in your code, and surfacing dependency vulnerabilities before they become incidents. You get the specific findings with context, not just a raw list of issues.

Whether you use a tool or run the checklist manually, the goal is the same: know what is in your repo before the public does. The checklist exists so the audit is repeatable, not something you reconstruct from memory each time. Run it before you ship, and then run it again the next time. The gaps it catches will be different ones.

Automate the audit

Find the gaps before your users do

GitDoctor scans your GitHub repository for exposed secrets, security vulnerabilities, and missing safeguards. Each finding comes with an AI prompt to fix it. First scan is free.

Scan your repo