WEBISOFT®
Confidential
Engineering Assessment
Report v1.0
Vibe Check® · Sample Report

AI-Built Software Security Audit

A senior human engineer’s independent review of an AI-built web application. Every finding read, verified, and signed by hand.

Client
████████ Inc., Series-A B2B SaaS
Application
Production web app, ~4,200 lines, built with an AI app builder
Engagement window
24-hour turnaround
Access
Read-only source repository
Prepared by
Webisoft · Vibe Check®
Reviewing engineer
William Marchand, Senior Engineer

Real report format. Client details and findings redacted for confidentiality.

VIBE CHECK® REPORTDocument Summary

Document revision history

VersionDescriptionReviewer
0.1Automated pass & manual triageVibe Check engine + W. Marchand
0.2Manual code review & finding write-upW. Marchand
0.9Business-impact rewrite & fix costingW. Marchand
1.0Final review, sign-off & deliveryW. Marchand, Senior Engineer

Contacts

ContactRoleEmail
William MarchandSenior Engineer · Reviewerinfo@webisoft.com
Vibe Check DeskDelivery & schedulinginfo@webisoft.com
██████Client · Founder / CTO████@█████.com

This document is confidential and prepared solely for the named client. Client identity, repository names, URLs, keys, and customer data have been redacted with ████ for this public sample. The report format, methodology, and finding structure are identical to a live Vibe Check delivery.

VIBE CHECK® REPORTContents
01 · Executive OverviewVibe Check®

Section 1

Executive overview


1.1   Introduction

████████ Inc. (“the Client”), a Series-A B2B SaaS company, engaged Webisoft to perform a Vibe Check: an independent, human-led security and quality audit of a production web application their team assembled largely with an AI app builder. The application is roughly 4,200 lines of code and handles account sign-up, a customer dashboard, and card payments.

The review was delivered on the standard Vibe Check basis: a fixed fee of $250, read-only access to the source repository, and a signed report inside 24 hours. No live customer data, admin credentials, or passwords were requested or accessed at any point.

1.2   Audit summary

One senior engineer reviewed the full codebase by hand, supported by Webisoft’s automated first pass. The purpose of the audit was to answer, in plain English, three questions the Client’s customers and investors are starting to ask: is anything exposed, can one customer reach another’s data, and will the app hold up as it grows.

In summary, the engineer identified 3 Critical issues that warrant action before the next enterprise conversation, 5 Warnings worth scheduling into the coming sprints, and 12 checks that passed. The three Critical findings are common to AI-built applications: a live payment key shipped inside the app, an interface that returns any customer’s records when an ID is changed, and a password-reset flow that can be guessed. None require a rewrite; each has a concrete, costed fix in Section 6.

3
Critical
5
Warning
12
Pass
01 · Executive OverviewMethodology

1.3   Test approach & methodology

A Vibe Check pairs an automated first pass with a full manual review, so that coverage is broad and every reported finding is verified by a human before it reaches the Client. The following phases were used:

Risk methodology (Likelihood × Impact)

Each finding is rated by measuring the Likelihood that it will be exploited or hit in practice, and the Impact should that happen. Each axis runs 1 to 5. The two values combine into a severity band that maps to the Vibe Check scale used throughout this report.

BandCombined scoreWhat it means for you
Critical8–10Fix before your next enterprise deal, security review, or launch. Real risk of exposure, data loss, or account takeover today.
Warning4–7Schedule into the coming sprints. Not on fire, but it will be exploited or will bite you as you grow.
Pass1–3Reviewed and healthy, or low enough to note and move on.

Likelihood × Impact matrix

Placement of this engagement’s eight findings. Rows are Impact (5 at top), columns are Likelihood (5 at right).

Impact ↓ / Likelihood →12345
5VC-02VC-01VC-03
4VC-04VC-05
3VC-07VC-06
2VC-08
1
01 · Executive OverviewScope

1.4   Assessment scope

The assessment was scoped to the source code of the Client’s production web application, provided through a read-only repository invitation.

Access was limited to the single reviewing engineer and revoked on delivery of this report.

02 · Assessment SummaryFindings Overview

Section 2

Assessment summary & findings overview


61/100
Overall risk score
Security38
Data privacy52
Payments71
Scalability64

Higher is healthier. The overall score is held down by the three Critical findings; each is individually fixable without a rewrite.

Findings overview

IDFindingSeverityStatus
VC-01Live payment key shipped in the app bundleCriticalOpen · fix ready
VC-02One customer can read another customer’s data (IDOR)CriticalOpen · fix ready
VC-03Password reset can be guessed (account takeover)CriticalOpen · fix ready
VC-04Database queries built from raw user inputWarningOpen
VC-05No limit on login attemptsWarningOpen
VC-06API accepts requests from any website (CORS)WarningOpen
VC-07Abandoned dependency with a known CVEWarningOpen
VC-08Error pages leak internal detailsWarningOpen

Status reflects a first-delivery report. On a live engagement, this column is updated as the Client remediates: Solved, Partially solved, Risk accepted, or Acknowledged.

03 · FindingsTechnical Details

Section 3

Findings & technical details


Every finding leads with what it means for your business, then the technical detail, redacted evidence, the fix, and the rough effort involved. Your $250 audit fee is credited against any of it.

VC-01 · Secrets management

A live payment key is shipped inside your app.

Critical
What this means for you
Your live payment secret is sitting in code that anyone who visits your site can download and read. With it, someone can issue refunds, read your payment history, and move money as if they were you. This is the single most urgent item in the report, and rotating the key takes minutes.
Technical detail

The live Stripe secret key is hard-coded into the front-end bundle and shipped to every browser. AI app builders frequently place server-only secrets in client-visible code because the prompt did not distinguish between a publishable key and a secret key. The key is also present in committed source, so it exists in the repository history even if removed from the current file.

Evidence (redacted)
/src/config.js · line 218 · bundled and served to the browser
// loaded client-side, visible in every browser
const STRIPE_SECRET = "sk-live-████████████████████";
const stripe = require("stripe")(STRIPE_SECRET);
Risk rating
Likelihood
4 / 5
Impact
5 / 5
Severity
Critical
Recommendation

Rotate the exposed key in the Stripe dashboard immediately so the leaked value is dead. Move the secret to a server-side environment variable that is never sent to the browser, and switch the front end to the publishable key only. Purge the key from the committed history. We can pair on this the same day the audit lands.

Effort
2–4 hours
Remediation status: Open · fix ready · recommended before any further deploys
VC-02 · Broken access control (IDOR)

One customer can read another customer’s data.

Critical
What this means for you
Any logged-in customer can see other customers’ records simply by changing a number in the address bar. For a B2B SaaS, that is a cross-customer data breach: the kind of incident that ends enterprise deals and triggers disclosure obligations. It is invisible in normal use, which is why it survives to production so often.
Technical detail

An API endpoint returns a record based on the ID in the URL without checking that the record belongs to the account making the request. Changing the ID returns someone else’s data. This is an Insecure Direct Object Reference (IDOR). AI builders reliably generate the “fetch by id” path and just as reliably omit the ownership check, because it was never asked for.

Evidence (redacted)
/api/routes/invoices.js · line 74
app.get("/api/invoices/:id", auth, async (req, res) => {
  // returns the record for ANY id, no owner check
  const invoice = await db.invoices.findById(req.params.id);
  res.json(invoice); // GET /api/invoices/██ returns another tenant
});
Risk rating
Likelihood
3 / 5
Impact
5 / 5
Severity
Critical
Recommendation

Scope every record lookup to the authenticated account, for example by filtering on both the record ID and the owner’s account ID, and return 404 when they do not match. Apply the same ownership check across all endpoints that take an ID, not just this one. Add a test that a second account cannot read the first account’s records.

Effort
1–2 days
Remediation status: Open · fix ready · audit all ID-based endpoints together
VC-03 · Authentication

Your password reset can be guessed.

Critical
What this means for you
The link that lets a user reset their password can be guessed, and it never expires. That means an attacker can take over accounts, including admin accounts, without ever knowing the password. Combined with VC-02, one compromised account can read across the whole customer base.
Technical detail

The password-reset token is a short, sequential value derived from a timestamp rather than a cryptographically random secret, and it carries no expiry. An attacker can enumerate recently issued tokens and complete a reset for an account they do not own. This is a direct account-takeover path.

Evidence (redacted)
/api/auth/reset.js · line 41
// predictable token, no expiry stored
const token = Date.now().toString(36); // guessable
await db.resets.insert({ user: ████, token });
// reset accepted whenever token matches, forever
Risk rating
Likelihood
5 / 5
Impact
5 / 5
Severity
Critical
Recommendation

Generate reset tokens from a cryptographically secure random source, store only a hash of the token, expire it after a short window (15 to 60 minutes), and invalidate it on first use. Rate-limit reset requests. These are standard building blocks; the fix is well understood and low risk.

Effort
~1 day
Remediation status: Open · fix ready
VC-04 · Injection (High)

Database queries are built from raw user input.

Warning
What this means for you
Search and filter inputs are dropped straight into database queries. A crafted input can read or alter data it should not, or make the query return everything. It has not been weaponized here, but it is the classic path to a data breach and should be closed before you scale.
Technical detail

User-supplied values reach the query layer without parameterization or validation, creating a NoSQL/SQL injection surface on the search and filter endpoints. The query is assembled by string concatenation from request fields.

Evidence (redacted)
/api/routes/search.js · line 52
// req.query.q flows straight into the query object
const results = await db.users.find(
  { $where: `this.name == '${req.query.q}'` } // injectable
);
Risk rating
Likelihood
3 / 5
Impact
4 / 5
Severity
Warning (High)
Recommendation

Use parameterized queries or the database driver’s typed query builders, never string interpolation. Validate and whitelist input fields, and drop the $where operator entirely. Add input-validation middleware at the API boundary.

Effort
1–2 days
Remediation status: Open
VC-05 · Authentication (High)

There is no limit on login attempts.

Warning
What this means for you
Anyone can try passwords against your login as fast as they like. That opens the door to automated password-guessing and credential-stuffing attacks using leaked passwords from other breaches. It also lets an attacker hammer your server, driving up cost and slowing the app for real users.
Technical detail

The login endpoint has no rate limiting, no throttling, and no account lockout or backoff. There is nothing to slow or stop high-volume automated attempts.

Evidence (redacted)
/api/auth/login.js · line 19
app.post("/api/login", async (req, res) => {
  // no rate limit, no lockout, unlimited attempts
  const ok = await checkPassword(req.body.email, req.body.password);
  res.json({ ok });
});
Risk rating
Likelihood
4 / 5
Impact
4 / 5
Severity
Warning (High)
Recommendation

Add rate limiting per IP and per account on login and reset endpoints, with exponential backoff and a temporary lockout after repeated failures. Log repeated failures for monitoring. A small middleware handles most of this.

Effort
4–6 hours
Remediation status: Open
VC-06 · Configuration (Medium)

Your API accepts requests from any website.

Warning
What this means for you
Your API is configured to trust every website on the internet. That makes it easier for a malicious page to act against your API using a logged-in user’s session, and it removes a layer of protection you should have by default.
Technical detail

Cross-Origin Resource Sharing (CORS) is set to a wildcard *, allowing any origin to call the API. This is a common AI-builder default meant to “make it work” during development that then ships to production.

Evidence (redacted)
/api/server.js · line 12
app.use(cors({ origin: "*" })); // any website may call the API
Risk rating
Likelihood
4 / 5
Impact
3 / 5
Severity
Warning (Medium)
Recommendation

Restrict CORS to your known front-end domains only. Pair it with proper cookie and CSRF handling for authenticated requests. This is a small, low-risk configuration change.

Effort
1–2 hours
Remediation status: Open
VC-07 · Dependencies (Medium)

An abandoned dependency carries a known CVE.

Warning
What this means for you
Your app depends on an outside package that is no longer maintained and has a publicly known security flaw. Because the flaw is public, it is easy to find and exploit, and no fix is coming from the original author. AI tools sometimes even invent package names that attackers then register, so every dependency needs a human sanity check.
Technical detail

The dependency manifest pins an outdated, unmaintained package with a published CVE. It has had no release in over three years and open, unpatched advisories. The version is also pinned loosely, so the build can pull an unexpected release.

Evidence (redacted)
/package.json · dependencies
"dependencies": {
  "████████████": "^0.2.1", // unmaintained, CVE-20██-████
  "express": "^4.18.2"
}
Risk rating
Likelihood
4 / 5
Impact
3 / 5
Severity
Warning (Medium)
Recommendation

Replace the package with a maintained equivalent or remove it if unused, pin exact versions, and add automated dependency and CVE scanning to your build so this is caught continuously. Verify that every dependency name is a real, maintained project.

Effort
3–5 hours
Remediation status: Open
VC-08 · Information disclosure (Medium)

Error pages leak internal details.

Warning
What this means for you
When something goes wrong, your app shows visitors a full technical error, including file paths, database details, and library versions. That hands an attacker a map of how your system is built and makes every other weakness easier to find and exploit.
Technical detail

The API returns raw stack traces and internal error objects to the client in production. Verbose error output exposes file paths, dependency versions, and query fragments. This is a default development behaviour that was never switched off.

Evidence (redacted)
/api/server.js · error handler · line 140
app.use((err, req, res, next) => {
  // full stack trace returned to the client
  res.status(500).json({ error: err.stack }); // leaks internals
});
Risk rating
Likelihood
3 / 5
Impact
2 / 5
Severity
Warning (Medium)
Recommendation

Add a global error handler that returns a generic message and a reference ID to the client, while logging the full detail server-side only. Disable verbose errors and debug mode in production.

Effort
3–4 hours
Remediation status: Open
04 · Scalability ReadGrowth & Load

Section 4

Scalability read


What this means for you
The app runs fine for your current handful of users, but the way it talks to the database will not hold. On our read, it starts to slow badly and collapses around 1,000 concurrent users. That is a wall you will hit during a launch, a big customer onboarding, or a press moment, exactly when you can least afford it.
Technical detail

Two patterns drive this. First, list endpoints load related records one row at a time inside a loop (the “N+1 query” problem), so a single dashboard view can fire hundreds of database calls. Second, list endpoints have no pagination, so every request loads the full table into memory and returns it. Both scale linearly with data and users, and together they saturate the database connection pool under concurrent load.

Evidence (redacted)
/api/routes/dashboard.js · line 96
const accounts = await db.accounts.findAll(); // no pagination: whole table
for (const a of accounts) {
  a.owner = await db.users.findById(a.ownerId); // N+1: one query per row
}
res.json(accounts);
Recommendation

Load related records in a single query (join or batched lookup) to remove the N+1 pattern, add pagination with sensible page sizes to every list endpoint, and add database indexes on the fields used for lookups and sorting. Re-test under simulated concurrent load to confirm headroom well past 1,000 users.

Effort
2–3 days
Collapses around
1,000 concurrent users
Scalability score
64 / 100
05 · What PassedHealthy Checks

Section 5

What passed


Twelve checks came back healthy. A Vibe Check reports the good with the bad, so you know what not to spend money on.

P01Passwords are hashed with a modern algorithm
P02Login sessions use signed, HTTP-only cookies
P03Traffic is served over HTTPS with valid certificates
P04Payment card data is never stored on your servers
P05Sign-up input is length- and type-checked
P06No hard-coded admin backdoor accounts
P07Front end escapes user content (no obvious XSS)
P08Database is not exposed to the public internet
P09Secrets, aside from VC-01, use environment variables
P10File uploads restrict type and size
P11Dependencies, aside from VC-07, are current
P12Logout fully clears the session
06 · Fix PlanPrioritized & Scoped

Section 6

Prioritized fix plan


In priority order. Each item shows rough effort. The fixes are written so your own AI or developer can execute the smaller ones; the deeper ones are worth an engineer.

C1

Rotate and hide the live payment key (VC-01)

Rotate the key today, move it server-side, purge it from history. Do this first.

2–4 hrs · DevOps
C2

Close the cross-customer data hole (VC-02)

Scope every record lookup to the logged-in account across all endpoints.

1–2 days · Engineer
C3

Fix the password-reset flow (VC-03)

Random, hashed, single-use, expiring tokens plus reset rate limiting.

~1 day · Engineer
W1

Parameterize database queries (VC-04)

Remove string-built queries and add input validation at the API boundary.

1–2 days · Engineer
W2

Rate-limit login and reset (VC-05)

Per-IP and per-account limits with backoff and temporary lockout.

4–6 hrs · Engineer
W3

Lock down CORS (VC-06)

Restrict to your own domains. Small config change, give it to your AI.

1–2 hrs · AI-safe
W4

Replace the abandoned dependency (VC-07)

Swap for a maintained package, pin versions, add CVE scanning to the build.

3–5 hrs · Engineer
W5

Silence verbose errors (VC-08)

Generic client errors with a reference ID, full detail logged server-side.

3–4 hrs · AI-safe
S1

Fix N+1 queries and add pagination (Scalability)

Batch related lookups, paginate list endpoints, add indexes, retest under load.

2–3 days · Engineer
Your $250 audit fee is credited toward any of these fixes. Hire Webisoft for all of the work or a single item and the audit is effectively free. There is no obligation to use us: the fix list is yours to hand to your own AI, your developer, or another firm, with the estimates above as a reference.
07 · ClosingSign-off

Section 7

Closing & sign-off


The application is in solid shape for its stage, and nothing here calls for a rewrite. The three Critical findings are the ones to act on before your next enterprise conversation or security review; each has a concrete, same-week fix. The Warnings are worth scheduling into the coming sprints, and the scalability work is best done before your next growth push rather than during it.

This kind of report is exactly what enterprise customers, insurers, and investors are starting to ask AI-built companies for. A Vibe Check is not a formal certification, but it tells you honestly where you stand and what closing the gap would take.

Every finding in this report was read and verified by hand by the engineer below. Findings, evidence, and client identity have been redacted for this public sample.

William Marchand signature
William Marchand
Senior Engineer · Webisoft
Reviewed & signed · Vibe Check® · Report v1.0
Webisoft® · Vibe Check® Confidential · Sample report ← vibecheck.webisoft.com
Get your own Vibe Check · $250

Report in 24 hours · Signed by a human engineer · Credited toward any fixes