How an application remediation audit earns a credible quote
An application remediation audit checks access, logic, data, dependencies, tests, and ownership before anyone commits to a repair price.

A credible repair quote comes from evidence, not a tour of the interface. An inherited project can look polished while its password reset leaks account existence, its admin check runs only in the browser, and its database accepts records the product can never use. A remediation service that prices from screenshots or a short call is pricing uncertainty. The buyer will eventually pay for that uncertainty through change orders, missed defects, or both.
The audit should answer two separate questions: what is broken, and what does the service actually control enough to repair? That distinction matters in projects created with Lovable, Bolt, v0, Cursor, or Replit because the visible code may be only one part of the system. Authentication settings, database policies, environment variables, deployment accounts, DNS, email delivery, storage rules, and third-party dashboards can sit elsewhere. A clean quote maps the whole operating system, records the evidence, and states which unknowns remain.
The buyer should be able to trace every priced task back to a failed check or a documented ownership gap. That trace changes the commercial conversation. It prevents cosmetic refactoring from outranking exposed data, and it gives both sides a shared definition of done. When a service cannot show the failed check, it should label the work as preventive improvement or discovery rather than presenting a guess as a defect.
A quote starts with access, not estimates
The service needs read access to every component that can change behavior before it can set a fixed scope. A repository alone is rarely enough. The first audit pass should build an asset and ownership register that ties each running component to an account, an owner, and a deployment environment.
The register should cover the source repository and its history, hosting project, production and staging domains, database, authentication provider, file storage, serverless functions, background jobs, email service, payment provider, analytics, error reporting, and any automation that deploys or modifies data. For each asset, record who owns it, who can administer it, how access can be transferred, and whether production depends on a personal account.
This is where buyers often discover that they do not own the product they paid for. The agency may control the repository. A former contractor may own the hosting team. The founder may have database access but no recovery codes. A quote cannot quietly assume those gaps will resolve themselves.
Ask the service to return an access ledger with a status for every asset. A useful example would record the source repository as buyer-owned with read access confirmed by the membership screen. It would record the production database as owner unknown with no audit access and only a connection name as evidence. It would show the hosting project under a contractor account with viewer access and transfer pending, while domain and DNS administration already belongs to the buyer.
The missing database access in this example is not a small administrative note. It blocks verification of policies, constraints, migrations, backups, and live data shape. The quote should mark the related work as conditional or exclude it until access arrives. A service that gives the same fixed number before and after seeing this ledger has not priced the actual project.
Authentication must be tested as a system
The auditor should trace every identity path from the browser to the data it authorizes. Seeing a login screen work proves only that one happy path exchanged credentials for a session. It says nothing about password recovery, email verification, session expiry, role changes, account deletion, or access across tenants.
Start with an identity and role matrix. List anonymous visitors, ordinary users, invited users, suspended users, administrators, support staff, and service processes. Then test what each identity can read and change. The most useful checks cross a boundary: user A requests user B's record, a suspended user reuses an old session, an ordinary user calls an admin endpoint directly, and a logged-out browser replays a previously valid request.
OWASP Application Security Verification Standard separates authentication, session management, and access control for a reason. Teams routinely blur them. Authentication proves who presented a credential. Authorization decides whether that identity may perform this action on this object. A valid session can still make an unauthorized request, so a client-side route guard or hidden button does not protect an API.
For a browser application backed by Supabase, inspect database grants and Row Level Security policies rather than trusting UI behavior. Supabase documentation says exposed-schema tables need RLS, and its API security guide explains that grants decide which roles can reach an object while policies decide which rows those roles can touch. The audit should enumerate tables, views, functions, and storage buckets, then exercise policies with at least two real test users.
A compact test matrix exposes gaps better than a note saying "auth works." It should attempt to make user A read user B's private row and keep the request and denied response. It should change role in a request body and preserve both the server rejection and unchanged row. It should call an API with an expired session, invoke an admin function anonymously, and reuse a deleted user's refresh token. Each result needs a timestamp and the relevant provider or application log.
The auditor should also check redirect allowlists, OAuth callback URLs, cookie attributes, token storage, rate limits on recovery and verification flows, and whether error messages disclose registered accounts. If authentication lives in generated client code while privileged writes use a service credential, the quote must include moving that trust boundary to a server-controlled component.
Every secret needs a location and a rotation decision
The service should inventory credentials in the current tree, full Git history, build settings, hosting variables, local examples, logs, and generated bundles. Searching only the latest files misses deleted .env files and keys committed three weeks ago. Removing a credential from the current branch does not make it secret again.
The inventory must distinguish publishable identifiers from privileged credentials. For example, Supabase documents publishable keys as suitable for public components when RLS protects data, while secret and legacy service_role keys belong only in backend components because they carry elevated access and can bypass RLS. Treating every visible key as a breach creates noise. Treating every key as harmless creates incidents.
The auditor can begin with reproducible searches such as:
git log -p -G '(api[_-]?key|secret|token|password)'
git grep -nE '(BEGIN (RSA|OPENSSH) PRIVATE KEY|service_role|sk_live_)'
The first command should return matching commits and patches. The second returns lines in the current tracked tree in the shape path:line:match. These searches do not prove safety because credentials can use unfamiliar formats, live in binaries, or exist only in a platform dashboard. They do create reviewable evidence and reveal whether the initial quote includes history cleanup.
GitHub's push protection documentation describes blocking recognized secrets before they enter a repository. That control helps future commits; it does not rotate a credential already exposed. For each finding, the report should name the credential owner, privilege, environments reached, last known use, rotation method, and whether rotation will break another service. The repair scope must include rotation and dependent configuration changes, not merely deleting the string.
Also inspect browser bundles and network calls after a production build. A server-only variable can become public through an incorrect build prefix, serialization into page data, or a generated API client. If the audit cannot access the relevant provider dashboard, it should say "exposure unverified" rather than "no exposed secrets."
Business logic needs examples with money and state
The auditor should reconstruct the product's rules independently of the current code. Generated applications often implement the screens faithfully while distributing business rules across button handlers, database triggers, serverless functions, and prompt-shaped conditionals. A line-by-line review cannot tell whether those rules match the business unless someone first writes the expected behavior down.
Pick the flows that create irreversible or financially meaningful state: signup and invitation, checkout, subscription changes, credit consumption, approvals, refunds, record deletion, exports, and admin overrides. For each flow, record its preconditions, authorized actor, state transition, side effects, retry behavior, and failure result. Then compare that model with the code and live data.
Suppose a credit purchase follows this sequence:
- The browser creates a pending order.
- A payment provider sends a signed completion event.
- A server function verifies the signature and marks the event processed.
- One database transaction records payment and adds credits.
- A repeated event returns success without adding credits again.
If the current app adds credits after a browser redirect, a user can replay the request. If the webhook updates the order before credits and the second write fails, money and entitlement diverge. If retries add credits twice, a normal provider retry becomes a balance error. The audit should run the same event twice, interrupt the flow between writes where practical, and retain the before-and-after rows.
This exercise sharpens a distinction that weak audits miss: a broken feature is observable behavior, while a broken invariant permits impossible state. Fixing the button may restore the happy path but leave duplicate balances, orphaned records, or unauthorized transitions in the database. The quote must include both code repair and data reconciliation when live records may already violate the rule.
Buyers should provide examples in plain language, including awkward exceptions. Who may reverse an approval? Can a user belong to two organizations? What happens to shared records when the owner leaves? Does cancellation take effect now or after a paid period? If nobody can answer, the service should price a discovery decision, not disguise a product decision as engineering.
Database integrity is more than whether queries run
The auditor should compare the intended data model, migration history, and actual production schema. Applications can appear functional while relying on nullable owner fields, duplicate external IDs, text where a constrained status belongs, missing foreign keys, or timestamps generated inconsistently in several clients.
Begin with structure: tables, columns, types, defaults, primary keys, foreign keys, unique constraints, check constraints, indexes, views, functions, triggers, and RLS policies. Confirm that migrations can create the current schema from an empty database. Then compare migration state with production. Manual dashboard changes that never reached version control are part of the remediation scope because the next deployment can erase or contradict them.
Run targeted integrity queries based on the business model. For a multi-tenant app, a useful starting set looks like this:
select id from projects where organization_id is null;
select external_id, count(*) from payments group by external_id having count(*) > 1;
select m.id from memberships m
left join organizations o on o.id = m.organization_id
where o.id is null;
select status, count(*) from orders group by status order by status;
The expected output is an empty row set for the first three checks and a reviewed set of allowed values for the last. Nonempty results are not just cleanup tasks. They show which invariant the schema failed to enforce and where application code may still create bad rows.
Inspect data access paths for injection and accidental broad updates. Parameterized client libraries help only where developers use them correctly. Dynamic SQL inside functions, string-built filters, raw query helpers, and admin tools still need review. Also look for updates or deletes without tenant predicates, functions created with elevated privileges, and views that expose columns hidden in the main UI.
Backup existence is not enough. The audit should identify retention, the account that controls restores, the latest successful backup, and whether anyone has tested a restore into a separate environment. A quote for invasive schema changes needs a rollback and data verification plan. Without one, "database repair" means experimenting on the only copy that matters.
Dependencies reveal maintenance debt and execution risk
The auditor should prove that the project installs and builds from a clean checkout with a committed lockfile. A working deployment built months ago does not show that a new engineer can reproduce it. Generated projects often accumulate overlapping UI libraries, abandoned wrappers, unused SDKs, and version pins added to silence one build error.
Record the runtime version, package manager, lockfile status, install command, build command, and resulting warnings. Run the ecosystem's advisory tool, but interpret its output. npm documentation says npm audit reports known vulnerabilities from configured dependencies. It cannot find an authorization flaw in custom code, and an advisory in a development-only package does not carry the same exposure as reachable server code.
A useful evidence capture for a JavaScript project is:
node -v
npm -v
npm ci
npm run build
npm audit
The report should retain exit codes, the first actionable error, the output artifact, and the audit JSON. Do not accept a quote that turns every advisory count into a package upgrade task. The service should trace whether vulnerable code ships, identify the safest compatible version, and note upgrades that force API or framework changes.
Architecture review belongs beside dependency review because they affect the same estimate. Map entry points, server functions, shared state, data clients, and duplicated business rules. Count generated copies only where the count changes work. A single 900-line component that owns routing, data fetching, validation, and modal state may require separation before a safe fix. Ten tidy components do not automatically need refactoring.
The popular recommendation to "rewrite it cleanly" is often wrong. Teams like rewrites because the estimate looks simple and nobody has to understand awkward code. A rewrite also discards working edge cases, migration knowledge, and production behavior that users already depend on. The audit should recommend a rebuild only when the current foundation blocks verification or repair, and it should name that blocker.
Tests must protect the repair boundary
The audit should measure whether tests detect the failures the quote promises to fix. A badge, test count, or green command has little meaning if the suite mocks every boundary and never checks authorization, persistence, or retries.
First run the existing commands from a clean checkout and record what passes, fails, hangs, or requires undocumented environment variables. Classify tests by what they cover: pure functions, components, API handlers, database policies, and complete user flows. Then connect each high-risk finding to a test that would fail before the repair and pass after it.
For authentication, use two users and assert cross-account denial. For a payment event, replay the same event identifier and assert one balance change. For deletion, assert both the intended cascade and the records that must remain. For a migration, apply it to a production-like copy and run the integrity queries. These tests produce evidence of a repaired boundary, not merely code coverage.
The quote should state which tests the service will add and where they run. It should also state what remains manual. Email deliverability, third-party account configuration, mobile browser behavior, and DNS cutovers may need an acceptance script rather than a stable automated test. Pretending every risk belongs in an end-to-end suite inflates cost and produces brittle tests.
Do not make coverage percentage the acceptance criterion unless the service defines what code counts and why the threshold matters. A small suite around identity, money, destructive actions, and tenant separation can protect a remediation better than hundreds of snapshot tests.
Deployment ownership can invalidate an otherwise sound repair
The auditor should trace how a reviewed commit becomes the production application and who can authorize every step. Source code can be correct while the live site points to another branch, carries stale variables, runs an obsolete function, or deploys from an account the buyer cannot access.
Record the production branch, build command, output directory, runtime, environment variable names, deployment trigger, domain mapping, TLS management, database migration step, and rollback method. Compare settings across local, preview, staging, and production environments. Values may differ, but their purpose and owner should not be mysterious.
Then perform a provenance check. Choose a harmless build identifier, place it in an approved diagnostic location, deploy through the documented path, and verify that production reports the same identifier. This catches manual uploads, shadow projects, and branch confusion. Remove the identifier afterward if it has no operational use.
Ownership matters as much as configuration. The buyer should control the organization accounts, billing, recovery methods, domains, and production credentials. The remediation service may need temporary administration, but the handoff should leave named buyer-controlled owners and revoke obsolete collaborators. Shared passwords are not a handoff plan.
The audit also needs an outage and rollback discussion. If a database migration and application release must land together, say how the team prevents old code from reading the new schema incorrectly. If rollback cannot reverse a data transformation, use a forward repair and backup checkpoint instead. A generic promise to "roll back if needed" does not cover destructive migrations.
FixMyMess offers a free code audit covering diagnosis before commitment, which can supply this evidence for buyers who cannot inspect an AI-generated project themselves. The useful deliverable is still the finding, its proof, the proposed repair, and the owner required to complete it.
A defensible quote separates facts from assumptions
The final quote should tie price and schedule to an evidence-backed finding register. Each line needs a symptom, root cause or current hypothesis, affected component, severity, repair action, verification method, dependency, and scope status. "Fix auth" is not a scope item. "Move role assignment to the server, restrict profile updates, and add cross-user policy tests" is.
Group work into three buckets. Confirmed work has evidence and can support a fixed price. Conditional work has a clear trigger, such as gaining database access or finding invalid live rows. Excluded work sits outside the service's control or the buyer's current decision. This structure lets a buyer compare quotes without pretending all uncertainty disappeared.
Severity and estimate confidence should stay separate. A critical authorization bypass can be easy to reproduce and cheap to repair. A medium-severity data inconsistency can require days of record analysis because nobody knows how many rows it affected. One label describes impact; the other describes how well the service understands the work. Combining them encourages auditors to overprice dramatic findings and underprice murky ones.
Each finding should carry an evidence reference that the buyer can inspect. For a cross-tenant read, that could be a redacted request, response, user identities, and the policy that allowed it. For a failed build, keep the clean-checkout commit, runtime version, command, exit code, and first relevant error. Screenshots help with dashboard configuration, but plain text exports are easier to compare after the repair. Redact personal data and credential values while leaving enough context to reproduce the result.
Estimates also need units that match the work. Quote a defined migration with its verification as one item. Quote repeated cleanup by a stated record range or a time allowance with an approval point. Do not hide coordination, account transfer, data backup, and release monitoring under project management. Those tasks consume real time and sometimes require the buyer or a former vendor to act.
The schedule should show gates, not just a start date and delivery date. A practical sequence might require account access before policy verification, buyer approval of disputed business rules before logic repair, a backup checkpoint before migration, and acceptance tests before production release. If one gate depends on a third party, name that dependency and explain what work can continue while it is blocked.
Acceptance language should describe observable results. For example, "an ordinary user receives a denied response when requesting another organization's invoice" can be tested. "Authorization is secure" cannot. "The application installs from a clean checkout and the production build exits successfully under the recorded runtime" is better than "the codebase is stable." The same standard belongs on data repair: name the integrity query and expected empty result.
Buyers should ask how the service handles a finding that changes after work starts. A reasonable change process shows the new evidence, explains why the original audit could not reveal it, states the effect on price and schedule, and waits for approval unless immediate action prevents harm. That protects both sides. It also exposes weak audits, because ordinary findings that should have appeared during inspection cannot be relabeled as surprises.
Finally, the quote should say what the buyer receives at handoff. At minimum, expect the repaired source, migrations, configuration inventory without secret values, added tests, finding register with resolution status, deployment instructions, ownership ledger, and known residual risks. Access revocation should be a named task. A repaired application with no operational record simply becomes the next inherited mystery.
Ask for these quote attachments:
- The asset and ownership ledger, with access gaps.
- The finding register, with proof and repair boundaries.
- The test and acceptance plan for each high-risk change.
- The deployment, migration, rollback, and handoff plan.
- Assumptions, exclusions, and rates or approval rules for conditional work.
The service should also identify decisions that belong to the buyer. Engineers can show that two cancellation behaviors conflict; they cannot choose the commercial policy without authority. Put that decision on the schedule with an owner and due date so it does not become invisible delay.
Reject estimates that depend on adjectives. "Minor cleanup," "production ready," and "standard security hardening" cannot be accepted or tested. A good quote lets another competent practitioner inspect the same evidence and understand why the work exists. If access remains missing, the honest number is a bounded discovery phase followed by a revised scope. Precision invented before inspection is sales theater, and inherited applications already contain enough fiction.
FAQ
How long should an inherited application audit take?
The time depends on the number of systems, risk-bearing flows, and access gaps, not the repository size alone. A small app with payments and missing production access can demand more investigation than a larger internal tool with clear ownership.
Can a remediation service quote from repository access alone?
It can quote code-only work, but it cannot credibly quote the whole production repair. Authentication settings, live schema, secrets, hosting configuration, and account ownership can change both scope and risk.
What access should I give an auditor?
Start with read or viewer access wherever the platform supports it, including source history, hosting, database, authentication, storage, logs, and deployment settings. Grant temporary administration only when a specific verification requires it, and record that change.
Is a working login enough to prove authentication is safe?
No. The audit must test recovery, expiry, role changes, direct API calls, and cross-user access. A login can succeed while authorization still exposes another customer's records.
Should every exposed API key be rotated?
Rotate privileged credentials and any credential whose secrecy controls access. First classify publishable identifiers correctly, then document privilege, exposure, dependencies, and the rotation result instead of deleting strings blindly.
Does npm audit cover application security?
No. It reports known dependency vulnerabilities available through the configured registry. Custom authorization, insecure business logic, database policies, leaked credentials, and deployment errors need separate inspection.
When is rebuilding an AI-generated app better than repairing it?
Rebuild when the current foundation prevents safe verification or change, and name the blocker. Messy code alone is not enough; a rewrite can lose working behavior and introduce a second set of defects.
What should a fixed-price remediation quote include?
It should include confirmed findings, specific repair actions, acceptance evidence, dependencies, ownership tasks, and explicit exclusions. Unknown work should have a trigger and approval rule rather than hiding inside a confident total.
How do I know the repaired app was actually deployed?
Require a documented deployment path and verify a harmless build identifier through that path. Also confirm the production branch, environment, migrations, domain mapping, and rollback owner.
Who should own production accounts after remediation?
The buyer's organization should own billing, recovery methods, domains, production credentials, and administrator roles. The service can hold temporary access, but the handoff should name buyer-controlled owners and remove obsolete collaborators.