How a Professional Code Audit Actually Works, Step by Step
Most explanations of code audits stay comfortably vague (“we assess your architecture,” “we evaluate best practices”), which tells you nothing about what actually happens between handing over repo access and receiving a report. That vagueness makes CTOs reasonably suspicious: is this a real engineering exercise or a scanner run with a logo on it?
Here’s the actual process, step by step, as practiced. No mystique.
Step 1: Scoping (deciding what “audit” means this time)
Before anyone reads code, the auditor and you agree on what question the audit is answering. “Look at everything” is not a scope; it’s a way to get shallow coverage of everything and depth on nothing. Real scopes sound like:
- “We inherited this from an agency. Tell us what we own and what’s dangerous.”
- “We’re raising a Series B. Find what a diligence team would find.”
- “Security is the concern: auth, data handling, dependencies. Skip the style commentary.”
- “Velocity has collapsed. Tell us why and what to fix first.”
Scoping also fixes the practical parameters: which repos and services are in scope, which are explicitly out, what the deliverable is, and the timeline. For a typical single-product codebase this conversation takes under an hour and saves days of misdirected effort.
Step 2: Access (read-only, minimal, boring)
The auditor needs to read, not touch. The standard, sane arrangement:
- Read-only access to the repository: a
Readrole on GitHub/GitLab/Bitbucket, or for the cautious, an exported bundle. History included; the git log is evidence. - Docs, if they exist: README, architecture notes, runbooks. Their absence is itself a finding, not a blocker.
- Optionally, CI config and infrastructure-as-code: pipeline definitions, Dockerfiles, Terraform. High signal, low sensitivity.
- Not needed: production access, customer data, live credentials. An auditor asking for production database access at this stage should raise your eyebrows.
An NDA typically precedes access, and revocation is one click when the audit ends. If your codebase is your crown jewels (it is), this step should feel appropriately uneventful. What you can do ahead of time to make this smooth is covered in how to prepare your codebase for an audit.
Step 3: Orientation (the first pass)
The first hours are spent building a map, not judging. The auditor:
- Tries to run the project from the README alone. This is a genuine test, performed deadpan. If the setup instructions are wrong or missing, every future engineer’s first week just got measured.
- Reads the structure before the code. Directory layout, module boundaries, where the entry points are, what talks to what. A codebase’s shape tells you what its authors believed the system was.
- Reads the history.
git logat a squint: commit cadence, author concentration (git shortlog -sn), hotspot files that change in every feature (git log --format= --name-only | sort | uniq -c | sort -rn), revert clusters that mark past incidents. - Inventories dependencies. Lockfiles, runtime versions, anything pinned, forked, or fossilized.
By the end of orientation the auditor has hypotheses (“authorization looks scattered,” “this module is the load-bearing mess”), which the deep dive will confirm or kill.
Step 4: Tooling pass (let machines do the machine work)
Automated analysis runs early, not because it finds the important things, but because it clears the ground so human attention lands where it’s needed:
- Dependency scanning against vulnerability databases (the
npm audit/pip-audit/ OWASP Dependency-Check category). - Static analysis for known-bad patterns: injection sinks, insecure crypto usage, secret-shaped strings (the Semgrep / CodeQL / gitleaks category).
- License inventory across the dependency tree.
- Mechanical metrics (file sizes, cyclomatic hotspots, duplication), used as pointers, not verdicts.
Tool output is triaged, not forwarded. A raw scanner dump contains hundreds of findings, most irrelevant to your actual risk; deciding which ten matter is the human contribution. The division of labor between the two is its own topic: see manual vs. automated code audits.
Step 5: Deep dive (reading the code that matters)
This is the audit’s center of gravity: an experienced engineer reading code, guided by the scope and the orientation-phase hypotheses. Attention is deliberately unequal:
- Critical paths get line-by-line reading. Authentication, authorization, payment flows, data export, anything touching PII or money. Here the auditor traces actual data flow: where does user input enter, where is it validated, what trust does each layer assume?
- Cross-cutting concerns get consistency checks. Is authorization enforced the same way in every entry point, or in nine of ten? Is error handling a policy or a mood? Multi-tenant isolation, idempotency on webhooks, timeout discipline on outbound calls.
- Tests get read, not counted. Coverage percentage is gameable; the question is whether a real bug on a critical path would fail a test. Sometimes the answer is a test file of mocks asserting the mocks.
- The boring majority gets sampled. CRUD is CRUD; it gets a representative pass, not a page-turn.
Findings are logged as they’re confirmed, each with file-and-line evidence. Anything ambiguous goes on a question list rather than into the report, which leads to the step most audits skip and shouldn’t.
Step 6: The questions call
A short session with your team: “Is this dead code or load-bearing?” “This cron job, intentional?” “We see three auth mechanisms; what’s the story?” This call kills false positives before they reach the report and frequently surfaces context that upgrades or downgrades findings. An audit report written with zero contact with the team is recognizable by its confident wrongness about intent.
Step 7: The report (findings, ranked, with receipts)
The deliverable is a written report, structured for two audiences at once: an executive summary a CEO can read in five minutes, and detailed findings an engineer can act on the same day. Each finding carries a severity, concrete evidence (file, line, commit where relevant), the business consequence in plain language, and a recommended fix with rough effort. Findings are ordered by what to fix first, not by the order they were found. And a good report also says what’s fine, because “no findings in payments” is information you paid attention for.
We break the deliverable’s anatomy down fully in what to expect in a code audit report.
Step 8: Walkthrough and handoff
A final call to walk the findings, answer challenges (good reports survive pushback; auditors should welcome it), and agree on what the severity ranking means for your next quarter. Then access gets revoked, and the report is yours: to fix against, to hand to a diligence team, or to file as a baseline for next year.
Total elapsed time depends on scope and codebase size: typically days to a few weeks end to end, with your team’s involvement measured in a couple of hours.
Get a free code audit
If you’d like to experience the process rather than read about it, Webisoft runs this exact exercise for free. A Webisoft engineer reviews your repository manually (the real process above, scoped to what a free engagement honestly supports) and sends you a written findings report with severity rankings and evidence. Genuinely free, read-only access, no obligation afterward.
Get a free code audit. Step 1 is a short scoping conversation, and it starts there.