Inherited Codebase
Audit Checklist:
What to Review
Before You Estimate
or Rewrite
VNFlatform Engineering Team
An inherited codebase rarely arrives with a reliable explanation of how it works. It may come from a previous agency, a departed engineer, an acquisition, a rushed MVP, or months of AI-assisted changes. The repository is only one part of what has been inherited; the real system also includes data, cloud accounts, deployment processes, external services, undocumented decisions, and behavior that users already depend on.
A useful audit establishes evidence before anyone promises a delivery date or recommends a rewrite. It should explain what exists, what can be reproduced, which paths matter to the business, where material risks sit, and what information is still unknown. This checklist gives founders, CTOs, and delivery teams a practical way to structure that work.
An audit is not a style review
Naming, formatting, and folder structure can affect maintainability, but they do not determine whether a product is safe to operate or economical to change. A tidy repository can still have broken authorization, fragile deployments, and untested data migrations. A messy repository may contain stable business rules that would be expensive and risky to recreate.
The audit should connect technical observations to real consequences: data loss, unauthorized access, recurring incidents, blocked releases, slow changes, vendor dependency, or missing operational ownership. Findings without that connection are difficult to prioritize and easy to turn into an arbitrary rewrite proposal.
1. Establish ownership, access, and audit boundaries
Before running the project, identify what the organization actually controls. Record the source repositories, cloud and hosting accounts, domain and DNS access, databases, storage, CI/CD, app-store accounts, monitoring, email delivery, payment systems, and other external services.
- Confirm who owns each account and which people currently have access.
- Use named accounts where possible instead of shared credentials.
- Separate read-only audit access from permission to change production.
- Record missing access as an unknown rather than assuming the system is unused.
- Agree which environments, data, and third-party systems the audit may inspect.
Do not rotate credentials, delete resources, upgrade dependencies, or run unknown automation as an exploratory first step. Preserve evidence and establish a recovery path before changing the system.
2. Reproduce the build without relying on tribal knowledge
A new engineer should be able to obtain the repository, install the expected toolchain, configure a safe local or test environment, and start the relevant applications from written instructions. Compare those instructions with the commands the CI pipeline and deployment process actually use.
Review manifests and lifecycle scripts before executing them. Use non-production credentials and representative test data. Record missing runtime versions, lockfiles, private packages, configuration values, native toolchains, generated code, and external services. A successful build is evidence; a README that claims the build works is not.
3. Map the architecture and external dependencies
Create the smallest map that explains how requests and data move through the product. Include applications, APIs, background jobs, databases, queues, storage, authentication providers, payment or messaging systems, analytics, scheduled tasks, and deployment targets.
The map does not need to describe every class. It should identify system boundaries, owners, trust changes, and failure points. Compare the map with deployed infrastructure and runtime configuration; repositories often contain abandoned modules, while production may depend on services that are absent from the code.
4. Trace the business-critical workflows end to end
Choose the small set of workflows whose failure would affect users, money, data, contractual delivery, or daily operations. Trace each one from the interface through APIs, business rules, data changes, external calls, asynchronous work, and user-visible completion or failure.
- What starts the workflow, and who is allowed to start it?
- Which validations and permission checks run on the trusted side?
- What data changes, and can partial completion leave inconsistent state?
- Which external systems can delay, duplicate, or reject the operation?
- How does the user or operator know the final result?
This trace often reveals the real architecture more clearly than a broad folder-by-folder review. It also creates a practical basis for tests and estimates.
5. Inspect the data model, migrations, backups, and recovery
Identify the authoritative data stores and the relationships that encode important business rules. Review schema migrations, background data changes, retention behavior, deletion paths, imports, exports, and any manual repair scripts.
Confirm that backups exist for critical data and that restore procedures have been tested. Look for environments sharing the same database, production data copied into unsafe locations, migrations that cannot be replayed, and writes that can be duplicated. A rewrite proposal is not credible until the team understands how existing data will be preserved or transformed.
6. Review security controls at the real trust boundaries
Inspect authentication, session handling, authorization, input validation, secrets, administrative functions, file handling, APIs, logging, and data exposure. Verify behavior on the server or other trusted boundary rather than relying on hidden interface elements.
OWASP ASVS provides a structured catalogue for web application security verification. Select the relevant controls according to the product and data risk; do not describe the product as compliant without completing and documenting the required verification.
Security findings need careful handling. Record evidence without copying secrets or sensitive customer data into the report, and separate an exploitable issue from a theoretical improvement.
7. Inventory dependencies, licenses, and supply-chain exposure
Review direct and transitive dependencies, lockfiles, private packages, build plugins, container images, downloaded binaries, and third-party SDKs. Identify unused packages, unsupported versions, known vulnerabilities, unclear licenses, and dependencies that can run code during installation or build.
Use the tools appropriate to the repository host and package ecosystems. For repositories hosted on GitHub, the official dependency graph documentation explains how manifests, transitive paths, licenses, and known vulnerabilities can be inspected. Tool output is evidence to review, not an automatic severity or upgrade plan.
8. Measure testability and runtime visibility
Run the existing checks and record what each one actually covers. A large test count may miss the critical workflows, while a small set of end-to-end or integration checks may protect the most valuable behavior. Identify which important paths have no runnable check.
Then inspect runtime evidence: error reporting, structured logs, audit trails, health checks, job monitoring, release markers, and incident history. Confirm that failures are visible without exposing sensitive data. If the team cannot distinguish a code defect from a configuration, infrastructure, or third-party failure, estimates will include significant uncertainty.
9. Audit deployment and operational ownership
Document how code moves from review to production, who approves releases, which checks run, how configuration changes are controlled, and how a failed release is recovered. Compare the documented process with recent deployment history.
Review environment drift, manual server changes, database migration order, feature flags, rollback limits, scheduled jobs, certificates, domains, backups, and on-call or incident expectations. Do not infer a 24/7 support commitment from the existence of monitoring; availability and response coverage must be agreed separately.
10. Rank findings by consequence, evidence, and decision
A useful finding states what was observed, where the evidence came from, what can happen, which users or systems are affected, and what decision is recommended. Separate confirmed findings from assumptions and unknowns.
Rank work by material risk and delivery dependency, not by how unattractive the code looks. Group recommendations into immediate containment, required stabilization, delivery enablers, and longer-term improvements. Assign an owner or decision-maker to every accepted risk and proposed action.
When an estimate is still premature
A fixed estimate is not well founded when the product cannot be built, production behavior cannot be reproduced safely, critical data stores are unknown, or key third-party access is missing. In those cases, estimate the bounded discovery needed to resolve the unknowns rather than hiding them inside a delivery quote.
The audit should make uncertainty smaller. It cannot remove uncertainty by changing the wording of the proposal.
Refactor, stabilize, replace, or rewrite?
Choose at the level of a system boundary or workflow, not by applying one verdict to the entire repository. Preserve behavior that is understood, valuable, and adequately controlled. Stabilize important paths that work but lack tests, visibility, or safe deployment. Replace isolated components when their risk or operating cost is disproportionate. Rewrite only where the existing boundary cannot support the required behavior safely or economically.
A rewrite still needs a data migration, acceptance criteria, parallel verification, rollout plan, and fallback. It does not erase the obligation to understand the current product.
What the audit should deliver
- A verified system and ownership map.
- A list of critical workflows and their current controls.
- Confirmed findings, assumptions, and unresolved unknowns.
- A prioritized risk and delivery backlog.
- Recommended preserve, stabilize, replace, or rewrite decisions by area.
- The evidence and prerequisites needed for a responsible estimate.
For a broader secure-development reference, the NIST Secure Software Development Framework organizes practices around preparing the organization, protecting software, producing well-secured software, and responding to vulnerabilities. OWASP SAMM can help teams examine gaps across governance, design, implementation, verification, and operations. Use these frameworks as references, not as proof that an unaudited product meets them.
Need a bounded audit before committing to delivery?
VNFlatform's AI Code Rescue & Product Hardening path starts with a paid, fixed-scope technical audit. The objective is to establish evidence, identify priorities, and define the implementation scope before an estimate or proposal is accepted.
If the inherited product was built or heavily changed with AI tools, the AI-Built MVP Production Readiness Checklist provides a complementary launch-focused review.
The practical audit rule
Do not estimate the codebase you were told exists. Audit the system that can be reproduced, traced, and supported by evidence. The difference is where delivery risk hides.