If You Vibe Code an App for Work, Put the Backend in Charge
Someone on Reddit asked about deploying a custom vibe-coded app for work, installed on a local server. They could not code their way through problems, but figured Claude could fix things when they broke.
I have been programming for 30 years. Beyond the obvious “does it work?”, these are the two things I would check first:
- the backend must not blindly trust the frontend
- secrets must not leak into the frontend
The backend must not trust the frontend
Assume a website frontend talking to a server-side backend. Same idea applies to mobile apps, desktop apps, browser extensions, internal dashboards, whatever. If there is a client and a server, the client is not trusted.
It is easy to build as if only your frontend will ever talk to your backend. Maybe the button is hidden. Maybe the form validates the email address. Maybe the frontend only sends role: "user".
But none of that matters if the backend accepts bad requests directly.
Anyone who can reach your backend can call it directly:
curl -X POST https://your-app.example.com/api/generate \
-H "Content-Type: application/json" \
-d '{"prompt":"do expensive AI work for me"}'
They do not need to use your UI.
They can try:
- login attempts
- account creation
- password reset flows
- free trial limits
- free AI calls
- alt text generation
- file uploads
- admin-looking payloads
- object IDs that belong to other users
- prices changed to
0 isAdmin: trueplan: "enterprise"
If the backend accepts it, it happened.
Frontend validation is for user experience
Frontend validation is useful. It makes the app feel better. It catches mistakes before a request goes over the network.
But it is not security.
If your frontend checks that a file is smaller than 10 MB, the backend still has to check that the file is smaller than 10 MB.
If your frontend hides the “delete project” button from non-admins, the backend still has to check that the current user is allowed to delete the project.
If your frontend disables the “generate” button after 10 free AI calls, the backend still has to count the calls.
The frontend can help honest users avoid mistakes. The backend decides what is allowed.
Ask the agent to check this directly
If I were vibe-coding an internal app and did not trust myself to catch this, I would ask the agent to review the backend directly.
Something like:
Review this app for places where the backend trusts the frontend too much.
Check all API routes. For each route, verify:
- authentication is required where needed
- authorization checks happen on the backend
- users can only access their own records
- request body fields cannot override server-owned fields
- paid or limited features are enforced server-side
- rate limits exist for expensive operations
- file upload limits are enforced server-side
Return concrete file paths and fixes.
The exact prompt does not matter. The important part is asking about the class of bug directly.
Coding agents are good at fixing things when you point them at the right problem. “Is this app secure?” is too vague.
You still have to decide whether the agent’s answer is good enough. For a work app with real data, real users, or real money involved, I would get a human programmer to check it too.
Rate limit anything expensive
AI calls make this worse because the attack can cost you money immediately.
If your app has a free feature that calls OpenAI, Anthropic, Gemini, or any other paid API, assume someone will try to call it directly.
Even on a local server, ask what “local” means.
Is it only bound to localhost? Is it exposed on the office Wi-Fi? Is it behind a tunnel? Is it reachable through VPN?
Rate limit these endpoints:
- login
- signup
- password reset
- email sending
- AI generation
- file uploads
- anything that hits a paid third-party API
Also set billing limits on the provider side. Do not rely only on your own app code for this.
For an internal tool, the rate limits can be simple. You do not need a giant abuse prevention system on day one. But you need something.
Do not put secrets in the frontend
The second thing I mentioned was leaking API keys or secrets in the frontend.
Frontend code is sent to users. For web apps, that is literal JavaScript in the browser. For mobile and desktop apps, it is still code running on a device you do not control.
Assume an attacker can inspect it.
At minimum, they can search the downloaded code for strings that look like secrets:
sk-...
eyJ...
AKIA...
-----BEGIN PRIVATE KEY-----
Some keys are meant to be public. Analytics keys are commonly public. Stripe publishable keys are public. Supabase anon keys can be used from the frontend if your row-level security is correct.
But secrets belong on the backend:
- OpenAI API keys
- Anthropic API keys
- Stripe secret keys
- database URLs
- private signing keys
- webhook secrets
- admin tokens
- service account credentials
If the frontend needs to do something that requires a secret, it should call your backend. The backend uses the secret. The frontend gets the result.
Environment variables do not automatically make secrets safe
One common mistake: putting a secret in an environment variable and assuming that makes it safe.
It depends where that environment variable is used.
In many frontend frameworks, variables with certain prefixes are intentionally bundled into the client. For example, PUBLIC_, NEXT_PUBLIC_, VITE_, or similar names usually mean “make this available to browser code.”
That is fine for public values. It is wrong for private secrets.
I would ask the agent to check this too:
Review all environment variables and config usage.
Identify any secrets that are imported or referenced by frontend code.
Check framework-specific public env prefixes.
List which variables are safe to expose and which must move server-side.
Then verify the built frontend bundle if the app matters. Search the output. Search the network requests. Search the browser source.
Do not just trust the .env file layout.
Local server does not mean safe
“Installed on a local server” can mean many things.
It might mean a machine under your desk only reachable from your laptop. It might mean an office server reachable by everyone on Wi-Fi. It might mean a NAS. It might mean a Cloudflare tunnel. It might mean “temporarily exposed for testing” that stays exposed forever.
I would still treat it as a real deployed app:
- require login if the data matters
- use HTTPS if it crosses a network
- restrict network access where possible
- keep secrets on the server
- back up important data
- log errors without logging secrets
- set billing limits for paid APIs
Internal tools are still tools. They still delete data, send emails, upload files, and call paid APIs.
My minimum checklist
For a small vibe-coded work app, my checklist would be:
- Can an unauthenticated user call any API route?
- Can one user read or modify another user’s data by changing an ID?
- Are admin actions checked on the backend?
- Are usage limits enforced on the backend?
- Are expensive operations rate limited?
- Are all secrets server-only?
- Are API billing limits configured?
- Are backups configured if the data matters?
- Is the app reachable only by the people who should reach it?
- Can I restore it if Claude “fixes” it into a worse state?
That last one matters.
If you cannot code your way out of a bad change, make sure the project is in git and committed before asking an agent to make changes. Then you can get back to a known working version.
git status
git add .
git commit -m "Working version before changes"
Use the agent. Let it help. But give yourself a way back.
I am not against vibe-coded internal tools. I use coding agents heavily. They are useful, and small custom tools can save a lot of time.
But if the app has a backend, the backend is the authority. The frontend is just a client.
And if a value is secret, it does not go into the frontend.
Good luck building.