Productera
All Posts
Founders7 min read

Why Your Contractors Built a Product That Works But Isn't Safe

Your app demos great and users are paying. But the codebase underneath is a liability. This isn't because your contractors were bad — it's because the incentives made it inevitable.

PT

Productera Team

March 21, 2026

It Demos Great

Your product works. The login screen looks clean. Users sign up, click around, and do the thing they're supposed to do. The contractor team delivered on time, more or less on budget, and the demo was impressive.

Six months later, you hire someone senior to take a look under the hood. They come back with a list of problems that makes your stomach drop. Authentication that doesn't actually authenticate. A database that's accessible from any IP address on the planet. Passwords stored in a way that means anyone with a single encryption key can read them all.

You're not alone. We've audited dozens of startup codebases that were built by contractors, and this is the pattern we see almost every time. The product works. The code doesn't protect anything.

This isn't because your contractors were incompetent. It's because the structure of most contractor engagements makes this outcome almost inevitable.

The Incentive Problem

A contractor has one job: deliver what was specified. If the spec says "users can log in and see their dashboard," that's what gets built. The login works. The dashboard loads. Ticket closed.

What doesn't get built is everything the spec didn't mention. Rate limiting on the login endpoint. Proper session management. Authorization checks to make sure User A can't see User B's data. Input sanitization to prevent someone from injecting malicious code through a form field. Audit logging so you know who did what and when.

None of these are in the user story. None of them show up in the demo. None of them are what you're evaluating when you review the sprint.

This isn't laziness — it's rational behaviour. A contractor working on a fixed scope or hourly engagement gets paid to deliver features, not to add invisible security infrastructure. Spending an extra day adding rate limiting means one less feature in the sprint. Adding comprehensive error handling doesn't get a round of applause in the demo. Setting up CI/CD and automated testing is work that benefits whoever comes after them, not the current engagement.

The incentive is to ship what's visible and move on to the next ticket.

The Knowledge Gap

There's a second, less obvious problem. Security, infrastructure, and production-readiness are specialisations. A developer who's great at building React components or Django views may genuinely not know that:

  • A framework's built-in authentication should never be explicitly disabled
  • Database ports should not be accessible from the public internet
  • Passwords should be hashed, not encrypted
  • User identity should come from the server-side token, not from the request body
  • CORS_ALLOW_ALL = True is not a valid production configuration

These aren't bugs. They're architectural decisions made by someone who didn't know they were making a security decision at all. The developer set ALLOW_ALL because it fixed the CORS error during development. They stored the user ID in the request body because it was the easiest way to get the feature working. They disabled the authentication middleware because it was getting in the way of testing.

Each individual shortcut is understandable. In aggregate, they create a codebase where the front door is wide open and there's no alarm system.

The Rotation Problem

Contractor teams rotate. The person who built the authentication module leaves after three months. The person who set up the AWS infrastructure is long gone. The person who chose the framework and its configuration has moved on to another client.

Each new contractor inherits a codebase they didn't architect, follows the patterns they find in it (including the bad ones), and adds their own features on top. Nobody has the full picture. Nobody is accountable for the system as a whole. And nobody has the incentive to stop and say "before I build the next feature, the foundation needs work."

The result is a codebase that grows features but never grows up. Twelve months and four contractor rotations later, you have a product that looks mature from the outside and is held together with duct tape on the inside.

We see this pattern with remarkable consistency. The codebase has dozens of features. It also has functions that are 2,000 lines long, the same logic copy-pasted in three places, and an authentication system that exists but isn't enforced. The code works — it just wasn't built to be maintained, secured, or scaled.

The "It's Fine Until It's Not" Moment

For a while, none of this matters. Your users don't notice. Your investors don't ask about it. Your sales calls focus on the product, not the plumbing.

Then one of these things happens:

An enterprise buyer asks if you're SOC 2 compliant. You're not, and a quick assessment reveals you'd fail six out of nine control categories. The deal stalls.

An investor does technical due diligence. They find the same patterns we find in our audits — broken auth, no tests, no CI/CD, exposed infrastructure. Your valuation takes a hit or the round gets delayed.

A security researcher finds a vulnerability. Or worse, an attacker does. And because you have no audit logging, you can't even tell what data was accessed.

You try to hire a senior engineer. They look at the codebase, see what they're inheriting, and decline the offer. Or they accept, spend their first three months untangling the mess, and nothing visible gets shipped.

The compounding cost of contractor-built technical debt isn't the debt itself — it's the opportunities it blocks.

What Contractors Should Have Handed Over (But Didn't)

Here's what a production-ready handoff looks like, versus what most contractor engagements actually deliver:

What you should getWhat you usually get
Authentication that verifies identity on every requestLogin that works in the demo
Authorization that checks what each user can accessNo access control beyond "logged in or not"
CI/CD pipeline that tests and deploys automatically"I deployed it from my laptop"
Automated tests for critical pathsZero tests
Infrastructure with proper security groups and loggingAWS defaults from the launch wizard
Dependency management with no known CVEsWhatever versions were current when they started
Documentation of architecture decisionsNothing, or a stale README
Monitoring and error trackingconsole.log

This isn't a checklist most founders know to ask for. And that's the core problem — if you don't know to specify it, it doesn't get built. Contractors deliver to spec. If the spec is "build a marketplace app," you get a marketplace app. Not a secure, observable, maintainable marketplace app.

How to Avoid This

If you're about to engage contractors:

Write security and production-readiness requirements into the spec, not just features. Require CI/CD from sprint one. Require automated tests for every feature. Specify that the framework's built-in auth must be used, not bypassed. Make infrastructure security part of the acceptance criteria.

And budget for a code review at the end of the engagement — not by the contractors themselves, but by an independent engineer. Think of it as an inspection before you accept the keys to a new house.

If you already have a contractor-built product:

Run the basics: npm audit or pip-audit for dependency vulnerabilities. Check your cloud security groups for ports open to 0.0.0.0/0. Search your codebase for user IDs coming from request bodies instead of auth tokens. Check whether your framework's authentication middleware is actually enabled.

Our five-point audit checklist covers the most critical checks you can do yourself in an afternoon.

If you're scaling and need it done right:

The pattern that works — and we're biased, but we've seen it consistently over eight years — is a small, dedicated team that stays with the product. Not a rotating contractor bench. Not a 15-person outsourced team where nobody has context. Three to four people who understand your domain, own the codebase, and are accountable for both features and foundations.

The difference between "a team that builds features" and "a team that builds a product" is the difference between a demo and a business.

Related: Patterns We See in Every Startup Audit · How to Audit Your AI-Generated Codebase · The Real Cost of Scaling a Vibecoded App · You're Outsourcing the Wrong Roles

Ready to ship?

Tell us about your project. We'll tell you honestly how we can help — or if we're not the right fit.