Ctrl K
ComunidadGuías…

SECURITY.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Security

DomBot holds your registrar API keys, which can read and change your domains. So
the design goal isn't to ask you to trust us — it's to make the important claims
**verifiable by a skeptic who doesn't trust us at all.** This document states
what DomBot does with your credentials and, for each claim, how you can confirm
it yourself.

## The trust model, in one line

DomBot is **local-first with no backend of its own.** Your credentials are
stored encrypted on your machine and are sent to exactly one place: the API of
the registrar they belong to. There is no DomBot server for them to be uploaded
to — so "the app phones home with my keys" isn't something you have to take our
word on; it's structurally absent, and you can watch the network to prove it.

## What DomBot does with your credentials

- **Storage.** Registrar and marketplace API keys entered in **Settings →
  Registrars** and **Settings → Markets** are
  encrypted with your operating system's credential store — Keychain on macOS,
  DPAPI on Windows, the system keyring (libsecret/kwallet) on Linux — via
  Electron [`safeStorage`](https://www.electronjs.org/docs/latest/api/safe-storage).
  The encrypted blob lives in a `0600` (owner-only) file in the app's user-data
  directory. See [`src/core/services/credentials.ts`](src/core/services/credentials.ts).
  If the OS has no encryption available, DomBot **refuses to save** rather than
  writing plaintext keys to disk (a plaintext fallback exists only behind an
  explicit `DOMBOT_ALLOW_PLAINTEXT_CREDENTIALS=1` opt-in for headless setups).
- **Use.** Credentials are read only to make requests **directly from your
  machine to that registrar's or marketplace's own API.** The registrar HTTP
  calls live in
  [`@aoxborrow/registrar-client`](https://github.com/aoxborrow/registrar-client),
  a separate open-source package; the marketplace clients are in
  [`src/core/markets/`](src/core/markets/). Auth codes fetched for a market
  sale go straight to that market and are never stored.
- **No telemetry, analytics, or crash reporting.** The app contains no Sentry,
  no analytics SDK, no usage pings — nothing that could carry a key off-device.
- **No auto-update phone-home.** Updates are downloaded manually from GitHub
  Releases; the app doesn't call an update server.

## The local MCP server

DomBot runs an MCP server so AI agents can manage your portfolio. It is bound to
**`127.0.0.1` only** and never exposed off the machine, and pairing a client
requires a one-time in-app **Approve/Deny** prompt with a matching code. See
[`src/electron/mcp/server.ts`](src/electron/mcp/server.ts) and the README's
[Embedded MCP server](README.md#embedded-mcp-server) section.

## Verify it yourself

You don't have to believe any of the above. Here's how to check.

### 1. Watch the network

Run DomBot behind an inspecting proxy and use it normally — add a registrar,
sync your portfolio, browse. You'll see connections **only to your configured
registrars' own API hosts** (and, on first agent connect, loopback traffic for
MCP). No DomBot-operated host appears, because there isn't one.

- **macOS:** [Little Snitch](https://www.obdev.at/products/littlesnitch/) or
  [Charles](https://www.charlesproxy.com/) / [mitmproxy](https://mitmproxy.org/).
- **Windows/Linux:** [mitmproxy](https://mitmproxy.org/) or
  [Wireshark](https://www.wireshark.org/) (hostnames are visible via SNI even
  without TLS interception).

### 2. Read the source

The whole app is [AGPL-3.0](LICENSE) and open. The three things worth reading:

- Credential storage — [`src/core/services/credentials.ts`](src/core/services/credentials.ts)
- Where registrar credentials are resolved (GUI store only, no env fallback) —
  [`src/core/services/registrars.ts`](src/core/services/registrars.ts) (`resolveField`)
- The actual registrar HTTP calls —
  [`@aoxborrow/registrar-client`](https://github.com/aoxborrow/registrar-client)

### 3. Confirm the binary matches the source

Every published release is **built in public CI** (GitHub Actions), not on a
maintainer's laptop, and carries a **build-provenance attestation** that
cryptographically ties the downloaded artifact to the exact commit and workflow
that produced it. Verify a download before running it:

```bash
gh attestation verify <path-to-download> --repo aoxborrow/dombot
```

A passing check means the binary you have was built by DomBot's release workflow
from this repository's source — so the source you audited is the app you're
running, and there's no room to slip in a different, key-stealing build.

## Application hardening

For defense-in-depth against a compromised dependency (the more realistic threat
than the author, once the above is verifiable):

- Renderer runs with `contextIsolation: true`, `nodeIntegration: false`, and
  `sandbox: true`; the UI reaches the main process only through a typed preload
  bridge. ([`src/electron/index.ts`](src/electron/index.ts))
- A strict **Content-Security-Policy** keeps the renderer same-origin — no
  remote scripts, styles, images, or network connections can load.
- The renderer can't navigate away from its own content, and external links open
  in your real browser rather than an in-app window.
- Electron **Fuses** disable `RunAsNode`, Node CLI/inspect args, and the
  `NODE_OPTIONS` env var, and enforce ASAR integrity. ([`forge.config.ts`](forge.config.ts))
- macOS releases are **signed and notarized** by Apple.

## Reporting a vulnerability

Please report security issues privately rather than opening a public issue. Use
GitHub's [private vulnerability reporting](https://github.com/aoxborrow/dombot/security/advisories/new)
for this repository, or email **aaron@oxborrow.com**. We'll acknowledge receipt
and keep you updated on a fix.