What we look at, in order
1. Can it be changed safely?
The most important question, and the one that predicts everything else. How long does a small change take from request to production? Is there a test suite, and is it trusted? Can a deploy be rolled back? A tidy codebase nobody can safely modify is worse than a messy one with good tests.
2. What is the operational risk?
Backups — and whether a restore has ever been tested. Single points of failure. Unsupported dependencies with known vulnerabilities. Secrets in the repository. Whether anyone is alerted when it breaks. These findings are often the most urgent and the cheapest to fix.
3. Where is the knowledge?
How many people understand each critical area? Systems where one person is the only one who understands billing carry a serious risk that no code metric captures.
4. Does the architecture fit the requirements?
Not whether it is fashionable — whether it supports what the business needs next. An unfashionable architecture that comfortably handles the roadmap is fine.
5. Code quality, last
It matters, but as a contributor to the first question rather than as an end in itself.
The findings that recur
Across audits, the same issues appear with striking consistency:
- Backups that have never been restored. Extremely common, and the highest-severity finding we routinely report. An untested backup is a belief, not a recovery plan.
- Credentials in version control history. Often removed from the current files but still present in history, and still valid.
- One person who understands the critical subsystem. Usually known informally and never treated as a risk to mitigate.
- No staging environment resembling production. Testing happens against data that does not look like real data.
- Dependencies years behind, with a blocking upgrade. One major version jump that nobody has scheduled, getting more expensive each quarter.
- Manual deployment steps that are not written down. Documented only in the memory of whoever usually does it.
- Missing authorisation checks on internal endpoints that were assumed to be unreachable.
Notice that most of these are process and operational findings, not code findings. That is consistently where the real risk sits.
How a report should be structured
A report that lists two hundred issues by severity is a document that gets skimmed once. What makes an audit actionable:
- Findings grouped by theme, not by file. Fifteen instances of the same missing check are one finding with fifteen locations.
- Each finding states the consequence in plain terms. "If this fails, customer data from the last 24 hours is unrecoverable" — not "backup configuration is suboptimal".
- Effort estimates attached, so trade-offs are possible.
- An explicit "do this first" list of no more than five items. If everything is a priority, nothing gets done.
- A separate list of things that look alarming but are fine. Underrated, and it builds trust in the rest of the report.
Reading a report without over-reacting
Two failure modes when a report lands.
Panic: treating every finding as urgent, freezing the roadmap, and starting a remediation programme that consumes a quarter. Most findings are ordinary technical debt that every system carries. The report exists to help you sequence, not to condemn.
Dismissal: "the auditor doesn't understand our constraints", which is sometimes true and usually not a reason to ignore the operational findings.
A reasonable response: fix the operational risks immediately, since they are usually days of work with disproportionate benefit. Schedule the structural items into normal delivery over two or three quarters. Accept the rest explicitly, in writing, with a note on why — an accepted risk is a decision; an ignored one is a surprise waiting to happen.
Audits in a transaction context
Technical due diligence has a different emphasis. The buyer is not asking whether the code is good — they are asking what it will cost to own.
The questions that move valuation:
- Can the team continue to deliver if key people leave?
- Are there licensing problems? Copyleft dependencies in a proprietary product are a real issue.
- Is customer data handled in a way that survives scrutiny under the regulations that apply?
- What is the realistic cost of the next two years of maintenance, including upgrades already overdue?
- Are there hard scaling limits close to current usage?
If you are preparing for a transaction, running an audit six months early is materially cheaper than having the buyer find these first — the findings are the same, but you control the timeline and the narrative.
What an audit cannot tell you
Worth being clear about the limits. An audit assesses a snapshot from the outside. It will not tell you whether the team is good — a competent team can inherit a bad system, and the reverse happens too. It will not tell you whether the product is right. And it will not find every bug; it finds patterns and risks.
Used properly, it answers one question well: what would it take to make this system safe to change and cheap to run? That is usually the question behind whichever one prompted the audit.