SCAN YOUR FIGMA MAKE APP FOR VULNERABILITIES

ENTER YOUR FIGMA MAKE APP URL

Enter your deployed app URL to check for security vulnerabilities.

Figma Make turns Figma frames into working React apps — the design-to-app pipeline optimized for visual fidelity, published in minutes. That is also the trap: the generated code is faithful to the design, and the design does not encode security. Auth screens become forms that post to a placeholder backend, “this field is required” becomes client-side-only validation, and every frame in the file can become a public route.

“It’s only a frontend from a design file” is exactly how these apps ship vulnerable. The Make output decides what reaches every visitor’s browser — including env-inlined API keys, Figma access tokens embedded to “fetch the latest design,” and route tables that expose unpublished frames. The backend that gets wired in later inherits forms with no server-side schema and pages whose only gate is a React conditional.

VibeEval scans the published app from outside — the URL, not the Figma file — and attacks it the way a stranger who found the link would.

Common vulnerabilities we find in Figma Make apps

The recurring shapes in Make-published apps, and how each one gets exploited.

The placeholder backend in production

Make ships with a built-in mock backend so the app works with zero setup — no auth, no per-user scoping, no rate limits. Publish without replacing it and every user shares one state: one user’s “private notes” are readable by every other visitor. The exploit is a second browser tab. Fix direction: replace the mock store with a real backend (your API, Supabase, Firebase) that enforces auth and per-user scoping before launch.

Figma tokens and secrets in the bundle

Generated code occasionally embeds a Figma personal access token so the app can pull the latest design — and a token with files:read scope reads every Figma file the issuing account can reach, unreleased product work included. The same inlining applies to anything referenced through VITE_* or NEXT_PUBLIC_*: both compile the literal value into the client bundle. Checking takes one command against your own deploy:

curl -s https://your-app.example.com/assets/index.js \
  | grep -oE 'figd_[A-Za-z0-9_-]{20,}|sk_live_[A-Za-z0-9]+|sk-[A-Za-z0-9]{20,}|AIza[A-Za-z0-9_-]{35}'

Any hit is already public — rotate it before you refactor, because the bundle has been served to every visitor and every crawler since publish. Then move the token-bearing call behind a server route so the browser receives data instead of credentials. The Token Leak Checker runs the same check across every script the page loads.

Routes generated from unpublished frames

Make can generate a route for every frame in the source file — drafts, internal pages, /pricing-v2-draft. The route table ships in the JS bundle, so an attacker does not even need to guess; they read it. Publishing the app effectively makes every included frame world-readable, regardless of design-time access controls. Fix direction: audit the route table before publish, delete unintended routes, and re-check after every regeneration.

Client-side-only auth gating

The design has a login screen, so the export has a login screen — but the “logged in” state is React state, and the route guard is a component conditional. Drop the guard in DevTools, or skip the UI and call the backend endpoint directly, and the protected page’s data answers without a session. Fix direction: wire a real auth provider (Clerk, Auth0, Supabase Auth) and enforce authorization in the API — every backend endpoint returns 401 without a valid session, with the frontend guard kept for redirects only.

Forms without server-side validation (mass assignment)

Make forms validate in the component and post the whole form state to whatever backend you connect. Nobody has to use your form. A handler that spreads the request body into a database update accepts fields the UI never rendered:

curl -X POST https://your-app.example.com/api/profile \
  -H 'Content-Type: application/json' \
  -d '{"name":"Alex","isAdmin":true,"plan":"enterprise"}'

If the response comes back with isAdmin set, that is mass assignment, and the fix is an allowlist schema on the server that rejects unknown keys outright:

const UpdateProfile = z.object({ name: z.string().min(1).max(80) }).strict();

const parsed = UpdateProfile.safeParse(req.body);
if (!parsed.success) return res.status(400).json({ error: "Invalid input" });
await db.profiles.update({ where: { id: session.userId }, data: parsed.data });

.strict() is doing the security work — without it, extra fields pass validation and reach the database. Note the update is keyed to session.userId, not to an ID from the body; taking the row ID from client input is how the same endpoint becomes a cross-user write.

XSS through direct data binding

Make’s data binding optimizes for visual fidelity, so rich-text fields — bios, comments, CMS bodies — tend to bind straight into the DOM:

// Generated: renders whatever the record contains
<div dangerouslySetInnerHTML={{ __html: post.body }} />

// Fixed: sanitize before it reaches the DOM
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(post.body) }} />

One stored payload in a bound field then executes in every viewer’s session — the same surface as LLM-rendered HTML and Markdown. Plain text is better still where the design allows it: {post.body} escapes automatically. Separately, check what the bound object contains — binding a whole user record to a profile card ships email, stripe_customer_id, and role to the browser even when the design only draws a name, so filter to user-safe fields server-side.

Check it yourself in five minutes

Three passes over your own published URL find most of what the export leaves open.

Read your route table. Make compiles routes into the bundle, so attackers do not guess paths — they read them. Extract the candidates and open anything you did not intend to publish:

curl -s https://your-app.example.com/assets/index.js \
  | grep -oE 'path:"/[a-zA-Z0-9/_-]*"' | sort -u

Test a protected page with no session. Open a protected route in a private window. If the page briefly renders before redirecting, the guard is cosmetic — and the API call behind it likely answered anyway. Watch the network tab: a 200 with real data on a logged-out request is the finding, not the redirect.

Replay a form without the form. Copy any form submission out of the network tab as cURL, then resend it with fields the UI never showed ("role":"admin", another user’s record ID). Anything other than a 4xx means the backend trusts the client.

What this misses is the cross-user case — whether signed-in user B can read user A’s records across every endpoint the app exposes. That takes two accounts and full endpoint coverage, which is the scan’s job.

How VibeEval works with Figma Make

  1. Enter your published URL. Point VibeEval at the Make publish or wherever you deployed the export — no Figma access, no code upload, exactly what an attacker sees.
  2. The agent attacks the app in a real browser. It extracts the route table and probes unintended routes, tests protected pages and their backend endpoints with no session and with a second account, replays forms with mass-assignment payloads, and scans the bundle for Figma tokens, key prefixes, and inlined env vars, plus security headers.
  3. Read the report, fix with prompts. Findings arrive ranked by severity with the exact route, form, or bound field affected — each with a paste-ready fix prompt you can feed back into Make or hand to whoever owns the backend.

Manual testing vs VibeEval

Manual review VibeEval
Time per full pass Hours: extract the route table, trace every form to its backend, grep the bundle Minutes, run against the published URL
Unintended-route discovery Reading minified route configs by hand Route table extracted and probed on every scan
Cross-user coverage Two accounts replayed manually per endpoint Second-account replay attempted on every discovered endpoint
After each regeneration Full re-check — Make rewrites code on every regeneration, and fixed items regress Re-scan on demand; regressions surface as new findings
Design-to-code judgment Where humans win: which frames should be public, which fields are user-safe Out of scope; the scanner covers the mechanical surface
Cost Engineer-hours per publish Flat, repeatable after every publish

The honest framing: a human still decides what the app should expose. The scanner wins on repeatability — Make regenerates code on every publish, and each publish deserves the same pass without the same hours.

Frequently asked questions

Can design-to-code tools create secure apps?

They can, but security is not part of the conversion — the Figma file encodes layout and content, not auth policy or validation rules. The export is a UI implementation that needs a security-aware backend wired in: real auth, server-side validation, scoped data access. Scanning the published result tells you which of those layers is actually missing.

What security is typically missing from Figma Make apps?

The consistent gaps: the placeholder backend still wired up, auth UI without auth logic, validation that exists only in the React component, routes generated from frames that were never meant to be public, and secrets inlined into the bundle. Each is invisible in the editor and obvious in a black-box scan.

My Make app is just a frontend — do I still need a scan?

Yes, because the frontend is what ships to the browser. The bundle can carry Figma tokens and API keys, the route table can expose draft frames, and bound fields can carry XSS. And the moment a real backend is connected, every form and guard the export generated becomes the interface attackers use against it.

Should I scan before or after wiring up the real backend?

Both. Scan the initial publish to catch bundle secrets, exposed routes, and the placeholder backend; scan again after connecting real auth and data to verify the endpoints actually enforce what the UI implies. Then re-scan after regenerations — Make rewrites code each time, and a passing item can fail next publish.

Does VibeEval support all Figma Make export formats?

Yes. The scan is black-box against the deployed URL, so it works whether you use Make’s own publishing or export the code and host it yourself — the framework and hosting don’t matter, only what the app serves.

Test your Figma Make app before launch

The publish shows you a pixel-faithful app; it cannot show you which frames, keys, and endpoints just went public with it. Run a scan against the published URL, fix the findings, and ship the version that survives someone reading your bundle.

SCAN YOUR DEPLOYED APP

Paste your live URL. We probe exposed keys, missing auth, open databases, and broken access control — results in under 60 seconds. 14-day trial, no card.

14-day free trial · No credit card · Cancel anytime

START FREE SCAN