Every system accumulates debt. That's not a moral failing — it's a natural consequence of building software under real-world constraints. Deadlines compress. Requirements shift. The developer who architected the database left two years ago. What remains is a system that works, mostly, but nobody can say with confidence where the risks are.
A codebase health audit is the antidote to that uncertainty. It's a systematic, evidence-based examination of your system's architecture, security posture, dependency chain, and operational characteristics. The output is not a generic report — it's a prioritized remediation roadmap that tells you what to fix first and why.
What we examine
1. Architecture and complexity
The first question: how is this system structured, and how much resistance will it offer to change?
We measure:
- Cyclomatic complexity — how many independent paths exist through each function. Functions with complexity above 15 are hard to test, hard to modify, and disproportionately likely to contain bugs.
- Module coupling — how tightly different parts of the system depend on each other. High coupling means changes cascade unpredictably.
- Dead code — functions, classes, and files that exist but are never called. Dead code is not harmless — it clutters search results, confuses new developers, and occasionally gets accidentally re-activated.
- Dependency depth — how many layers deep a function call goes before it hits the database or an external service. Deep call stacks are fragile and hard to debug.
Tools we use: PHPStan, ESLint with complexity rules, SonarQube, custom static analysis scripts.
2. Test coverage and quality
Test coverage is one of the most misunderstood metrics in software. 80% coverage means nothing if the tests don't cover the paths that matter.
We look at:
- Coverage percentage on business-critical paths — the code that handles money, authentication, data mutation, and external integrations.
- Test quality — do the tests actually assert meaningful outcomes, or do they just check that functions don't throw exceptions?
- Test infrastructure — can you run the test suite locally in under 5 minutes? If not, developers won't run it, and it stops being useful.
- Missing test categories — integration tests, end-to-end tests, load tests. Unit tests alone don't catch the bugs that take production down.
3. Dependency chain
Every third-party library your application uses is code you didn't write, don't control, and probably don't monitor.
We audit:
- Known CVEs — using tools like
npm audit,composer audit,pip-audit, or Snyk to cross-reference every dependency against the National Vulnerability Database. - End-of-life dependencies — libraries that are no longer maintained. No new releases means no security patches.
- Phantom dependencies — libraries that are installed but never imported. They add attack surface without providing value.
- License compliance — GPL, AGPL, and SSPL dependencies can have legal implications for commercial software. Most teams don't check.
4. Security posture
This is where my background in IT audit at EY directly applies. I know what compliance auditors look for because I spent three years being one.
We check:
- OWASP Top 10 — SQL injection, XSS, broken authentication, insecure deserialization, and the other seven vulnerabilities that account for the vast majority of real-world exploits.
- Secrets management — are credentials hardcoded? Committed to git? Stored in environment variables without rotation? Accessible to developers who don't need them?
- Authentication and session management — token storage, session expiry, password hashing algorithms, MFA support.
- Security headers — CSP, HSTS, X-Frame-Options, Referrer-Policy. Missing headers are the lowest-effort, highest-impact security fix in most applications.
- Error handling in production — stack traces, verbose error messages, and debugging endpoints exposed to the public internet.
5. Infrastructure and deployment
How the code gets from a developer's machine to production is as important as the code itself.
We review:
- CI/CD pipeline — does it exist? Does it run tests? Does it enforce linting? Can a single developer deploy to production unilaterally?
- Environment parity — do staging and production use the same database version, the same runtime, the same configuration? Divergence here causes bugs that only appear in production.
- Backup and recovery — when was the last time someone tested a database restore? Not "do backups exist" but "can you actually recover from them?"
- Monitoring and alerting — if the application throws an error at 3 AM on Saturday, does anyone know? How long before it's noticed?
What the output looks like
The deliverable is not a 40-page PDF that nobody reads. It's a structured remediation roadmap:
| Priority | Finding | Risk | Effort | Recommendation |
|---|---|---|---|---|
| 🔴 Critical | SQL injection in /api/users | Data breach | 2 days | Replace with parameterized queries |
| 🔴 Critical | 4 CVEs in lodash@4.17.15 | Remote code execution | 1 hour | Update to lodash@4.17.21 |
| 🟡 High | No rate limiting on login | Brute-force attack | 3 days | Implement rate limiting middleware |
| 🟡 High | Sessions stored in localStorage | XSS → session hijack | 2 days | Move to HttpOnly cookies |
| 🔵 Medium | Dead code: 3,200 lines | Maintenance burden | 1 day | Delete identified files |
| 🔵 Medium | No CI pipeline | Manual deployments | 3 days | Set up GitHub Actions |
Every finding has evidence, risk assessment, and a concrete fix with effort estimate. The executive summary is one page — designed for the CTO or VP Engineering to read in five minutes and make a decision.
When you need one
- Before a compliance audit. SOC 2, ISO 27001, PCI DSS — all require documented evidence of security controls. An audit before the official audit gives you time to fix what they'll find.
- After acquiring a company. M&A due diligence for technology companies should include a codebase assessment. The system's technical debt is a line item on the balance sheet whether you measure it or not.
- When a key developer leaves. If the person who "understands the system" is gone, you need someone to document what's actually running before it becomes a black box.
- Before scaling. If you're about to double your user base, hit peak season, or expand to new markets, you need to know what will break under load.
If your system hasn't had a formal audit in the past 12 months — or ever — a system audit is where we start. 30-minute call, no pitch deck, just an honest assessment of what you're running and what fixing it would involve.