Code audit before taking over or rebuilding software: what to check

Before taking over or rebuilding a software project: dependencies, tests, documentation, security and what the audit report must tell whoever decides.

The agency that built your business software closes, the in-house developer leaves, or a new vendor proposes starting again from scratch. Someone in the company has to decide, usually without being able to read the code. This article is for that person: what a code audit should check before you sign, and what to expect from the report.

In short

  • Before the code, check that you hold everything: repository, servers, domain, database, accounts.
  • An unsupported language, framework or library is a security risk, and catching up has a cost that needs estimating.
  • Without automated tests, every change is checked by hand or discovered by your users.
  • If only one person knows how the software is installed and released, writing that down comes first.
  • Rewriting from scratch is the riskiest option. Sometimes it’s the right one, but it needs a reason.
  • The report should say what each problem means for the business and in which order to tackle it.

Before the code: what you actually own

A takeover can stall before anyone opens a file. The questions are simple:

  • Is the code in a repository with its full change history, or did you receive a zip file?
  • Who is the registered owner of the hosting, the domain, the app store accounts and external services (email, payments, maps)?
  • Do you have admin credentials for the database and control panels, or does only the previous vendor?
  • Are there paid components licensed to someone else?
  • Following the available instructions, can a newcomer install the project on a clean machine?

The last one is the most telling test. If it fails, the documentation is missing and part of the knowledge lives in someone’s head.

Dependencies and stalled versions

All software sits on third-party components: the language, the framework, dozens or hundreds of libraries. OWASP has listed this among the top web application security risks since 2013; in the 2025 edition it ranks third as “Software Supply Chain Failures” (OWASP Top 10:2025, A03). According to OWASP you are likely exposed if you don’t track the versions of every component, including the dependencies of your dependencies, or if anything you run is vulnerable, unsupported or out of date, from the operating system to the libraries.

Every PHP release branch gets two years of full support and two more of security fixes only, then reaches end of life (php.net). PHP 7.4 has had no fixes since 28 November 2022, PHP 8.1 none since 31 December 2025 (php.net, unsupported branches). Node.js 18 and 20 are also listed as end of life on the official releases page (nodejs.org).

What I look at here:

  • the language and framework versions against their support dates;
  • the lockfile that pins library versions (without it, two installs of the same project can behave differently);
  • known vulnerabilities and abandoned packages, with tools such as npm audit or composer audit.

A decision maker needs to know how far the project is from a supported version and how much work closing that gap takes. Two hundred warnings on minor libraries can matter less than one framework that is three major versions behind.

AI-generated code that was never cleaned up

A lot of code is now written with AI help, and it shows in the projects I review: files and functions far longer than they need to be, generated code that was never cleaned up, the same logic repeated in several places. GitClear, which sells code analysis tools, looked at 211 million changed lines from 2020 to 2024 and reports a spike in duplicated code blocks (GitClear).

The cost comes twice. The code is harder to read and fix for whoever comes next. And if the team keeps working on it with AI, every change burns more tokens than it should, because the model has to re-read all that code. Through the APIs, the tokens a model reads are billed too (Anthropic pricing).

I use Claude Code every day myself, alongside review agents and automated tests. The trouble starts when generated code goes in exactly as it came out. The audit marks where the code can be shortened and in which order it pays to do it.

Tests: what happens when you change something

Automated tests check that the software still does what it should after a change. Four questions: do they exist, do they still run, do they cover the flows that matter (payments, sign-ups, calculations, invoicing), and do they run on their own on every change?

You can still take over a project with no tests. You start by writing tests around the critical flows to pin down the current behaviour, and only then touch the fragile parts. That work belongs in the quote from day one.

Documentation, and knowledge in one person’s head

A project can run for years as long as the person who wrote it is around. The steps to release an update exist only in their memory, and some business rules (why the discount is calculated that way, why that field is mandatory) exist only in the code. OWASP treats this as a security issue as well: no single person should be able to write code and push it all the way to production without someone else reviewing it (A03).

Things to check:

  • is there a document explaining how to install, configure and release the software?
  • is there a test environment separate from the live one?
  • are releases automated, or does one person do them by hand?
  • are the main business rules written down anywhere?

Security basics

A code audit doesn’t replace a penetration test. Reading the code, though, some problems show up quickly:

  • Passwords and keys in the code. OWASP notes that many organisations keep them hardcoded in plain text in source code and configuration files (OWASP Secrets Management). If they ever reached the repository they must be changed, because deleting them leaves them in the change history.
  • Access control. It is the top risk in the OWASP 2025 list, and OWASP found some form of it in 100% of the applications tested (A01). The classic example: change a number in the page address and you see another customer’s order or record.
  • Backups and restores. If the software handles personal data, the GDPR requires the ability to restore access to it promptly after an incident, and regular testing of security measures (GDPR, art. 32). Ask when a test restore was last done.

Rewrite or fix it piece by piece

When a project is in bad shape, starting over looks clean. Martin Fowler writes that he and his colleagues have seen this plan fail most of the time: replacing a serious system takes a long time, users can’t wait for new features, and working out what the existing system does is harder than it looks (Fowler, Strangler Fig). Joel Spolsky’s example was Netscape, which went almost three years without a major release while rewriting its code from scratch; old code holds years of bug fixes found in real use, and a rewrite throws them away (Spolsky).

The alternative is to replace the software one part at a time, starting with the most fragile parts or the ones that change most often, while the rest keeps running.

A rewrite makes sense when:

  • the technology is abandoned and there is no upgrade path;
  • the software must now do something quite different, and little of the current code would survive;
  • the project is small enough that rebuilding it costs less than understanding it;
  • every change breaks something else, there are no tests and nobody knows the code.

Otherwise, gradual repair is usually the better bet. If after the audit you still decide to rebuild everything, you decide with the facts in hand.

What the report should give you

The report is for the person who decides, so a list of issues exported from a tool isn’t enough. It should include:

  1. A one-page summary: can the team work on this project, under what conditions, with what risks.
  2. Each problem with its consequence in business terms. “The server runs PHP 7.4, which has had no security fixes since November 2022” tells you something; “outdated PHP version” doesn’t.
  3. Priorities: what to do now, what in the next few months, what can wait.
  4. Rough estimates for each block of work, so you can compare them with vendor quotes.
  5. An answer to your actual question: take over or rebuild, or whether the vendor’s proposal makes sense.
  6. A separate technical section for whoever will work on the code.

Ask for a meeting to go through it, open to your team or your vendor.

If you’re about to take over a project or weigh a rebuild proposal, here’s how I work: code audit and technical second opinion.

Articles

All articles