[{"data":1,"prerenderedAt":851},["ShallowReactive",2],{"blog-is-safe/emergent":3},{"id":4,"title":5,"body":6,"category":820,"date":821,"dateModified":821,"description":822,"draft":823,"extension":824,"faq":825,"featured":823,"headerVariant":836,"image":837,"keywords":838,"meta":839,"navigation":503,"ogDescription":840,"ogTitle":837,"path":841,"readTime":842,"schemaOrg":843,"schemaType":844,"seo":845,"sitemap":846,"stem":847,"tags":848,"twitterCard":849,"__hash__":850},"blog/blog/is-safe/emergent.md","Is Emergent Safe? AI App Builder Security Review (2026)",{"type":7,"value":8,"toc":810},"minimark",[9,13,16,28,33,40,88,92,95,98,101,178,181,184,187,202,209,213,216,255,262,275,330,333,346,354,358,361,368,374,416,419,477,483,486,538,549,565,569,572,615,622,633,645,658,662,665,668,675,683,690,694,726,776,794,806],[10,11,12],"p",{},"On July 15, 2026, Emergent announced a $130 million Series C at a $1.5 billion post-money valuation, roughly a year after public launch. The numbers behind it are large: more than 200,000 paying customers, around $120 million in annual recurring revenue, and over 12 million apps built on the platform in twelve months. Most of those apps were built by people who cannot read the backend code that runs them.",[10,14,15],{},"That last part is the reason this review exists. There is almost no independent security writing about Emergent, and the platform's architecture differs from the Supabase-backed builders in a way that quietly invalidates most of the advice its users have probably already read.",[17,18,19],"tldr",{},[10,20,21,22,27],{},"Emergent is trustworthy as a vendor and generates real, portable code you own on GitHub. The security problem is structural, not malicious. Emergent's default stack is React plus FastAPI plus managed MongoDB, and MongoDB has no row-level security, so there is no database-level backstop underneath your API. Every authorization decision lives in a FastAPI route handler an agent wrote. Read your endpoints, then ",[23,24,26],"a",{"href":25},"/blog/getting-started/first-scan","scan what shipped",".",[29,30,32],"h2",{"id":31},"our-verdict","Our Verdict",[34,35,37],"verdict-badge",{"verdict":36},"caution",[10,38,39],{},"Use with Caution",[41,42,43,48,67,71],"pros-cons",{},[44,45,47],"h4",{"id":46},"whats-good","What's Good",[49,50,51,55,58,61,64],"ul",{},[52,53,54],"li",{},"Your database is never exposed to the browser, unlike anon-key architectures",[52,56,57],{},"Code exports to your own GitHub repo as standard React and FastAPI, with real commit history",[52,59,60],{},"No proprietary runtime, so you can leave without a rewrite",[52,62,63],{},"Managed MongoDB, TLS and deploys are handled for you",[52,65,66],{},"Secrets live in the backend environment, not in client bundles",[44,68,70],{"id":69},"what-to-watch","What to Watch",[49,72,73,76,79,82,85],{},[52,74,75],{},"MongoDB has no row-level security, so there is no backstop below your API",[52,77,78],{},"A single missing check on one endpoint exposes that entire collection",[52,80,81],{},"Untyped request bodies open the door to NoSQL operator injection",[52,83,84],{},"Generated FastAPI CORS config is a recurring source of findings",[52,86,87],{},"Almost no independent security coverage to learn from yet",[29,89,91],{"id":90},"the-architecture-is-the-whole-story","The Architecture Is the Whole Story",[10,93,94],{},"Skip this section and nothing else in the review will land properly.",[10,96,97],{},"Emergent deploys full-stack apps as a React frontend, a FastAPI backend, and a managed MongoDB instance provisioned with the app. Deploys take about fifteen minutes and run 50 credits per month per app. Your code goes to your GitHub repository in standard form.",[10,99,100],{},"Compare that to how Lovable, Bolt and Base44 typically wire things up:",[102,103,104,119],"table",{},[105,106,107],"thead",{},[108,109,110,113,116],"tr",{},[111,112],"th",{},[111,114,115],{},"Supabase-style builders",[111,117,118],{},"Emergent",[120,121,122,134,145,156,167],"tbody",{},[108,123,124,128,131],{},[125,126,127],"td",{},"Who talks to the database",[125,129,130],{},"The browser, using a public anon key",[125,132,133],{},"Your FastAPI backend only",[108,135,136,139,142],{},[125,137,138],{},"Where the credential lives",[125,140,141],{},"Shipped in the client bundle",[125,143,144],{},"Server-side environment variable",[108,146,147,150,153],{},[125,148,149],{},"Database reachable from internet",[125,151,152],{},"Yes, by design",[125,154,155],{},"No",[108,157,158,161,164],{},[125,159,160],{},"Authorization enforced by",[125,162,163],{},"Postgres RLS policies plus your code",[125,165,166],{},"Your code, and nothing else",[108,168,169,172,175],{},[125,170,171],{},"Failure mode",[125,173,174],{},"Missing RLS policy exposes a table to anyone",[125,176,177],{},"Missing check on one route exposes a collection",[10,179,180],{},"Read the last two rows together. On Supabase the database is exposed on purpose, and row-level security is the wall that makes that survivable. It's a wall people forget to build, which is why \"Lovable app leaked user data\" is a genre at this point.",[10,182,183],{},"Emergent never opens that door. The browser cannot reach MongoDB. That's a real advantage and worth saying plainly, because it removes the single most common catastrophic failure in vibe-coded apps.",[10,185,186],{},"But it also means the wall is gone, because there was never a door to guard.",[188,189,190],"danger-box",{},[10,191,192,196,197,201],{},[193,194,195],"strong",{},"MongoDB has no row-level security."," PostgreSQL lets you attach a policy to a table that filters rows by the current user, and that policy runs no matter which query arrives. MongoDB has role-based access at the user and collection level, but nothing that says \"this request may only see documents where ",[198,199,200],"code",{},"owner_id"," equals the caller.\" On Emergent, if your FastAPI handler forgets to filter by the logged-in user, the database will happily return every document in the collection. There is no layer beneath it that says no.",[10,203,204,205,208],{},"So all the Supabase hardening advice you've read, the RLS policies, the ",[198,206,207],{},"auth.uid()"," checks, the \"enable RLS on every table\" checklists, does not apply here. Not because it's wrong, but because there's nothing to apply it to. Your FastAPI routes are the entire security boundary.",[29,210,212],{"id":211},"the-endpoint-audit-that-actually-matters","The Endpoint Audit That Actually Matters",[10,214,215],{},"Here's the shape of the bug to look for. This is the pattern we see constantly in scans of API-backed apps, and it's the one MongoDB gives you no protection against.",[217,218,220],"code-block",{"label":219},"The vulnerable version",[221,222,227],"pre",{"className":223,"code":224,"language":225,"meta":226,"style":226},"language-python shiki shiki-themes github-dark","@app.get(\"/api/invoices/{invoice_id}\")\nasync def get_invoice(invoice_id: str, user = Depends(get_current_user)):\n    invoice = await db.invoices.find_one({\"_id\": ObjectId(invoice_id)})\n    return invoice\n","python","",[198,228,229,237,243,249],{"__ignoreMap":226},[230,231,234],"span",{"class":232,"line":233},"line",1,[230,235,236],{},"@app.get(\"/api/invoices/{invoice_id}\")\n",[230,238,240],{"class":232,"line":239},2,[230,241,242],{},"async def get_invoice(invoice_id: str, user = Depends(get_current_user)):\n",[230,244,246],{"class":232,"line":245},3,[230,247,248],{},"    invoice = await db.invoices.find_one({\"_id\": ObjectId(invoice_id)})\n",[230,250,252],{"class":232,"line":251},4,[230,253,254],{},"    return invoice\n",[10,256,257,258,261],{},"That endpoint has authentication. ",[198,259,260],{},"Depends(get_current_user)"," confirms you're logged in, so it looks guarded, and in a code review it reads fine. It's still broken.",[10,263,264,265,269,270,274],{},"Nothing checks that the invoice belongs to ",[266,267,268],"em",{},"you",". Any logged-in user who changes the ID in the URL reads anyone's invoice. That's ",[23,271,273],{"href":272},"/blog/vulnerabilities/idor","IDOR",", and it's the most common finding in this whole category.",[217,276,278],{"label":277},"The fixed version",[221,279,281],{"className":223,"code":280,"language":225,"meta":226,"style":226},"@app.get(\"/api/invoices/{invoice_id}\")\nasync def get_invoice(invoice_id: str, user = Depends(get_current_user)):\n    invoice = await db.invoices.find_one({\n        \"_id\": ObjectId(invoice_id),\n        \"owner_id\": user.id,          # the part that was missing\n    })\n    if not invoice:\n        raise HTTPException(status_code=404)\n    return invoice\n",[198,282,283,287,291,296,301,307,313,319,325],{"__ignoreMap":226},[230,284,285],{"class":232,"line":233},[230,286,236],{},[230,288,289],{"class":232,"line":239},[230,290,242],{},[230,292,293],{"class":232,"line":245},[230,294,295],{},"    invoice = await db.invoices.find_one({\n",[230,297,298],{"class":232,"line":251},[230,299,300],{},"        \"_id\": ObjectId(invoice_id),\n",[230,302,304],{"class":232,"line":303},5,[230,305,306],{},"        \"owner_id\": user.id,          # the part that was missing\n",[230,308,310],{"class":232,"line":309},6,[230,311,312],{},"    })\n",[230,314,316],{"class":232,"line":315},7,[230,317,318],{},"    if not invoice:\n",[230,320,322],{"class":232,"line":321},8,[230,323,324],{},"        raise HTTPException(status_code=404)\n",[230,326,328],{"class":232,"line":327},9,[230,329,254],{},[10,331,332],{},"One line. On Supabase, an RLS policy would have caught the first version even with the line missing. On Emergent, nothing does.",[334,335,336],"tip-box",{},[10,337,338,341,342,345],{},[193,339,340],{},"Grep your repo for this in about two minutes."," Export to GitHub, then run ",[198,343,344],{},"grep -rn \"find_one\\|find(\" backend/"," and look at every result. For each one, ask a single question: does this filter mention the current user? If a query touches user-owned data and the filter has only an ID in it, you found one. Fix those before anything else on this page.",[10,347,348,349,353],{},"Authentication and authorization are different checkpoints, and conflating them is the failure mode here. We wrote up the two-checkpoint pattern in ",[23,350,352],{"href":351},"/blog/how-to/protect-routes","protecting your routes",", and it maps directly onto FastAPI dependencies.",[29,355,357],{"id":356},"nosql-operator-injection","NoSQL Operator Injection",[10,359,360],{},"This one is specific to MongoDB and catches people who think injection is a SQL-only problem.",[10,362,363,364,367],{},"MongoDB queries are documents, not strings. There's no query text to escape, which is why MongoDB is often described as immune to injection. That's true for the classic ",[198,365,366],{},"' OR 1=1--"," style attack and false in a more interesting way.",[10,369,370,371,27],{},"If an endpoint accepts a raw dictionary and drops it into a filter, the attacker isn't injecting syntax. They're injecting ",[266,372,373],{},"structure",[217,375,377],{"label":376},"Vulnerable: untyped body",[221,378,380],{"className":223,"code":379,"language":225,"meta":226,"style":226},"@app.post(\"/api/login\")\nasync def login(body: dict):                  # note: plain dict, no model\n    user = await db.users.find_one({\n        \"email\": body[\"email\"],\n        \"password\": body[\"password\"],\n    })\n    return {\"ok\": user is not None}\n",[198,381,382,387,392,397,402,407,411],{"__ignoreMap":226},[230,383,384],{"class":232,"line":233},[230,385,386],{},"@app.post(\"/api/login\")\n",[230,388,389],{"class":232,"line":239},[230,390,391],{},"async def login(body: dict):                  # note: plain dict, no model\n",[230,393,394],{"class":232,"line":245},[230,395,396],{},"    user = await db.users.find_one({\n",[230,398,399],{"class":232,"line":251},[230,400,401],{},"        \"email\": body[\"email\"],\n",[230,403,404],{"class":232,"line":303},[230,405,406],{},"        \"password\": body[\"password\"],\n",[230,408,409],{"class":232,"line":309},[230,410,312],{},[230,412,413],{"class":232,"line":315},[230,414,415],{},"    return {\"ok\": user is not None}\n",[10,417,418],{},"A normal request sends two strings. An attacker sends this instead:",[217,420,422],{"label":421},"The attack payload",[221,423,427],{"className":424,"code":425,"language":426,"meta":226,"style":226},"language-json shiki shiki-themes github-dark","{\n  \"email\": { \"$ne\": null },\n  \"password\": { \"$ne\": null }\n}\n","json",[198,428,429,435,456,472],{"__ignoreMap":226},[230,430,431],{"class":232,"line":233},[230,432,434],{"class":433},"s95oV","{\n",[230,436,437,441,444,447,450,453],{"class":232,"line":239},[230,438,440],{"class":439},"sDLfK","  \"email\"",[230,442,443],{"class":433},": { ",[230,445,446],{"class":439},"\"$ne\"",[230,448,449],{"class":433},": ",[230,451,452],{"class":439},"null",[230,454,455],{"class":433}," },\n",[230,457,458,461,463,465,467,469],{"class":232,"line":245},[230,459,460],{"class":439},"  \"password\"",[230,462,443],{"class":433},[230,464,446],{"class":439},[230,466,449],{"class":433},[230,468,452],{"class":439},[230,470,471],{"class":433}," }\n",[230,473,474],{"class":232,"line":251},[230,475,476],{"class":433},"}\n",[10,478,479,482],{},[198,480,481],{},"$ne"," means \"not equal.\" The filter now reads \"find a user whose email is not null and whose password is not null,\" which matches the first user in the collection. The attacker logged in without knowing a single credential.",[10,484,485],{},"The fix is a type declaration, and FastAPI does the work once you give it one:",[217,487,489],{"label":488},"Fixed: Pydantic model",[221,490,492],{"className":223,"code":491,"language":225,"meta":226,"style":226},"from pydantic import BaseModel, EmailStr\n\nclass LoginBody(BaseModel):\n    email: EmailStr\n    password: str\n\n@app.post(\"/api/login\")\nasync def login(body: LoginBody):             # FastAPI now rejects non-strings\n    ...\n",[198,493,494,499,505,510,515,520,524,528,533],{"__ignoreMap":226},[230,495,496],{"class":232,"line":233},[230,497,498],{},"from pydantic import BaseModel, EmailStr\n",[230,500,501],{"class":232,"line":239},[230,502,504],{"emptyLinePlaceholder":503},true,"\n",[230,506,507],{"class":232,"line":245},[230,508,509],{},"class LoginBody(BaseModel):\n",[230,511,512],{"class":232,"line":251},[230,513,514],{},"    email: EmailStr\n",[230,516,517],{"class":232,"line":303},[230,518,519],{},"    password: str\n",[230,521,522],{"class":232,"line":309},[230,523,504],{"emptyLinePlaceholder":503},[230,525,526],{"class":232,"line":315},[230,527,386],{},[230,529,530],{"class":232,"line":321},[230,531,532],{},"async def login(body: LoginBody):             # FastAPI now rejects non-strings\n",[230,534,535],{"class":232,"line":327},[230,536,537],{},"    ...\n",[10,539,540,541,544,545,548],{},"With ",[198,542,543],{},"email: EmailStr"," and ",[198,546,547],{},"password: str"," declared, FastAPI returns a 422 before your code runs. The dictionary never reaches MongoDB.",[550,551,552],"warning-box",{},[10,553,554,557,558,544,561,564],{},[193,555,556],{},"Check the routes that take a dict."," Search your backend for ",[198,559,560],{},": dict",[198,562,563],{},"Body(...)"," without a model attached. Login, search, and filter endpoints are where untyped bodies collect, and they're also the endpoints an attacker probes first. Every route should name a Pydantic model.",[29,566,568],{"id":567},"cors-and-what-our-scanner-keeps-finding","CORS, and What Our Scanner Keeps Finding",[10,570,571],{},"FastAPI's CORS middleware has a specific combination that shows up over and over in generated backends:",[217,573,575],{"label":574},"The combination to look for",[221,576,578],{"className":223,"code":577,"language":225,"meta":226,"style":226},"app.add_middleware(\n    CORSMiddleware,\n    allow_origins=[\"*\"],        # any site\n    allow_credentials=True,     # ...and send cookies\n    allow_methods=[\"*\"],\n    allow_headers=[\"*\"],\n)\n",[198,579,580,585,590,595,600,605,610],{"__ignoreMap":226},[230,581,582],{"class":232,"line":233},[230,583,584],{},"app.add_middleware(\n",[230,586,587],{"class":232,"line":239},[230,588,589],{},"    CORSMiddleware,\n",[230,591,592],{"class":232,"line":245},[230,593,594],{},"    allow_origins=[\"*\"],        # any site\n",[230,596,597],{"class":232,"line":251},[230,598,599],{},"    allow_credentials=True,     # ...and send cookies\n",[230,601,602],{"class":232,"line":303},[230,603,604],{},"    allow_methods=[\"*\"],\n",[230,606,607],{"class":232,"line":309},[230,608,609],{},"    allow_headers=[\"*\"],\n",[230,611,612],{"class":232,"line":315},[230,613,614],{},")\n",[10,616,617,618,621],{},"Each line looks like a reasonable \"make it work\" setting during development. Together, the first two are the problem: any website can make authenticated requests to your API using your logged-in user's cookies. This is the finding CheckYourVibe reports as ",[193,619,620],{},"CORS Allows Credentials from Any Origin",", and it's one of the highest-severity things the scanner surfaces on API-backed apps.",[10,623,624,625,628,629,632],{},"The browser will actually refuse the literal ",[198,626,627],{},"*"," with credentials enabled, which is why this often survives testing. What ships instead is middleware that reflects whatever ",[198,630,631],{},"Origin"," header it receives, and that behaves exactly like a wildcard while passing a casual check.",[10,634,635,636,639,640,644],{},"Set ",[198,637,638],{},"allow_origins"," to your real frontend domains. Full detail in ",[23,641,643],{"href":642},"/blog/how-to/setup-cors-properly","setting up CORS properly",", including why an allowlist beats reflection.",[646,647,648],"info-box",{},[10,649,650,653,654,657],{},[193,651,652],{},"CORS is not an API access control."," It constrains browsers, and nothing else. Anyone with ",[198,655,656],{},"curl"," ignores it completely. Fixing CORS is worth doing, but it does not substitute for the ownership checks above.",[29,659,661],{"id":660},"what-emergent-gets-right","What Emergent Gets Right",[10,663,664],{},"The criticism above is about a stack shape, not a vendor, and it would be unfair to stop there.",[10,666,667],{},"The code is genuinely yours. Emergent pushes a real repository with real commit history to your GitHub account, and you can clone it, run it locally, and host it somewhere else. That's not universal in this market, and it means a security review is even possible. Platforms that hide the backend cannot be audited by anyone.",[10,669,670,671,27],{},"Keeping MongoDB off the public internet is the right call. It removes the leaked-anon-key failure that has produced most of the public incidents in vibe coding, including the ",[23,672,674],{"href":673},"/blog/stories/lovable-app-exposed-18000-users","Lovable app that exposed 18,000 users",[10,676,677,678,682],{},"Secrets live server-side. Because FastAPI holds the connection string, your MongoDB credentials never enter a client bundle, so the ",[23,679,681],{"href":680},"/blog/vulnerabilities/exposed-api-keys","exposed API key"," problem that dominates browser-first builders mostly doesn't arise. Do still confirm nothing sensitive leaked into the frontend, since agents sometimes wire a third-party key into React by mistake.",[684,685,687],"lesson-box",{"title":686},"The trade Emergent makes",[10,688,689],{},"Browser-to-database platforms give you a dangerous default plus a strong backstop. Emergent gives you a safe default and no backstop. Which is better depends entirely on whether anyone reads the endpoints. If you audit your routes, Emergent's model is the stronger one. If you never look, both fail, just on different days.",[29,691,693],{"id":692},"your-emergent-security-checklist","Your Emergent Security Checklist",[695,696,697,702,706,710,714,718,722],"checklist-section",{},[698,699],"checklist-item",{"description":700,"label":701},"You cannot audit what you cannot see. Push to your repo and open the routes directory.","Export to GitHub and read the backend",[698,703],{"description":704,"label":705},"Search for find_one and find. Any query touching user data needs owner_id or equivalent in the filter, not just an ID.","Filter every user-owned query by the current user",[698,707],{"description":708,"label":709},"Search for ': dict' in route signatures. Untyped bodies allow NoSQL operator injection.","Give every endpoint a Pydantic model",[698,711],{"description":712,"label":713},"Replace allow_origins=['*'] with your actual frontend URLs. Never pair a wildcard or reflected origin with allow_credentials=True.","Pin CORS to your real domains",[698,715],{"description":716,"label":717},"Grep the frontend build for 'mongodb+srv'. It should return nothing.","Confirm the MONGO_URI is only in the backend",[698,719],{"description":720,"label":721},"If you pasted a key or connection string into the build conversation, treat it as logged and rotate it.","Rotate credentials shared through chat",[698,723],{"description":724,"label":725},"Endpoint review catches logic bugs. A scan catches headers, TLS, exposed files and source maps you would not think to check.","Scan the deployed URL",[727,728,729,736,742,752,770],"faq-section",{},[730,731,733],"faq-item",{"question":732},"Is Emergent safe to use in 2026?",[10,734,735],{},"Emergent is safe as a platform in the ways that matter most. It writes standard React, FastAPI and MongoDB code, pushes it to your own GitHub repository, and does not trap your app in a proprietary runtime. The risk is the code itself. Emergent's default stack has no database-level authorization layer, so every permission check lives in a FastAPI route handler the agent wrote. If one endpoint is missing a check, nothing behind it catches the mistake.",[730,737,739],{"question":738},"Does Emergent use MongoDB, and does that change my security work?",[10,740,741],{},"Yes, Emergent provisions a managed MongoDB instance with each deployed app, and it changes your security work significantly. MongoDB has no row-level security policies the way PostgreSQL does, so the Supabase advice written for Lovable or Bolt does not transfer. There is no second line of defense below your API, which makes reviewing each endpoint the whole job rather than a nice-to-have.",[730,743,745],{"question":744},"Can attackers reach my Emergent database directly?",[10,746,747,748,751],{},"Not the way they can with a Supabase anon key. The browser talks to your FastAPI backend, and only the backend holds the MongoDB connection string, so the database is not addressable from the internet. That's a genuine structural advantage. It also concentrates the risk: a leaked ",[198,749,750],{},"MONGO_URI",", or one over-permissive endpoint, gives up everything at once.",[730,753,755],{"question":754},"What is NoSQL operator injection and does it affect Emergent apps?",[10,756,757,758,761,762,765,766,769],{},"It affects any MongoDB app where untyped JSON reaches a query filter. If an endpoint accepts a raw dict and passes it to ",[198,759,760],{},"find_one",", an attacker can send ",[198,763,764],{},"{\"$ne\": null}"," in place of a string and match any record, which turns a login form into a free pass. Declaring a Pydantic model with ",[198,767,768],{},"str"," fields on every endpoint stops it, because FastAPI rejects the object before it reaches the database. Check your login and lookup routes first.",[730,771,773],{"question":772},"Is Emergent safer than Lovable or Base44?",[10,774,775],{},"They fail differently rather than one being clearly safer. Lovable and Base44 lean on PostgreSQL row-level security, which is a real backstop when configured and a well-documented disaster when it isn't. Emergent keeps the database off the internet entirely but gives you no backstop at all. Emergent's model is better if you audit your endpoints and worse if you don't.",[777,778,779,785,789],"related-articles",{},[780,781],"related-card",{"description":782,"href":783,"title":784},"The database Emergent provisions with every app, and what its access model does and does not cover.","/blog/is-safe/mongodb","Is MongoDB Safe?",[780,786],{"description":787,"href":351,"title":788},"Authentication and authorization are two checkpoints. Emergent apps need both in the FastAPI layer.","How to Protect Your Routes",[780,790],{"description":791,"href":792,"title":793},"The failure mode when an endpoint checks who you are but not what you own.","/blog/vulnerabilities/broken-access-control","Broken Access Control",[795,796,799,803],"cta-box",{"href":797,"label":798},"/","Start Free Scan",[29,800,802],{"id":801},"shipped-an-app-on-emergent","Shipped an app on Emergent?",[10,804,805],{},"Scan the deployed URL for CORS misconfiguration, exposed files, missing headers and leaked keys. No signup needed to see your first results.",[807,808,809],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}",{"title":226,"searchDepth":239,"depth":239,"links":811},[812,813,814,815,816,817,818,819],{"id":31,"depth":239,"text":32},{"id":90,"depth":239,"text":91},{"id":211,"depth":239,"text":212},{"id":356,"depth":239,"text":357},{"id":567,"depth":239,"text":568},{"id":660,"depth":239,"text":661},{"id":692,"depth":239,"text":693},{"id":801,"depth":239,"text":802},"is-safe","2026-08-04","Is Emergent safe in 2026? A security review of the React, FastAPI and managed MongoDB stack it generates, and why there is no database-level backstop behind your API.",false,"md",[826,828,830,832,834],{"question":732,"answer":827},"Emergent is safe as a platform in the ways that matter most: it writes standard React, FastAPI and MongoDB code, pushes it to your own GitHub repository, and does not hold your app in a proprietary runtime. The risk is the code itself. Emergent's default stack has no database-level authorization layer, so every permission check lives in the FastAPI route handlers the agent wrote. If one endpoint is missing a check, nothing behind it catches the mistake.",{"question":738,"answer":829},"Yes. Emergent provisions a managed MongoDB instance with each deployed app. It changes your security work significantly. MongoDB has no row-level security policies the way PostgreSQL does, so the Supabase advice you have read for Lovable or Bolt does not transfer. On Emergent there is no second line of defense below your API, which makes reviewing each endpoint the whole job rather than a nice-to-have.",{"question":744,"answer":831},"Not the way they can with a Supabase anon key. In Emergent's architecture the browser talks to your FastAPI backend, and only the backend holds the MongoDB connection string. That is a genuine structural advantage over browser-to-database platforms. It also means a leaked MONGO_URI, or one over-permissive endpoint, gives up everything at once.",{"question":754,"answer":833},"It affects any MongoDB app where untyped JSON reaches a query filter. If an endpoint accepts a raw dict and passes it to find_one, an attacker can send {\"$ne\": null} instead of a string and match any record. Declaring a Pydantic model with str fields on every endpoint stops it, because FastAPI rejects the object before it reaches the database. Check your login and lookup routes first.",{"question":772,"answer":835},"They fail differently rather than one being clearly safer. Lovable and Base44 lean on PostgreSQL row-level security, which is a real backstop when configured and a well-documented disaster when not. Emergent keeps the database off the internet entirely but gives you no backstop at all. Emergent's model is better if you audit your endpoints and worse if you do not.","amber",null,"is emergent safe, emergent ai security, emergent app builder security, emergent.sh review, emergent mongodb security, emergent vibe coding safe, emergent security risks",{},"Security review of Emergent, the AI app builder that hit a $1.5B valuation in July 2026. The MongoDB authorization gap every Emergent app inherits.","/blog/is-safe/emergent","11 min read","[object Object]","Article",{"title":5,"description":822},{"loc":841},"blog/is-safe/emergent",[],"summary_large_image","T1Z2s3vYQl4Y0kL4SMFIHHEYLr4fSpQMghAV3zIcPA0",1785862008453]