Home / Sample report
Redacted sample · real engagement

The audit report, exactly as a client receives it.

A redacted sample from a real engagement: an AI-built startup-intelligence SaaS audited ahead of its public launch. Client identifiers are masked and sensitive figures rounded — the findings, file paths and fixes are what the client received.

AI-built startup-intelligence SaaS · Python/FastAPI + vanilla JS · May 2026 · Prepared by Andrei Artiushenko
13
findings
2
critical
18
report sections

1. Executive summary

The platform under review is a working prototype with a real foundation: multi-source scraping, an LLM analysis pipeline, scoring, public pages and an admin panel. It is not yet a production system. Two critical issues — live credentials committed to the repository and a fallback signing key that lets production boot with a predictable secret — were on track to ship to a public launch.

The deeper pattern is typical of AI-generated codebases: the happy path works, the failure path was never written. Failed LLM analyses are marked as processed and silently dropped, schema migrations run as raw DDL inside except: pass, and the analyzer blocks its own event loop while it waits on a third-party API.

None of this is fatal. The highest-risk items add up to 10–15 hours of focused work, and the report sequences them so security lands first, reliability second, throughput third — before any attempt to scale the dataset.

2. What was reviewed

  • Codebase: backend API, models, workers, scrapers, frontend pages, configuration
  • Data pipeline end to end: source → lead → LLM analysis → record → API → frontend
  • Eight data sources — including two promised in the spec but absent from the code
  • LLM usage: 30 days of API calls, tokens, spend and unit economics
  • Product flow: feed, detail cards, compare, market position, admin workflow
  • Security and configuration: secrets, auth, CORS, proxy and deploy setup

3. Findings at a glance

Every finding carries a severity, an exact location and a concrete fix. The thirteen from this engagement:

sample-audit-report.md13 findings
CRITICAL
Live proxy credentials committed to the repository
data/parser_config.json
CRITICAL
Production can boot with a fallback signing key
backend/api/auth.py
HIGH
CORS open to every origin on the admin API
backend/api/main.py · allow_origins=["*"]
HIGH
Migrations run as raw DDL inside except-pass
core/background.py · run_migrations()
HIGH
Failed analyses marked as processed — leads silently lost
core/analyzer.py · finally: mark_leads_checked_by_url()
HIGH
Blocking LLM call inside the async event loop
core/openai_client.py · analyze_and_save()
MEDIUM
User-facing analysis only reachable through an admin endpoint
backend/api · /admin/analyze-market
MEDIUM
Full URL set loaded into memory for deduplication
backend/crud/leads.py · get_leads_links()
MEDIUM
Unbounded read of the unprocessed lead queue
backend/crud/leads.py · get_unchecked_leads()
MEDIUM
Pipeline state kept in a JSON file — lost on redeploy
data/scraper_state.json
MEDIUM
No hard spend cap on the LLM pipeline
ops · balance alert only, no budget limit
LOW
Sequential analyzer caps throughput at one lead per ~3s
core/analyzer.py · DELAY_BETWEEN_CALLS = 3
LOW
Scored claims shipped without evidence or confidence fields
models / API · no evidence[], no confidence_score

4. Three findings, in depth

The format is identical for every finding in the report: what it is, where it lives, why it matters for the business, and exactly how to fix it.

CRITICALbackend/api/auth.py · OWASP A05 Security Misconfiguration
Production can boot with a fallback signing key

Session tokens are signed with SECRET_KEY. Because the config falls back to a static default when the variable is missing, any environment where it was never set signs admin sessions with a value that lives in the repository. Anyone who has read the code can mint a valid admin token.

# flagged SECRET_KEY = os.getenv("SECRET_KEY", "<static fallback>") # fix — refuse to boot without a real key SECRET_KEY = os.environ["SECRET_KEY"]
Fail fast at boot, rotate the key, invalidate existing sessions. Delivered with a checklist of every required production variable.
CRITICALdata/parser_config.json · OWASP A05 / secrets management
Live proxy credentials committed to the repository

Working credentials for the paid scraping proxy sit in a tracked JSON config. Everyone with repository access — contractors, CI, a leaked laptop — owns that account, and git history keeps the secret long after the file is “cleaned”.

# flagged — committed to git "proxy": { "user": "████", "password": "██████" } # fix PROXY_USER / PROXY_PASS from the environment # + rotate, purge history
Move to environment variables, rotate the credentials, purge git history, add secret scanning to CI so the bug class stays fixed.
HIGHcore/analyzer.py · reliability / data loss
Failed analyses are marked as processed

The lead loop marks every URL as checked in a finally block — including when the LLM call failed on a rate limit or network error. A transient outage permanently throws away leads, and nothing in the admin shows it happened. A classic AI-generated pattern: the happy path works, the failure path was never written.

# flagged finally: mark_leads_checked_by_url(url) # runs even when analysis failed # fix — explicit lifecycle, failures stay visible status: pending -> processing -> done | failed(retry_count)
Replace the boolean with pending / processing / done / failed plus a retry budget, so transient errors retry and permanent failures surface in the admin.

5. The remediation plan

Findings are cut into a backlog a single developer can execute — priorities, business effect, hour estimates. P0 alone removes both criticals in under a working day.

PriorityTaskWhy it mattersEstimate
P0Remove committed credentials, rotate proxy + signing keysCloses the account-takeover path1–2h
P0Enforce required production secrets, lock CORS to known originsAdmin surface no longer one mistake from open1–2h
P0Move the LLM call off the event loopAPI stops freezing during every analysis1h
P0Honest lead statuses with retry handlingTransient errors stop deleting work2–3h
P1Parallel analyzer with bounded concurrencyThroughput scales without babysitting4–8h
P1Database-level dedup instead of in-memory URL setsStays fast past 100k leads2–3h
P1Cheap pre-filter before the expensive LLM callStops paying full price for junk leads6–10h
P2Move pipeline state from JSON into the databaseDeploys stop erasing progress2–4h
P2Replace raw-DDL migrations with AlembicSchema changes become predictable3–5h
P2Pipeline metrics dashboardBottlenecks visible before they bite4–6h

6. Beyond the vulnerabilities

A report that only lists vulnerabilities misses why prototypes stall. The full deliverable also models the unit economics of the LLM pipeline and the order in which to build toward revenue:

“≈12.8k LLM calls and ≈88M tokens in 30 days cost about $15. Spend was never the bottleneck — reliability was. At current unit costs, enriching 100,000 companies is a $120–300 problem, provided a cheap pre-filter stops paying full price for junk.”
From section 8 of this report — LLM spend and unit economics
Structure

Inside the full deliverable.

Eighteen sections. The findings above are roughly a third of it — the rest sequences the path from prototype to sellable product.

01

Severity-ranked findings

Every finding with location, business impact and a concrete fix. No “consider improving” filler.

02

Prioritized backlog

P0/P1/P2 with hour estimates, cut into sprints a single developer can execute and a reviewer can verify.

03

Cost & unit economics

LLM spend per processed record, projections at 10k / 50k / 100k scale, and hard budget guardrails.

04

Four-phase roadmap

Stabilize the pipeline, ship self-serve, scale the dataset — then layer the AI product on top.

05

Data & legal risk

Source-by-source terms-of-service review with explicit go / API-only / avoid calls before launch.

06

Target architecture

A three-agent pipeline with queue, retries, caching and pre-compute — specified to the file level, with estimates.

Client name, URLs and commercially sensitive figures are redacted or rounded. Findings, file paths and fixes are unchanged from the delivered report. This engagement covered a Python/FastAPI codebase — AI-generated code fails the same way in every stack, and Laravel reports follow the identical format and severity model.

Want this level of clarity on your codebase?

Fixed price, five-day turnaround, every finding shipped with a fix.