In short
- Base44 runs the platform: SOC 2 Type II, ISO 27001, encryption at rest and in transit, and a secrets vault that only backend functions can read. Its own docs say you are responsible for your app's security settings.
- Each entity (data table) has row-level and field-level rules. Base44's reference says an operation with no rule stays open to everyone, including anonymous visitors on apps that need no login.
asServiceRolein a backend function skips every entity rule, and a function called by plain HTTP has no signed-in user. Each function has to check its caller itself.- The free security scan flags open tables, user-editable fields that rules depend on, private fields on public records and open functions. It warns you at publish time but does not stop you publishing.
- The Wiz flaw of July 2025 was fixed by Wix within 24 hours. It also showed that every app's id is public, so your rules, not a hidden URL, decide who reads what.
On this page
- Is Base44 safe? The short answer
- What Base44 is responsible for, and what you are
- The stack Base44 builds, and where it leaks
- What Base44's own security tools catch
- Base44 security risks, with concrete examples
- How to check your Base44 app
- Fixes, with prompts for the Base44 AI chat
- Base44 app security: the traps after the first fix
- Test the published app after every publish
- Base44 app security checklist
- Questions
- Sources
Is Base44 safe? The short answer
For the platform, the evidence is good. For your app, it depends on you. Base44, owned by Wix, builds a full app from a chat: a React frontend, a managed database, sign-in and hosting. The parts Base44 runs are well covered. Its security overview lists SOC 2 Type II and ISO 27001 certification, encryption at rest and in transit, regular penetration tests by internal and third-party teams, and a bug bounty program.
The same page carries a warning in a box: you are responsible for your app's security settings. Base44 provides the tools, and you review the permissions and run the scan before you publish. That split is where data leaks. The AI writes access rules as it builds, and those rules decide whether a stranger can read your bookings, messages or customer list. Nobody checks them against what your app is for except you.
What Base44 is responsible for, and what you are
| Area | Base44 does | You do |
|---|---|---|
| Servers, encryption, certifications | All of it: SOC 2 Type II, ISO 27001, GDPR, data encrypted at rest and in transit | Nothing, beyond choosing a data region on Business or Enterprise if you need one |
| Sign-in | Runs it: email and password, Google, Microsoft, Apple, SSO, and MFA for your users on the Builder plan and above | Choose the methods, who may register, and the app's visibility |
| Data rules per entity | The AI suggests rules as it builds and flags risky ones | Review every entity and every operation: create, read, update, delete |
| Backend functions | Runs them on Deno and passes the user's session when your frontend calls them | Check the caller and the owner inside each function, above all when it uses asServiceRole |
| Secrets | Stores API keys in an encrypted vault that only backend functions can read | Keep keys out of pages and frontend code |
| Dependencies | Updates the starter packages for new apps | Upgrade your own app: it keeps its versions until you fix them |
| Testing | Free scan; Wiz and Tenzai integrations on the Builder plan and above | Run them, then test the published app after every publish |
Platforms have bugs too, and Base44 has had a public one. In July 2025, Wiz Research found that two undocumented endpoints, for registration and email verification, needed only an app's id to create a verified account on a private app, SSO-only apps included. Wiz reported it on 9 July, Wix shipped a fix within 24 hours, Wiz verified it on 10 July, and Wix found no sign of abuse. Nothing is left to patch on your side. The lasting lesson is in the write-up: the app id is not a secret. It sits in the URL and in the path of the app's manifest file, so anyone can see it. Rules that check the owner of each record are what still hold if a stranger ever gets an account.
The stack Base44 builds, and where it leaks
A Base44 app is a React frontend, hosted by Base44 or on your own domain, that talks to Base44's backend through the @base44/sdk library. Your data lives in entities: tables described by a JSON Schema, which the editor calls data tables. Sign-in, file uploads, email and AI calls are built in. Custom server logic goes in backend functions, which run on Deno, and API keys go in Secrets, which only those functions can read, with secrets.get().
The important part: the browser reads and writes entities directly, with the app id and the visitor's session. There is no server code of yours in between. As with Supabase row level security, the access rules on each entity are the only thing between a stranger and your records. Base44's agent reference puts the default plainly: an operation with no rule stays open to everyone, including anonymous visitors on public apps that need no login. On an app that requires login, everyone means every account, and if anyone can sign up, that is anyone with an email address.
Each entity has two levels of rules. Row-level security decides which records a user can create, read, update or delete. Field-level security decides which fields inside a record they can read or write. A rule is true (everyone), false (no one), or a condition such as "the record's creator is the signed-in user". The holes come from these rules, from backend functions and from keys, and the risk table below lists each one with where to look.
What Base44's own security tools catch
Base44 does more here than most AI builders, and it is worth using all of it. The security scan is free on every plan: open Dashboard, then Security, then Run Security Scan. It checks these areas and offers a one-click fix for most findings, with a checkpoint in the chat so you can roll a fix back:
- Permissions: tables with missing rules, or people with more access than they should have.
- User field access: custom user fields that your rules rely on but users can edit, added in October 2026.
- Private fields: fields like emails or tokens on records anyone can read, added in October 2026.
- Exposed secrets: keys, passwords or tokens left where visitors can find them.
- Backend functions: functions a stranger can call without signing in.
- Credit protection: AI, image or email features reachable from outside your app.
- App dependencies with known vulnerabilities, and static code analysis on the Builder plan and above.
- Security headers: whether other sites can show your app in an iframe (X-Frame-Options) and use the camera or location through it (Permissions-Policy).
On the Builder plan and above you can add your own Wiz tenant for composition and code analysis, and since October 2026 connect Tenzai to run an AI penetration test on your published app, billed to your Tenzai account. Each table's Permissions page also shows a warning icon and a Permission risks detected banner when a rule looks too open.
Know the limits. The scan warns you in the publish panel but does not block publishing. Changes made after a scan turn the fix buttons off until you rescan. The scan does not cover Base44's hosting, which you cannot change anyway. And it reads your rules and code: it tells you what the rules say, which is not always what a stranger gets back from your published app.
Base44 security risks, with concrete examples
| Hole | What a stranger can do | Where to look |
|---|---|---|
| Entity with no read rule, or All Users on Read | Download every record: bookings, leads, messages, profiles | Dashboard, Data, the table, Permissions |
| Read is owner-only, Update and Delete have no rule | Change or delete other people's records without seeing them | The Update and Delete rows of the same page |
| Create open on an app with no login | Insert fake or spam records at will | The Create row: Base44's reference asks for an explicit rule on no-login apps |
| Rule compares a record to a custom user field | Change their own field to another company's value and read that company's records | User fields users can change in the scan |
| Public table with an email or phone field | Collect the contact details of everyone listed | Private fields in the scan |
Backend function with asServiceRole and no caller check | Call the function by its address and get data no rule would allow | The function's code; Backend functions in the scan |
| AI or email called from the browser | Run your AI and email features and spend your credits | Prevent unauthorized credit usage in the scan |
| Secret key in a page | Use your Stripe, OpenAI or other account directly | Exposed secrets in the scan, and your JavaScript |
How to check your Base44 app
Six checks. The first two happen in the editor and change nothing. The others look at your published app the way a stranger would. Run them on your own app only.
- 1
Run the security scan
Dashboard, Security, Run Security Scan. Read every finding before you click Fix all: the scan does not apply anything on its own, and some fixes change how pages behave. Open the Acknowledged section too, in case someone hid a real issue.
- 2
Read the rules of every table
Under Data, open each table, then Permissions. For each of Create, Read, Update and Delete, write down who is allowed. All Users means anyone, even without signing in. The Generated JSON (Preview) at the bottom shows the exact rules. Personal data should say Creator Only, or a condition on
created_by_id, on Read, Update and Delete. Then click Test permissions in preview to open the app as one of your test users and see what that person reaches. - 3
Check the app's visibility
Dashboard, Overview, App Visibility. Base44 sets apps that look like public sites to Public with no login by default. If your landing page grew into an app with accounts, check this setting, then check the rules again: visibility decides who gets in, the rules decide what they read.
- 4
Open the published app signed out
Use a private window and your browser's developer tools, on the Network tab. Browse the pages and look at what the data requests return. To retry one without a session, right-click it, copy it as cURL, delete the
Authorizationheader and the cookie, and run it. Records in the answer are records anyone can read. - 5
Repeat as a second account
Sign up a fresh test account and open a record that belongs to your first one, for example by changing the id in the address bar. If it loads, your rules check that someone is signed in, not who owns the record. That is an IDOR, the access bug we run into most often in AI-built apps.
- 6
Search the JavaScript for keys and call your functions
Paste your app's JavaScript into the API key leak checker to find secret keys. Then call each of your backend functions with no session. Each one has its own address,
https://your-app.base44.app/functions/functionName, or the same path on your own domain, so a plaincurllike the one below is enough. An answer with data, or an email sent, means anyone can trigger it.
# Your own app only. No cookie, no Authorization header: a stranger's request.
curl -i -X POST https://your-app.base44.app/functions/getInvoices \
-H "Content-Type: application/json" -d '{}'
# 401 or 403: the function checks its caller.
# 200 with records: anyone on the internet gets the same answer.Fixes, with prompts for the Base44 AI chat
Base44 recommends describing the rules to its AI chat in plain words, and it asks for your approval before changing existing ones. Be specific, name every table, and ask it to report what it left open.
Make personal data owner-only
For every data table that holds personal data (bookings, orders, messages,
profiles, uploads), set Read, Update and Delete to: the record's creator
(created_by_id equals the signed-in user's id) or an admin.
Set Create to signed-in users only.
Do not use a custom user field in any rule unless that field is locked so
users cannot edit it.
Then list every table you changed, and every table still readable by
everyone, with the reason.The rules it should produce look like this. Base44's own reference recommends created_by_id as the owner field: the platform sets it when a record is created and it is always present, unlike a custom field.
{
"name": "Booking",
"type": "object",
"properties": {
"guest_name": { "type": "string" },
"phone": { "type": "string" }
},
"rls": {
"create": { "created_by_id": "{{user.id}}" },
"read": { "$or": [ { "created_by_id": "{{user.id}}" }, { "user_condition": { "role": "admin" } } ] },
"update": { "$or": [ { "created_by_id": "{{user.id}}" }, { "user_condition": { "role": "admin" } } ] },
"delete": { "$or": [ { "created_by_id": "{{user.id}}" }, { "user_condition": { "role": "admin" } } ] }
}
}Never let a rule trust a field the user can edit
App users can change the custom fields on their own profile. A rule like "read records whose company matches the user's company" lets a user type in another company and read its records. Base44 rates this High when anyone can sign up. Click Fix all on the User fields users can change card: it locks each field so only your app's editors can change it, and moves the code that sets it during onboarding to the server. Test sign-up afterwards.
Hide private fields on public records
For a table that should stay public, like a directory or reviews, keep the record readable and put a field-level rule on the private parts:
"email": {
"type": "string",
"rls": {
"read": { "$or": [ { "created_by_id": "{{user.id}}" }, { "user_condition": { "role": "admin" } } ] }
}
}Make every backend function check its caller
When your frontend calls a function through the SDK, the user's session comes along. When anything calls it by plain HTTP, there is no user. And asServiceRole skips row and field rules entirely, so a function that uses it decides alone what the caller gets. Check the user first, read as the user where you can, and scope any service-role query to the caller:
import { createClientFromRequest } from "npm:@base44/sdk";
export default async function (req: Request): Promise<Response> {
const base44 = createClientFromRequest(req);
// 1. Who is calling? No signed-in user, no data.
const user = await base44.auth.me().catch(() => null);
if (!user) return Response.json({ error: "Sign in first" }, { status: 401 });
// 2. Read as the user: the entity rules still apply.
const invoices = await base44.entities.Invoice.filter({ created_by_id: user.id });
// 3. Only if you truly need the service role, scope it to the caller yourself:
// await base44.asServiceRole.entities.Invoice.filter({ created_by_id: user.id });
return Response.json(invoices);
}Prompt for the chat: "Review every backend function. Each one must reject callers with no signed-in user unless it is a webhook, which must verify the provider's signature. Remove asServiceRole wherever the user's own permissions are enough, and where it stays, filter by the caller's id. List what you changed." For webhooks, the Stripe webhook guide shows the signature check.
Keys, credits and files
- Keys: store third-party keys in Secrets and call the service from a backend function. If a key was ever in a page, it is public: rotate it at the provider, following what to do when an API key leaks.
- Credits: new apps run AI, email and similar integrations from backend functions only, by default. On older apps, the scan's Prevent unauthorized credit usage issue offers Fix, which restricts access, or Resolve with AI, which moves browser calls into backend functions. Then add a per-user limit, as in the guide to unprotected AI endpoints.
- Files: Base44 offers public and private uploads, plus signed links for private files. Invoices, ID documents and anything personal belong in private uploads, shown through a signed link.
Base44 app security: the traps after the first fix
- Opening Read can open writes. When Update and Delete have no rule of their own, they inherit the Write rule, then the Read rule. If your only protection lives on Read and you later make Read public, edits and deletes become public too. Give Update and Delete explicit rules first.
- Empty user fields are a gray zone. Base44's changelog says that since 2 September 2026 a rule denies access when the user's value is empty, but its agent reference still warns that an empty field can match records whose field is also empty. Do not depend on either: only gate on a user field every user has, or use
created_by_id, which is always set. - Fix all can break visitor pages. On an app without login, a permissions fix can break a page where visitors look up something they submitted, such as a booking. Use the Fix the visitor lookup page button Base44 offers, rather than opening the table again.
- Acknowledged is not fixed. An acknowledged function stays hidden until its code changes, and other acknowledged issues stay hidden until you restore them. Review that list before each launch.
- Sessions live in localStorage. Base44 keeps sign-in tokens in the browser's localStorage, not in HttpOnly cookies, and Content-Security-Policy cannot be set per app. Any script that runs in your pages can read a visitor's token, so never render user input as raw HTML and keep third-party scripts to the ones you need.
- The editor is not the live app. If your latest changes are not published, the scan says so for credit protection. Publish, scan again, then test the published address, not the preview.
Test the published app after every publish
The scan reads your configuration. A test from outside shows what actually comes back. Each time the AI rebuilds a page or adds a table, rules can change, so last month's passing check says little about today's version.
That is the part Keybrum automates, on apps whose owner has proved ownership. It reads each entity named in your JavaScript with no session (attack base44.entity-read): read-only, keeping counts, field names and one redacted record as proof. It also searches the bundle for secret keys, and tests security headers, exposed files and open AI endpoints. Your coding agent reads the findings and fixes through Keybrum's MCP server, and plans attack again on every deploy.
Base44 app security checklist
- The security scan ran after the last change, every finding is fixed or deliberately acknowledged, and the Acknowledged list was reviewed.
- Every table holding personal data has Creator Only, or a
created_by_idcondition, on Read, Update and Delete. - No table has All Users on Update or Delete. Create is limited to signed-in users unless strangers really must add records.
- No rule depends on a custom user field that users can edit.
- Public tables carry no private fields, or those fields have a field-level rule.
- Every backend function rejects callers with no user, or verifies a webhook signature, and every
asServiceRolequery is filtered by the caller. - No third-party key appears in your JavaScript; all of them are in Secrets.
- AI, email and image features run from backend functions with a per-user limit.
- App visibility matches the app: Private or login required for anything with accounts.
- Personal files use private uploads and signed links.
- The published app was tested signed out and as a second account after the last publish.
For the checks that apply to any AI-built app, the vibe coding security checklist goes further, and the guide to API keys exposed in the frontend lists which keys may ship to a browser.
Questions
Is Base44 safe to use?
The platform has the credentials you would look for: Base44 is SOC 2 Type II and ISO 27001 certified, encrypts data at rest and in transit, and runs penetration tests and a bug bounty program. The risk sits in each app's data rules and backend functions, which Base44's docs make your responsibility. Run the built-in scan, then test the published app signed out.
Is Base44 secure for business data?
The platform side covers what business buyers ask for: certifications, encryption at rest and in transit, a DPA on request, and data residency in the EU, UK, Australia or US on Business and Enterprise plans. Data is not end-to-end encrypted, so Base44 staff can access it if needed. Whether your data stays private from other users depends on the rules of each table: an entity with no rule for an operation is open to everyone.
Can other users see my data in a Base44 app?
Only if the rules allow it. Rules that check created_by_id against the signed-in user keep each person to their own records. Rules that only require a signed-in user let any account read everything, and on an app with open sign-up that means anyone. Test with a second account.
Does Base44 have a security scan?
Yes, on every plan including the free one: Dashboard, then Security, then Run Security Scan. It checks permissions, user-editable fields used in rules, private fields, exposed secrets, open backend functions, credit usage, dependencies and security headers, with static code analysis on the Builder plan and above. It warns at publish time but does not block publishing.
Does setting my Base44 app to Private protect the data?
It limits who can open the app to invited people, and it is only available on paid plans. Everyone you invite still gets whatever the rules allow, so an invited user can read other users' records if a table is open. Keep owner-only rules on personal data even in a private app.
Was Base44 hacked?
In July 2025, Wiz Research reported a flaw that let outsiders register on private Base44 apps using only the public app id. Wix fixed it within 24 hours, Wiz verified the fix, and Wix said it found no evidence of abuse. No action was needed from app owners.
Sources
- 1.Base44 security: An overview, Base44 Docs
- 2.Entities: Security (row and field level rules), Base44 Docs
- 3.Base44 entities: Row-level security (RLS), Base44 Docs
- 4.Managing data permissions, Base44 Docs
- 5.Running a security scan, Base44 Docs
- 6.Choosing who can access your app, Base44 Docs
- 7.Backend Functions Overview, Base44 Docs
- 8.Base44 integrations SDK (file uploads, core integration control), Base44 Docs
- 9.Product changelog, Base44
- 10.Critical Vulnerability in Base44, Wiz Research
- 11.Base44 flaw could have allowed access to other users' private data, TechRadar