Security Basics

9 min

What a 48 hour security audit finds before launch

What a 48 hour security audit finds before launch

Not every finding deserves the same urgency. What a tightly scoped 48 hour audit checks first: exposed credentials, IDOR, Supabase RLS, and payment trust boundaries, and how to prioritize what comes back.

Not every finding deserves the same urgency. What a tightly scoped 48 hour audit checks first: exposed credentials, IDOR, Supabase RLS, and payment trust boundaries, and how to prioritize what comes back.

A customer should not be able to change one number in a URL and view another customer’s invoice. Your browser bundle should not contain a Supabase service-role key. And a payment webhook should not be trusted simply because it reached your endpoint.

These are not theoretical security concerns. They are common failure modes in fast-moving SaaS products, especially when a live app has been assembled with AI assistance, managed services and a tight launch window. A 48 hour security audit is designed to find the issues that can lead to exposed data, account takeover, fraudulent actions or a difficult conversation with your first enterprise customer.

The goal is not to produce a long document full of generic warnings. It is to give a founder or product team a credible view of what is exposed, how serious it is and what should be fixed first.

What a 48 hour security audit is actually for

A short audit is an application-security assessment focused on the real attack surface of a live product: its public URL, frontend code, APIs, authentication flows, database rules, integrations and repository configuration. It is particularly useful before a launch, fundraising process, customer security review or major feature release.

Forty-eight hours does not mean every line of code receives the same level of scrutiny, nor does it replace a larger penetration test for a mature platform. It means the work is tightly scoped around the areas most likely to create immediate business risk. For an early-stage product, that is often the right trade-off.

A useful audit starts with both the live application and the repository. Testing the live site alone can reveal exposed endpoints and broken access controls, but it may miss credentials committed in configuration files, unsafe server-side routes or code paths that have not yet been reached through the interface. Reviewing source code without the live environment can miss deployment mistakes, headers, production permissions and differences between local and hosted configuration.

The combination matters because security failures rarely sit neatly in one place. A secure-looking frontend can call an API that trusts a client-supplied user ID. A carefully written database policy can be bypassed by an exposed admin key. A well-built checkout flow can still accept forged webhook events if signature verification is absent.

The findings that matter most in a 48 hour security audit

Not every finding deserves the same response. A missing header and a publicly accessible customer database are both security issues, but they do not carry the same urgency. A good report separates critical paths from sensible hardening work and explains the practical consequence of each issue.

Exposed credentials and privileged keys

Repositories built quickly often contain secrets in .env files, example configuration, commit history or frontend bundles. The most serious cases include Supabase service-role keys, database connection strings, private API tokens, payment-provider secrets and signing keys.

A public Supabase anon key is not automatically a breach. It is intended to be used in a client application. The question is whether row-level security is enabled and correctly configured. A service-role key, by contrast, should never be delivered to a browser or committed to a repository that unauthorised people can access. It can bypass row-level security and give an attacker broad control over data.

The audit should identify the file path, affected key type, exposure route and exact containment steps. In many cases, rotation is required as well as code removal. Deleting a secret from the latest commit does not make it safe if it remains in Git history or has already been deployed.

Authentication and authorisation failures

Authentication answers, “Who is this user?” Authorisation answers, “Are they allowed to do this?” Products frequently get the first part right and leave gaps in the second.

A common example is insecure direct object reference, usually shortened to IDOR. A signed-in user requests /api/orders/123, changes the number to 124, and receives another user’s order. The endpoint may be protected by login, but it has not checked ownership or tenant membership.

Other high-risk patterns include trusting role claims supplied by the browser, accepting JWTs with weak or missing validation, allowing password-reset or email-verification links to be replayed, and exposing administrative functions through routes that only hide the button in the interface. Security needs to be enforced on the server and at the database layer where appropriate, not merely in the UI.

For multi-tenant SaaS products, the audit should test whether a normal account can read, modify or delete records belonging to another organisation. That includes less obvious objects such as uploaded files, support tickets, saved payment methods, invitations and usage data.

Supabase RLS and database exposure

Supabase accelerates development, but its flexibility can create an unpleasant production surprise. A table may have row-level security disabled. A policy may permit all authenticated users to select every row. An insert policy may allow a user to choose another user’s user_id, creating records on their behalf.

These are not edge cases. They are exactly the sort of configuration errors that can survive a functional test because the app appears to work correctly for its creator.

An effective review examines which tables are reachable from the client, whether RLS is enabled, the logic of each policy and how privileged server operations are separated from public requests. It also looks at storage buckets, since files can expose personal information even when the database itself is protected.

Payment and webhook trust boundaries

Payments introduce a second set of identities: the customer, your application and the provider. A secure payment flow does not take a price, product entitlement or subscription status at face value from the browser. Those values should be derived or confirmed on the server.

Webhook handlers need similar care. If an endpoint marks a user as paid whenever it receives a JSON payload claiming success, an attacker may be able to grant themselves access without paying. The handler should verify the provider signature, use the raw request body where required, validate event types and handle replayed events safely.

This is also where business logic matters. A technically valid payment integration can still create fraud risk if discounts, credits, refunds or access upgrades can be manipulated through unverified parameters.

Dependencies, headers and exposed endpoints

Known vulnerable dependencies are rarely the only issue, but they are worth checking. An audit can identify packages with serious disclosed vulnerabilities, outdated frameworks and dangerous development tools left enabled in production.

It should also review security headers and browser controls. Content Security Policy can reduce the impact of script injection. HSTS helps prevent downgrade attacks. Cookie settings affect session theft risk. CORS rules determine which websites can call your APIs from a browser. Missing headers are not always urgent on their own, but they can make a more serious flaw easier to exploit.

How the 48-hour process should work

The process should be straightforward because founders should not need to become security specialists to arrange an assessment. You provide the live application URL and appropriate repository access. The reviewer maps the application, runs targeted automated checks and manually tests the areas where automated tools are least reliable.

Tools such as GitLeaks, Snyk, OWASP ZAP, Burp Suite and Semgrep can quickly surface leaked secrets, vulnerable packages, suspicious patterns and exposed routes. They are useful accelerators, not a substitute for judgement. AI-generated code can look convincing while making unsafe assumptions about identity, permissions, input validation or framework defaults.

Manual review is where those assumptions are tested. Does a route verify that the requesting user owns the resource? Does a Supabase policy match the intended tenant model? Is a server action truly server-side? Can a client alter the amount passed to a payment endpoint? Are sensitive operations protected against replay, enumeration or privilege escalation?

Within 48 hours or less, the result should be a severity-rated report that tells the team what was found, where it lives and how to resolve it. A critical finding needs a clear path such as: rotate this key, remove it from src/lib/supabase.ts, move privileged calls to a server route, enable RLS on this table and apply this policy change. “Improve access control” is not an implementation plan.

What to fix first after the report

Start with anything that permits unauthorised access to customer data, privileged systems or money. That usually means exposed secrets, broken RLS, IDOR vulnerabilities, administrative access flaws and insecure payment or webhook handling. Contain active exposure first by rotating credentials, restricting access or disabling an unsafe endpoint if necessary.

Next, fix high-severity issues that could become account compromise or cross-tenant access. Then address medium-risk weaknesses, dependency updates and defensive controls such as headers. The precise order depends on your product. A missing CSP is more urgent for an app rendering user-generated HTML than for a tightly controlled internal dashboard. A permissive storage bucket is more urgent when it contains identity documents than when it holds public marketing assets.

Where internal capacity is limited, direct remediation can be more valuable than a report alone. HollowByte can implement the required code and configuration changes, then verify that the fix closes the original path rather than merely moving it.

Your app does not need to be perfect before customers see it. It does need to avoid the predictable failures that turn early momentum into an incident. A focused review gives you a practical answer to the question that matters before you invite more users in: can each person access only what they should?

Back to blog

(function() { function applyMainRole() { var hero = document.getElementById('hero'); if (!hero) return false; var node = hero; while (node.parentElement && node.parentElement !== document.body) { node = node.parentElement; } if (node && node.parentElement === document.body) { node.setAttribute('role', 'main'); return true; } return false; } if (applyMainRole()) return; var attempts = 0; var interval = setInterval(function() { attempts++; if (applyMainRole() || attempts > 20) { clearInterval(interval); } }, 250); })();