Skip to main content
SECURITY & TELEMETRY

Hand this link to your security team as-is

Adoption reviews stall in predictable places. Does code leave the machine, are prompts stored, can it be turned off, and what changes when it is. Those answers are below, and where we cannot give you proof we say so instead of rounding it up.

What can be verified

The orchestration engine is closed, so "read the code" is not an answer we can offer. What we can offer is the full list of outbound hosts so a network monitor is enough to check us, and every asset the agents consume published as a plain file. No third party has audited any of this.

SCOPE

What leaves the machine and what does not

While it is running, the app sends a batched event stream to our own Google Cloud project (BigQuery) roughly every 10 seconds. Here is what is in that batch and what is not.

never sent

Source code, repositories, diffs, file paths

Not on any default path. The agent CLI reads and writes them on local disk, and Marblo only spawns that CLI as a subprocess on your machine. Home directory paths that could otherwise leak through logs (/Users/*, /home/*, C:\Users\*) are replaced with <USER_HOME> by the scrubber.

never sent

Prompts, model responses, terminal output

Any field named prompt, initialPrompt, message, userInput, content, or raw_input is dropped entirely before the queue — not masked. Partial scrubbing of natural language is unreliable, so the field never ships at all. Ticket titles, descriptions, and chat messages are also absent from the event stream; read that against the sixth item below, which is a different category.

never sent

API keys, credentials, personal identifiers

Keys shaped like sk-ant-*, sk-*, or AIza*, and any field whose name reads as a secret (*_KEY, *_TOKEN, *_SECRET, ANTHROPIC_*, OPENAI_*) become <REDACTED>. Email addresses become <EMAIL> and phone numbers <PHONE>. Marblo does not proxy your model traffic and does not hold your CLI logins.

on by default

De-identified operational events

Event names at lifecycle points (agent:spawned, task:completed and similar), model id, agent role, ticket status transitions, duration in ms, input and output token counts, estimated cost, process exit code, app version, platform, and an anonymous install id. Failure events carry an error category (cli_auth, runtime_crash, and so on) and a short scrubbed message. The purpose is operational quality: which harness and model combinations crash, where onboarding stalls, whether a release regressed.

opt-in

Crash reports

Ships off. Switched on, crash stack traces, PII-masked error messages, and your OS and app version go to Sentry (US-hosted, 90-day retention). It is the only third party the app can send to, and turning it on asks for cross-border transfer consent separately. The same scrubber runs on this path. The app sends nothing to GA4, Mixpanel, or any other analytics vendor — the marblo.app website uses GA4 under its own cookie consent, but that is the website, not the app.

product data

What syncs to your account

Ticket titles and descriptions, activity logs, agent and board state, chat messages, and cost roll-ups sync to Firestore under your account, because a live board a team watches together has to. This is not de-identified and it is not governed by the analytics toggle — treat it as the same category as your data in any hosted issue tracker. If a ticket description should stay private, do not put a secret in it.

SETTINGS → PRIVACY

Three switches, all under Settings → Privacy

The defaults are stated as they are. Being one click away does not turn a default-on collector into an opt-in one.

First-party analytics

on by default

Governs the de-identified operational events described above. Turning it off takes effect immediately and persists across restarts.

Crash reports

off by default

Sends to Sentry. Turning it on asks for cross-border transfer consent separately, and the SDK's user object is cleared before send.

Training-data contribution

off by default

Switched on, it stores the raw prompt and response text of your own agent turns so we can train our own models on it. It is raw text — it can contain your code and it can contain PII — which is precisely why it is a separate, explicit, off-by-default switch rather than a line item in a bundled consent dialog. It writes to a different BigQuery dataset from the de-identified events, so access is separable at the IAM level.

The one thing you lose by turning it off

The first-party analytics switch also governs cost roll-up writes. With it off, the Usage tab stops accruing new spend history. Everything else in the app behaves identically.

SUPPLY CHAIN

Is what the store installs safe

The store installs content that runs on a user's machine, so the registry is treated as a supply-chain surface.

External items are pinned
An external item must declare source.ref as a tag or commit SHA. Moving branches are not allowed, and the manifest schema enforces the shape of that pin.
Nothing is silently vendored
Third-party code is not copied into the repo; it is fetched from its upstream at the pinned ref, so license and ownership stay with the original author.
Permissions must be declared
Every executable item type (skill, agent, workflow, mcp-server, harness) is required by the schema to declare the capabilities it requests. An empty list is a valid, meaningful answer; omission is not allowed, so a silent item cannot render as a harmless one.
Community items are never one-click
A community item with an install contract installs only after the user acknowledges an "unreviewed content" warning, and that acknowledgement is enforced in the main process rather than the UI. One-click means "we reviewed it." Consent-gated means "we pinned and verified it, but you are trusting the author."

What is not true yet

Leave this list out and the items above stop being believable too. It is carried over from the repository's own SECURITY.md.

  • Permissions are disclosure, not enforcement. Marblo spawns CLI subprocesses with your own credentials. It can show you what an item says it needs; it cannot restrict what that item does once installed, and it does not claim to.
  • Pinning buys reproducibility, not freshness. Freezing a dependency at one commit means upstream fixes do not reach users until the registry moves the pin. The job that watches upstreams for new releases, advisories, deletions, archival, license changes, and force-moved tags does not run yet — until it does, treat pins as frozen, because they are.
  • App-side enforcement of status: revoked has not shipped. The field and the advisory file exist so the vocabulary is in place. CI validation is also intentionally narrow: schema, id, required permissions, license, immutable source pin, and best-effort repository reachability. Verifying an upstream's license text and scanning an external payload for secrets remain maintainer-review responsibilities.
FOR SECURITY REVIEW

What security reviews actually ask

The answers keep the parts that do not flatter us. Those questions come up in review anyway, and writing them down first saves everyone a round trip.

Does Marblo proxy our model traffic?
No. Marblo spawns the Claude, Codex, and Grok CLIs as subprocesses, and each CLI talks to its own vendor directly. The credentials are yours and AI usage is billed to your own accounts. The honest addendum: that traffic is governed by each vendor's own terms and data policy. Reviewing Marblo does not substitute for reviewing the enterprise terms of the model vendors you connect.
What outbound hosts does a default install contact?
Google/Firebase (authentication, Firestore, and the cloudfunctions.net callables that receive the event, heartbeat, cost, and outcome batches), the GitHub release feed for updates, and github.com plus raw.githubusercontent.com when you install something from the store. Point Little Snitch, LuLu, Charles, or any proxy at it and check for yourself. A Sentry ingest host appearing without you having opted in would be a bug — please report it. No other analytics vendor should ever appear.
Do you train models on our code?
Not from any default path. Collection happens only for accounts that switched training-data contribution on, and only after the server confirms eligibility. The design is fail-closed: unknown state — not yet fetched, fetch failed, signed out — means do not capture, and the server re-checks consent on every insert. Today the server accepts it from exactly one account, the operator's own; anyone else can switch the toggle on and nothing is collected, and the app says so in the status line under the switch. What is collected is never sent to Anthropic, OpenAI, xAI, or any other model vendor.
Are the events anonymous?
De-identified, not anonymous. The client sends no account identifier and the row key is the anonymous install id, but a server-side function attaches your account id to the stored row's metadata so repeat installs by one person can be de-duplicated. So the stream is de-identified in transit and in its row key, and re-linkable by us inside our own warehouse. We are not going to call that anonymous.
Can collected data be deleted?
There is no self-serve delete control in the app. Requests go to team@marblo.app and are handled within 30 days. For Korean users, consent is changeable at any time (PIPA Art. 22) and declining changes nothing about how the product works (PIPA Art. 15(3)). Nobody outside the company has audited any of this — what we offer instead is the outbound host list above and the fact that you can flip the switch off and watch the 10-second batches stop.

If your review needs material we have not published here, we will put it together. On-prem deployment, SAML, and audit logs are answered through the same channel.

Marblo Security & Data Transmission | What Leaves Your Machine and What Does Not | Hypemarc