Skip to main content

Bookkeeping for Code-Audit Firms: How to Book Static Audits, Hourly Remediation, and Resold SAST Subscriptions

9 min readMike ThriftMike Thrift
Bookkeeping for Code-Audit Firms: How to Book Static Audits, Hourly Remediation, and Resold SAST Subscriptions

Ask a boutique code-audit firm's founder what their revenue model is, and you'll usually get a confused pause before "well... both?" A static-analysis audit shop rarely picks a lane. One client pays $6,500 for a two-week static review of a legacy Rails app. Another pays $40 per developer per month for an ongoing SAST subscription the firm resells and configures. A third pays a custom rate for a "full audit package" that bundles static analysis, dynamic testing, and remediation work billed by the hour. Three deals, three different revenue-recognition rules, and one chart of accounts that's usually not built to tell them apart.

This is a genuinely common shape for technical services businesses right now: security and code-quality consultancies that started as pure engagement shops are increasingly reselling or white-labeling SAST (Static Application Security Testing) tooling alongside their audit work, because clients want both a one-time opinion and an ongoing scanner in CI. The bookkeeping problem that creates is specific enough that most general-purpose "consulting firm" advice glosses over it.

The Three Revenue Streams Hiding in One Business

Before you can book anything correctly, you need to separate what you're actually selling, because each one behaves differently on the books.

1. Static audits (fixed-scope, point-in-time). A source-code review — standards adherence, dependency and CI/CD pipeline checks, architecture review — typically prices in the $5,000–$8,000 range for a defined scope. This is a discrete deliverable: a report, delivered on a date, with a defined end.

2. Dynamic audits and full audit packages (fixed-scope or hourly, often milestone-based). Testing system behavior under load or adversarial conditions runs $8,000–$16,000, and a combined static-plus-dynamic-plus-remediation "full audit package" is usually custom-quoted and billed against milestones or hours. Auditor seniority, codebase size and documentation quality, regulatory scope (healthcare and finance audits require deeper data-tracing and permission verification), and timeline pressure all move the price — which means two audits with the same label can have wildly different cost structures underneath.

3. SAST subscriptions (recurring, resold or reseller-margin). The tooling side of this market has consolidated around per-seat SaaS pricing: broad platforms bundling SAST, SCA, secrets scanning, and IaC checks start around $15–20 per user per month, point tools for a single capability sit in the $10–15/user range, and enterprise contracts from the large vendors can exceed $100,000 a year for a few hundred applications. When an audit firm resells or bundles one of these platforms — configuring it, tuning false-positive rules, and taking a margin on the subscription — that revenue is recurring, not project-based, and it may or may not be your revenue depending on whether you're acting as principal or agent in the contract.

Lumping all three into "consulting revenue" is exactly how a P&L stops telling you anything useful about the business.

Why the Revenue Recognition Actually Differs

Under ASC 606 (or its close international equivalents), the accounting question is when does control of the promised good or service transfer to the customer — and the answer is different for each stream above.

  • A fixed-scope static or dynamic audit is usually recognized point-in-time, when the report is delivered and accepted — or, if billed against milestones, recognized as each milestone is completed. If you're invoicing 50% up front and 50% on delivery, the deposit is a liability (unearned revenue) until the report ships, not revenue the day the check clears.
  • Hourly remediation and implementation work is recognized as the hours are performed, which means you need a mechanism for unbilled time — work performed in a period but not yet invoiced — to show up as an asset (unbilled receivable / WIP) rather than disappearing until the invoice date. This is the single most common distortion in project-based bookkeeping: a firm looks unprofitable in the invoicing month and wildly profitable the next, purely because of billing lag, not because the underlying work changed.
  • A resold SAST subscription is recognized ratably over the subscription term — monthly or annually, matching the period the customer actually has access to the tool. If you're the reseller and you're acting as an agent (arranging for the vendor to provide the software) rather than principal (promising to provide the software yourself), you should only be recognizing your margin, not the gross subscription price — booking the full pass-through amount as revenue when you're economically just a billing conduit overstates your top line and misstates your real margin percentage.

Getting the principal-vs-agent call right matters beyond GAAP correctness: it's the difference between a P&L that shows $180,000 in subscription revenue at 8% margin and one that correctly shows $14,400 in commission revenue at 100% margin. Lenders, insurers, and anyone building a valuation multiple on top of your numbers will read those two P&Ls very differently — and only one of them is close to true.

The Practical Chart of Accounts

A code-audit firm running all three revenue streams benefits from splitting revenue (and often COGS) at the account level, not just tagging things in a spreadsheet after the fact:

  • Income:Audits:Static
  • Income:Audits:Dynamic
  • Income:Consulting:Remediation (hourly)
  • Income:Subscriptions:SAST-Margin (your commission/margin only, if you're an agent)
  • Income:Subscriptions:SAST-Gross (if you're principal and resell the full contract)
  • Liabilities:UnearnedRevenue:Audits
  • Assets:UnbilledReceivables:Consulting

This is where plain-text, version-controlled accounting earns its keep for a technical services firm — the same engineers who configure SAST rulesets for clients are usually comfortable reviewing a .beancount ledger diff, and a Git history on your books gives you the same auditability you're selling to your own clients. It's a little on-the-nose for a code-audit shop to keep its own financial records in an opaque, un-diffable format.

Where Firms Actually Get This Wrong

A few patterns show up repeatedly in this business model:

  1. Booking subscription deposits as revenue immediately. If a client prepays for an annual SAST license you're reselling, that cash is a liability until the coverage period elapses — recognizing it all in month one overstates the quarter it lands in and understates every quarter after.
  2. Never tracking unbilled hours. Hourly remediation work performed near a month-end but invoiced the following month should still show up as an asset in the correct period, or your margins will look like they're swinging wildly for no operational reason.
  3. Treating reseller pass-through as gross revenue. As above — this inflates top-line numbers in a way that looks good until a buyer's diligence team (ironically, doing the same kind of technical due diligence your firm sells) unwinds it and re-rates the business.
  4. No separate tracking for regulated-industry engagements. Healthcare and financial-services audits carry materially more scope (data-tracing, access-control verification) and usually more liability exposure — if your books don't separate that revenue and its associated cost, you can't tell whether your compliance-heavy engagements are actually profitable relative to your general static reviews.

A Worked Example: One Invoice, Three Different Postings

Say your firm signs a client in March for a $7,000 static audit (50% deposit, 50% on delivery), 20 hours of hourly remediation at $175/hour to be billed in April, and a resold SAST subscription at $18/seat/month for their 40-developer team, where your firm keeps a $4/seat margin and passes the rest to the vendor.

  • March deposit ($3,500): Debit Cash, credit Liabilities:UnearnedRevenue:Audits. No revenue yet — you haven't delivered the report.
  • April report delivery: Debit Liabilities:UnearnedRevenue:Audits and the remaining $3,500 receivable, credit Income:Audits:Static for the full $7,000. Revenue lands in the month the work was actually accepted, not the month either check cleared.
  • March remediation hours (worked but not yet invoiced): If 8 of the 20 hours were performed in March but the invoice goes out in April, debit Assets:UnbilledReceivables:Consulting and credit Income:Consulting:Remediation for those 8 hours ($1,400) in March; the remaining 12 hours ($2,100) post normally in April when both the work and the invoice land in the same month.
  • Monthly SAST subscription: If you're acting as agent, only the $160 monthly margin (40 seats × $4) posts to Income:Subscriptions:SAST-Margin; the $720 pass-through (40 × $18) moves through a clearing account against what you owe the vendor, never touching your income statement. If your contract instead makes you principal — you're the party promising the software to the client, even if a vendor delivers it under the hood — the full $720 recognizes as revenue with the $560 vendor cost booked as COGS, netting to the same bottom line but very different (and, if you're not principal, materially misleading) top-line numbers.

Three transactions, three different timing rules, and — critically — the second one is the reason a lot of small audit shops look like they had a rough April when nothing about the business actually changed. The unbilled-hours entry is what keeps March's numbers honest.

Why This Matters More Than It Used To

Demand for the underlying service is growing for a reason worth noting: buyers doing technical due diligence increasingly treat code and security posture as material to deal terms, not a formality — technical findings routinely move valuation discussions by 15–30%, and a meaningful share of expected deal synergies now hinge on integration quality that a code audit is what actually surfaces before close. If your own firm gets acquired, recapitalized, or brought into a larger due-diligence pipeline someday, the first thing a buyer's finance team will do is exactly what your audit team does to client codebases: pull the ledger apart and check whether the numbers hold up under scrutiny. A business with a chart of accounts that already separates fixed-fee, hourly, and subscription-margin revenue answers that question in minutes instead of weeks.

Keep Your Own Books as Clean as the Code You Audit

Running a hybrid audit-and-subscription business means your revenue recognition has three different rules living under one roof, and spreadsheets rarely enforce that distinction consistently over time. Beancount.io offers plain-text accounting that's transparent, version-controlled, and easy to diff — a natural fit for a technical team that already thinks in terms of auditable history. Get started for free and keep your own financial records as rigorous as the audits you sell.

Share this article