Skip to main content
Sign in to Arbor CloudSign in

SecurityUpdated October 7, 2026

Where Arbor runs. What it can reach.

The website, the local engine and Arbor Cloud: what each can reach, the limits we set, and the gaps we know about.

Found a problem? Email a security report to support@getarbor.dev.

Three places Arbor runs

What each one can reach and what it keeps. Each row links to the full section.

Where Arbor runs, what it can reach and what it keeps
WhereStatusWhat it can reachWhat it keeps
The websiteLive at getarbor.devYour browser, and the waitlist database when you join. AWS serves every page.Waitlist emails and signup times, plus the referring page and utm_source tag when present. Public pages set no cookies and no visitor ID; signing in sets an encrypted session cookie.
The enginev3.0.3, on your machineYour files and your local git. It makes no network requests of its own..arbor/ in your project: the graph and, if you use receipts, your requests to Claude Code. Receipt snapshots go into your repository’s .git.
Arbor CloudOpen since October 7, 2026One repository at a time, read-only, through Arbor’s GitHub App.Reports with file paths, symbol names and counts. No source code. Payment records from Razorpay, never card numbers.
Part 1

Running today

The Cloud boundary, the public website and the engine on your machine.

Only the workbench is open

In shortTwo independent layers, the API and the website, serve the Cloud workbench and refuse every other Cloud route. Neither has a switch a visitor can flip.

Arbor Cloud reopened on October 7, 2026 as a new service. The first Cloud’s routes stay closed. Neither layer has a cookie, query-parameter or user-role switch that opens a closed route.

The API checks one setting before it loads credentials, a database, telemetry or workers. The workbench value mounts only health checks, the GitHub sign-in exchange, the account and workspace routes this website’s server calls, the GitHub App webhook and the Razorpay webhook. Every other path answers 404. A typo or different casing leaves it serving only /health.

The website serves a fixed list of public pages and files, plus sign-in, the workbench and the routes the workbench calls. The first Cloud’s admin and sharing pages and its API routes stay closed. A path that isn’t on the list returns 404.

What routes answer today
RequestAnswerLayer
GET /dashboard, signed out307 → /auth/signinWebsite
GET /api/repos404 ROUTE_CLOSEDWebsite. The first Cloud’s API paths.
GET /health200 · mode: workbench_publicAPI
Any other API path404 ROUTE_CLOSEDAPI

CI checks both layers. It builds the website closed and open and requests the routes that must stay closed, boots the API without credentials, and boots the production container.

About Arbor Cloud

The public website

In shortStrict headers, nothing loaded from other hosts, and a waitlist rate limit that keeps only a salted hash of your IP address, in memory.

Every page carries a Content Security Policy that blocks framing, plugins and form posts to other sites. Responses also send Strict-Transport-Security for two years, X-Frame-Options: DENY, nosniff, and a Permissions-Policy that turns off the camera, microphone and geolocation. The two public API routes get default-src 'none' and are sent with no-store.

The policy still allows inline scripts, which the theme loader and the framework’s own page scripts use. Public pages load nothing from other hosts: fonts and images come from this site.

Each server instance allows 10 waitlist attempts a minute per client address. That stops bursts, not attempts spread across many instances or addresses. The limiter keeps only an HMAC-SHA256 of your IP address, keyed with a random salt that each instance creates in memory and never stores. It writes nothing to the database. Request bodies over 4,000 bytes are refused, and a hidden field turns away simple bots. The privacy notice lists what a sign-up stores.

The sample explorer uses an authored example bundled with the site. It does not read your files or connect to GitHub.

The engine runs on your machine

In shortNo telemetry, no update check and no network requests of its own. Data leaves your machine only through steps you take.

The Arbor CLI, MCP bridge and local servers include no HTTP client and make no network requests of their own: no telemetry, crash reports or update checks. Indexing, queries and receipts run locally. The engine runs git only for local commands such as diff, show and merge-base. It never runs fetch, pull or push.

Installing contacts the channel you choose: GitHub Releases, npm or crates.io. The npm package downloads its binary from GitHub Releases. Your MCP client receives the graph context its tools return and may send it to its model provider. The engine’s optional GitHub Action posts its report as a pull-request comment unless you set comment-on-pr: false.

.arbor/ holds the graph, with symbol names, file paths, signatures and docstrings, and, if you use receipts, the text of your requests. v3.0.3 does not add it to .gitignore, so add it yourself before you commit. The quickstart covers this.

What MCP clients receive

Local ports

In shortThe bridge listens only on 127.0.0.1. arbor serve --headless is the exception: it listens on every network interface, with no authentication.

arbor bridge speaks MCP over stdio, and your MCP client starts it. It also opens local ports, and so do two other commands:

Ports the engine opens, by command. 3333 and 7432 are defaults.
PortOpened byServesListens on
7433arbor bridge, arbor vizWebSocket graph queries127.0.0.1
8081arbor bridge, arbor vizWebSocket graph updates for the visualizer127.0.0.1
3333arbor bridge --httpMCP over HTTP127.0.0.1
7432arbor serveGraph queries127.0.0.1
7432arbor serve --headlessGraph queriesEvery network interface, with no authentication

The HTTP transport accepts only application/json and sends no CORS headers. Bodies are capped at 4 MiB, headers must arrive within 10 seconds and the body within 30, and it serves at most 64 connections at once. --port changes its port.

Use arbor serve --headless only on a network you trust: anyone who can reach its port can query the graph.

v3.0.3 release notes

Dependencies and releases

In shortCI fails on known advisories and pins every GitHub Action to a commit. v3.0.3 ships without a checksums file or an attestation; the release workflow on main now adds both.

CI for the website and API runs on every pull request to master. It fails on any Rust vulnerability advisory that cargo audit finds in the API, with one documented exception in an optional MySQL driver the API never compiles, and on high or critical npm advisories in the website. It also produces a CycloneDX bill of materials for both, installs from lockfiles, and scans the repository and its history for live-looking credentials. Every GitHub Action in that CI is pinned to a full commit SHA.

The API image runs as an unprivileged user (UID 10001) that cannot modify its own binaries. CI builds the image as deployed, boots it with every Linux capability dropped, and checks the user, the closed boundary and a clean shutdown. An API release must name a successful CI run for the exact commit, and we then check that /health reports that commit.

The engine’s CI runs cargo-deny on pull requests. License and dependency-source checks fail the run. The advisory check reports without failing it until the open advisories are fixed.

v3.0.3 ships without a SHA256SUMS file or a provenance attestation, and the install scripts and npm wrapper don’t verify checksums. GitHub publishes a SHA-256 digest for each v3.0.3 asset, and the Scoop manifest pins the Windows archive’s digest. The engine’s release workflow on main now publishes SHA256SUMS and a signed provenance attestation for each archive, but no published release includes them yet.

v3.0.3 release assets
Part 2

Arbor Cloud

How the account-based Cloud handles access, tokens and analysis. Pull requests from forks and installations managed by an organization have had less testing than personal repositories; tell us if something looks wrong. The privacy notice and terms cover payments.

Access and tokens

In shortRead-only tokens for one repository at a time, rechecked with GitHub before every run and every report read. Repository tokens never reach the database.

Arbor reads repositories through its GitHub App. GitHub shows the App’s permissions when you install it. Each time Arbor needs a repository, it requests a token for that one repository, with read-only access to contents, metadata and pull requests. It rejects a token with any other permission or repository, or with 15 minutes or less left. Before a run, before a report is saved and on every report read, it asks GitHub whether you can still read that repository.

These repository tokens stay in memory and are never stored in the database. Git receives the token through an askpass helper and an environment variable, never in the clone URL, git config or command arguments. When you sign in, the token GitHub issues for your account is kept in your session cookie, which Auth.js encrypts and which expires 30 days after you last use Cloud. The API uses it to read your GitHub profile and doesn’t store it.

API logs pass through a writer that redacts known token formats, bearer values, private keys, passwords in URLs and secret query parameters. Error reports sent to Sentry are scrubbed the same way and drop request bodies, cookies, authorization headers, and stack-frame source and variables.

Requests from your account reach the API only through this website’s server, which proves itself with a shared secret of at least 32 characters, compared in constant time. Your GitHub identity comes from the server session, never from the request body, and a change sent from another site’s page is refused. Each API instance limits how many requests each signed-in user or client address can make a minute. GitHub webhooks need a valid HMAC-SHA256 signature, and a repeated delivery is ignored. A webhook only updates installation state. An analysis starts only from a signed-in request, never from a pull-request event.

The analysis worker

In shortA shallow checkout with no hooks, scripts or installs, analyzed in a separate process with limits on time, CPU, memory and open files. Resource limits, not a sandbox.

Each run checks out the exact pull-request head commit from github.com with a shallow, blob-filtered clone. Git hooks and submodules are off, and no build script or package install runs. Oversized checkouts are refused. Within the limits, source files beyond the number the worker analyzes, or larger than it parses, are skipped, and the report says its graph is partial.

To check dependencies, the run sends the names and versions of the crates.io and npm packages listed in Cargo.lock, package-lock.json and npm-shrinkwrap.json to the OSV vulnerability database at api.osv.dev. It skips packages the lockfile records as coming from git, a local path or another registry, and sends no source code. An npm entry that doesn’t record its source is sent, so a private package’s name can reach OSV.

Analysis runs in a separate analysis-worker process in its own Linux process group, with a cleared environment and no system or global git config. It has caps on wall time, CPU time, memory and open files, writes no core dumps and cannot gain new privileges. Its input and its report are size-limited. The API reads only a bounded amount of the worker’s error output and discards it, because engine diagnostics can include repository contents.

Reports keep file paths, symbol and branch names, commit IDs, dependency versions and advisories, the relationships between them, and risk labels. They don’t keep source text or patches.

These are resource limits, not a sandbox for hostile code. Today the worker runs inside the API container, not on separate machines. Each checkout sits in its own temporary directory, removed when the run ends. If the API process itself is killed, leftovers older than 20 minutes are deleted before the next run.

Part 3

Claims and reports

What we don’t claim, and how to tell us about a problem.

What we don’t claim

We make no SOC 2, ISO 27001, uptime SLA or independent audit claims. CI and dependency alerts are review inputs, not proof that Arbor has no vulnerabilities.

Arbor’s analysis describes static relationships and their gaps. It never proves a change is safe.

Report a vulnerability

In shortEmail support@getarbor.dev with “Security report” in the subject. We coordinate disclosure with you; there is no paid bounty or guaranteed response time.

Include the affected URL, or the engine version and install channel, what you expected, what happened, a minimal reproduction and the impact.

A closed route that answers, a response that exposes data, or a build that bypasses the Cloud boundary is a security issue, even where old application code still exists.

Test locally or in an environment we have explicitly authorized. Please don’t submit test sign-ups to the live waitlist, send write requests to production, scan third-party infrastructure or try to reach other people’s data. Leave out access tokens, personal data and other secrets, and keep exploitable details out of public issues while we investigate.

We coordinate reproduction and disclosure with you in the reporting conversation. We don’t offer a paid bug bounty or a guaranteed response time.

Email a security report