IS DATABUTTON SAFE? SECURITY ANALYSIS | VIBEEVAL

Is Databutton safe? The short answer

Databutton the platform is safe. Apps built with Databutton are safe when the developer adds the layers the agent left out. The platform handles hosting, deploys, and a secrets store correctly, and the generated stack — React plus Python FastAPI — is a solid architecture. The generated apps consistently ship with endpoints missing auth dependencies, CORS configured wide open, docs endpoints enabled in production, and the occasional third-party key called from the browser. Each gap is a small fix; collectively they are the difference between a demo and a production app.

The Databutton generation pattern

Databutton’s agent generates functional code quickly. It prioritizes “this works on first try” over “this is hardened.” That has a predictable cost:

  • Endpoints ship without auth. A generated /routes/projects/{id} returns data without checking who is asking, unless you explicitly asked for auth.
  • Ownership is assumed, not checked. Even with auth wired, generated lookups return any record whose ID the caller supplies.
  • CORS opens wide. The generated CORSMiddleware frequently allows all origins with credentials, because that makes development friction-free.
  • Keys drift client-side. The secrets store exists, but generated code sometimes calls a third-party API from React — putting the key in the bundle.
  • The API documents itself to attackers. FastAPI’s /docs and /openapi.json stay enabled in production, enumerating every route.

These are not bugs in Databutton; they are characteristics of AI generation under “make this work” pressure. Knowing the pattern is the entire fix — every audit item below targets one of those failure modes.

The 6 areas to harden in every Databutton app

1. Authentication on every endpoint

Generated FastAPI routes default to “anyone can call this.” The fix is mechanical: a shared auth dependency that verifies the caller’s token, attached to every protected route — or to the whole router so a new route can’t ship open.

Fix. Centralize auth in a dependency:

from fastapi import APIRouter, Depends, HTTPException

async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = verify_firebase_token(token)  # verify signature + audience
    if not user:
        raise HTTPException(status_code=401)
    return user

router = APIRouter(dependencies=[Depends(get_current_user)])
# every route on this router now requires auth

Router-level dependencies are the safer default than per-route opt-in — a forgotten route fails closed, not open.

2. Ownership checks (BOLA / IDOR)

Auth confirms the request has a valid token. It does not confirm the token’s user owns the resource being requested. AI-generated routes routinely look up by ID and return whatever they find — including records belonging to other users.

Fix. Every route that takes a resource ID checks ownership:

@router.get("/projects/{project_id}")
async def get_project(project_id: str, user=Depends(get_current_user)):
    project = db.get_project(project_id)
    if project is None:
        raise HTTPException(status_code=404)
    if project.owner_id != user.uid:
        raise HTTPException(status_code=403)
    return project

Manual test: sign in as user A, copy a request with a record ID, sign in as user B, and re-fire it. If B gets A’s data, you have a BOLA.

3. Strict input models (mass assignment)

Pydantic models exist in the generated code, but write endpoints sometimes accept extra fields or reuse the database model for updates. A client that can set owner_id or is_admin in a request body owns your authorization model.

Fix. Separate input models from storage models, and forbid extras:

from pydantic import BaseModel, ConfigDict

class ProjectUpdate(BaseModel):
    model_config = ConfigDict(extra="forbid")
    name: str
    description: str | None = None
    # owner_id, role, is_admin: never accepted from the client

@router.patch("/projects/{project_id}")
async def update_project(project_id: str, body: ProjectUpdate,
                         user=Depends(get_current_user)):
    ...  # ownership check, then apply only body's fields

4. CORS locked to your origin

Generated FastAPI middleware frequently ships allow-all origins with credentials enabled. Any website can then make credentialed requests to your API through a logged-in visitor’s browser.

Fix. Allowlist the production origin:

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://yourapp.example.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE"],
    allow_headers=["Authorization", "Content-Type"],
)

See CORS + credentials misconfig for the attack this closes.

5. Production information hygiene

FastAPI serves /docs, /redoc, and /openapi.json by default — a complete, typed map of your API for anyone who visits. Combined with verbose validation errors, an attacker learns your whole surface without guessing.

Fix. Disable the docs endpoints in the deployed app and return generic errors:

from fastapi import FastAPI
from fastapi.responses import JSONResponse

app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)

@app.exception_handler(Exception)
async def unhandled(request, exc):
    log.exception("Request failed")
    return JSONResponse(status_code=500,
                        content={"detail": "Internal server error"})

6. Secrets and spend control

The secrets store is the correct home for every third-party key — but only calls made from the FastAPI side use it. Audit the React code and the deployed bundle for keys, and rate-limit anything metered.

Fix. Route third-party calls through the backend, then cap spend:

# every LLM call goes through an authenticated, rate-limited endpoint
@router.post("/ai/summarize")
@limiter.limit("20/hour")  # per authenticated user
async def summarize(body: SummarizeIn, user=Depends(get_current_user)):
    key = db.secrets.get("OPENAI_API_KEY")  # secrets store, server-side
    ...

Without a per-user limit, one script against an LLM endpoint runs up your bill in minutes. Check the deployed bundle with the Token Leak Checker; rotate any key that ever shipped client-side.

Scheduled jobs — the forgotten surface

Databutton supports scheduled jobs, and they run with your backend’s full privileges. Two rules keep them safe: pull credentials from the secrets store (never inline), and validate anything a job ingests from an external source before writing it anywhere user-visible. A job that fetches an external feed and stores it for rendering is an injection path if the feed is attacker-influenced — see LLM-rendered HTML/Markdown for the rendering half of that bug.

Pre-launch Databutton checklist

A practical sequence to run before pushing a Databutton app to a real audience:

  1. Every FastAPI route that touches user data has an auth dependency.
  2. Every ID-keyed route checks ownership after the lookup.
  3. Write models forbid extra fields; owner/role never come from the client.
  4. CORS allowlists the production origin only — no allow-all with credentials.
  5. /docs, /redoc, and /openapi.json are disabled in production.
  6. Error responses are generic; stack traces and validation internals stay server-side.
  7. No third-party keys in the React source or the deployed bundle; all secrets in the secrets store.
  8. Rate limits on auth endpoints and every LLM-calling or metered endpoint.
  9. Firebase Auth (or your provider) tokens are verified server-side, signature and audience.
  10. Run VibeEval against the deployed URL for the dynamic pass.

Databutton vs Base44 vs Lovable — security positioning

  • Databutton. React + Python FastAPI, platform-hosted, with a secrets store and scheduled jobs. Failure modes are missing auth dependencies, BOLA, open CORS, and docs endpoints in production — classic API-layer gaps.
  • Base44. All-in-one with built-in entities and permissions panels. Failure modes concentrate in entity permission configuration.
  • Lovable. Opinionated Supabase + frontend. Failure modes concentrate in RLS, anon keys, and BOLA.

Pick the tool whose failure modes you have the bandwidth to audit. For Databutton, that means someone comfortable reading FastAPI routers — the checks are mechanical once you know where to look.

The verdict

Databutton produces real full-stack applications quickly, on a sound architecture. Security is not the agent’s priority. Treat every Databutton-generated app as needing a security review before production: auth dependencies on every route, ownership checks, strict input models, CORS locked down, docs endpoints off, secrets server-side, and rate limits on anything metered. The list is mechanical and scannable. Run it before launch, every launch.

Scan your Databutton app

Let VibeEval scan your deployed Databutton application for the missing-auth, BOLA, CORS, and credential-leakage patterns that AI generators most often leave in.

COMMON QUESTIONS

01
Is Databutton safe to use?
Databutton the platform is safe — it's a hosted environment with managed deploys, a built-in secrets store, and HTTPS. The risk sits in the apps its agent generates: FastAPI endpoints ship without auth dependencies unless asked, CORS middleware is often configured wide open, third-party API calls sometimes land in the React code where keys leak into the bundle, and docs endpoints stay enabled in production.
Q&A
02
What is the most common Databutton app vulnerability?
Missing auth on generated FastAPI endpoints. The agent produces working routes fast, and working does not include authentication unless you prompted for it. Every route that reads or writes user data needs an auth dependency that verifies the caller's token, plus an ownership check comparing the record's owner to the authenticated user.
Q&A
03
Are API keys safe in Databutton's secrets store?
Keys in the secrets store are protected — but only while they stay server-side. Generated code sometimes calls third-party APIs directly from the React frontend, which puts the key in the browser bundle where anyone can extract it. Audit the deployed JavaScript for key prefixes like sk-, sk_live_, and AIza, route those calls through FastAPI, and rotate anything that ever shipped client-side.
Q&A
04
Does Databutton enforce authentication on generated endpoints?
No — auth is the developer's responsibility. Auth is commonly wired via Firebase Auth or a similar provider, but the generated FastAPI routes don't automatically require it. Attach an auth dependency to every protected route, verify tokens server-side (signature and audience, not just decode), and add ownership checks on every ID-keyed lookup.
Q&A
05
Can I use Databutton for an app handling user data?
Yes, with manual hardening. A Databutton-generated app needs: an auth dependency on every data route, ownership checks on every ID-keyed route, strict Pydantic models that forbid extra fields, CORS locked to your production origin, docs endpoints disabled, rate limits on LLM-calling endpoints, and generic error responses. Run a deployed-app scan before going live.
Q&A
06
Is Databutton's CORS configuration safe by default?
Frequently not. Generated FastAPI middleware often ships allow_origins set to all origins together with allow_credentials=True. That combination lets any website make credentialed requests to your API from a visitor's browser. Set the origin allowlist to your production domain only.
Q&A
07
What does Databutton do well from a security standpoint?
The architecture is sound: a real Python FastAPI backend rather than client-only logic, a built-in secrets store so keys have a correct home, platform-managed hosting and deploys, and scheduled jobs that run server-side. Pydantic gives typed validation at the boundary. The gap is application-level — the agent ships functionality faster than it ships hardening.
Q&A

SCAN YOUR APP

14-day trial. No card. Results in under 60 seconds.

START FREE SCAN