Last updated: November 4, 2026
Myla Security examines the systems you connect — a GitHub organisation, a Supabase organisation, a Google Workspace domain, and a domain name — for exposed secrets, vulnerable dependencies and risky configuration, and helps you fix them. It can also watch what your AI coding agents do. This page describes what we read, what we store, what we deliberately do not store, and who else sees any of it. We do not sell your data, and we do not use it to train models.
The claims below are meant to be checkable against our source code. Where a limit is enforced by a test rather than only by intention, we say so.
GitHub. Through a GitHub App installation you authorise, we read repository contents and metadata: file paths, commits and their authors, package manifests and lockfiles, GitHub Actions workflow files, outside collaborators, webhooks, Dependabot and secret-scanning alerts, and organisation settings such as two-factor enforcement. Reading file contents is unavoidable for this — a scanner cannot find a secret committed in a file without reading the file. The token the scanner uses is minted per scan and downscoped: every permission the installation granted is re-requested as read, so the scanning token cannot write even if the App were later granted a write permission.
Supabase. Five read-only scopes you authorise — database:read, auth:read, rest:read, storage:read, projects:read. We call configuration endpoints only: the security advisor report, storage buckets’ public/private flags, and the data API’s exposed schemas. None of these reads a row of your table data, and we never request a scope that would reveal your API keys. Consent is organisation-wide: every project in the organisation, including ones you add later.
Google Workspace. Exactly two read-only scopes, and the omissions are the point: admin.directory.user.readonly and admin.reports.audit.readonly. These let us see which third-party apps have been granted access to your workspace and which scopes they hold, and which administrators lack two-step verification. We hold no Gmail scope and no Drive scope, so we cannot read a message, a subject line, an attachment or a file — not as a policy, but because the permission was never requested. We call the Admin SDK over REST only.
A domain name. No sign-in, no credential, nothing to install. We read what the public internet already publishes about the name: DNS records (mail servers, SPF, DMARC), the certificate presented on a TLS handshake, and the headers your site returns on an HTTPS request. We do not verify that you own the domain, because everything we read is public either way.
Across all four, we read; we do not change anything — with one deliberate exception, described next.
“Fix it” can open an issue or a pull request on your GitHub repository. When you approve a specific change, we mint a separate short-lived token with exactly the permissions that action needs, restricted to the named repositories, and use it for that action only. It is never the scanning token, which cannot write at all. Nothing is opened, merged or pushed without you approving that exact change first, and we never push to a default branch.
We store the findings a scan produces, not the material they came from. A finding records things like the repository and file path, the kind of problem, a severity, and the advisory IDs for a vulnerable package.
We do not store your repository’s contents. Files are read in memory during a scan and discarded; only the finding remains.
We do not store secrets we find. When a scan matches something that looks like a credential, the value never leaves the function that found it — we keep its first four characters plus “…” so you can recognise it, and a type label. The full value is never written to our database or our logs.
We store no GitHub credential at all. The connection record holds the installation id, the account name, the granted permissions and who connected it. The token used to scan is minted at scan time and never persisted.
Supabase and Google Workspace are different, and we say so plainly. Both use OAuth, so for each we hold one refresh token. It is encrypted at rest with AES-256-GCM in a dedicated database column — never in a field that read paths return, never logged. The encryption key is a hosting-environment variable, held outside the database, so the stored row is not usable on its own. You can revoke either grant from the provider’s own dashboard at any time.
If you connect a coding agent, the Gate records what it does. This is the part of the product most likely to see something sensitive, so it is worth being exact about.
From a coding agent’s hooks (Claude Code, Cursor) we record provenance only: the tool name, a repository-relative file path or a hostname, and whether the source was internal or external. The adapters read the tool’s input and never its response — and the response is where the fetched page text, the search results and the file contents live. A test asserts this: it feeds a payload carrying content in every such field and fails if any of it reaches what we keep or render. So Myla records that an external read happened and where from, never a copy of what was read.
When an agent asks the Gate to approve an action, it sends us its own account of the session, and here we do keep a limited excerpt so a human reviewing the decision can see what the agent was reacting to: the task description, a snippet of each external source, and for an outbound message its subject, recipients and a snippet of the body. Each snippet is truncated to 280 characters and passed through the same secret redaction as everything else. Attachment names and data classes are kept; attachment contents never are. These excerpts are shown to you on the Gate screen, and are not sent to any AI model.
Open question: decide whether a 280-character excerpt of an external source is acceptable retention for a customer, or whether it should be shortened, made opt-in, or dropped in favour of the label alone. This is the one place the product stores third-party content, and it is a judgement call, not a bug.
Signing in uses Supabase authentication: your email address and password (passwords are handled by Supabase, not stored by us in readable form), and a display name if you set one. Your account belongs to a team, which determines what you can see; access is scoped to your own team.
Security-relevant actions — a scan running, a risk accepted or withdrawn, an agent quarantined, a source disconnected — are recorded in an append-only, hash-chained ledger, so the history is tamper-evident. Each entry carries the hash of the one before it, and the database itself refuses updates and deletes: a trigger raises an error on any attempt, so the chain cannot be quietly edited, by us or by anyone who reached the database.
That is deliberate, and it has a consequence worth stating: ledger entries are not deleted on request while the account exists. They carry fixed descriptions, identifiers, severities and the Gate excerpts described above — never a secret value.
When you chat with Myla or ask her to explain a finding, we send your messages and a snapshot of your current security state to Anthropic’s Claude API to generate the reply. That snapshot lists your connections and their status, and your open findings by id, severity, check, title and plain-language summary — the same stored material described above, including the first four characters of a matched secret, never the whole value and never raw repository contents. It is clearly marked in the request as untrusted data rather than instructions. We do not use your data to train models.
To tell you whether a package you depend on has a known vulnerability, we send the name and version of each npm package found in your lockfiles to OSV, Google’s open-source vulnerability database. No code, no file contents and nothing identifying you or your repository is sent — only the package coordinates, which are public facts about public packages. Your dependency list is itself information, so we name this rather than leave it implied.
If you turn on push notifications, your browser gives us a subscription endpoint, which we store so we can reach that device. Sending a notification means delivering it to the push service your browser nominates — Google, Mozilla or Apple, depending on the browser. The payload is a short title and body, such as how many new high-severity findings a scan produced and in which account. We can confirm only that the push service accepted a message; nothing tells us whether a person saw it, and nowhere in the product do we claim otherwise. Account emails are sent through Resend.
If error monitoring is enabled (via a Sentry DSN set in our hosting environment), an unexpected error sends a report to Sentry containing the error’s name, message and stack, your user id, and your team id and role. The configuration disables every default that would capture more: no performance tracing, no session replay, no automatically attached personal data, no request bodies, headers or cookies, and no breadcrumbs. A final pass deletes the request, extra and breadcrumb containers outright and redacts known secret formats from any remaining message or stack text before the report leaves the process. If no DSN is set, nothing is sent anywhere and errors are recorded in our hosting provider’s logs as a name, message and HTTP status only.
We use Vercel Web Analytics to see, in aggregate, whether people arrive, try the demo and start setting up — the kind of thing we need before pointing anyone at the site. It is cookieless: it sets no cookie, assigns no cross-site identifier, and does no session recording and no device fingerprinting. Surveilling our own visitors would be indefensible for a security product, so we deliberately did not choose a tool that does it.
Two things are recorded. First, a page view — the page’s path (we strip the query string before it is recorded, so nothing a URL parameter carries is kept) and the referrer, so we can tell, say, a link shared on Reddit from one on Discord. Second, a few funnel events, each a plain count with at most a small non-identifying label: a demo step was run (which of the three), a public scan was started or finished (whether the built-in sample was used), a sign-up was started or completed (the method — password or Google), an agent was issued, and an agent contacted the Gate for the first time (which coding-agent client).
What these events never carry is the point: no personal data — no email, name, user, team or agent id, and no IP address; no contents of a repository you scan — not the URL, not a finding, not a package name; and nothing from the Gate’s ledger. The demo on /try runs the real policy engine in your browser with no network call for the evaluation itself; the step-run event is sent separately, after the verdict is shown, and a test (check:gate-demo) holds that the evaluation path makes no network request.
Open question: decide whether to name these as formal “sub-processors” and whether a data-processing agreement is in place with each — do not assert one that does not exist.
The homepage scanner, usable without an account, keeps only rate-limit counters — a hashed, time-bucketed key rather than your raw IP address, with an expiry — so it can enforce limits. It does not create an account or retain scan contents.
If you ask for early access, we store the email address and company you enter, and which screen you asked from, so we can follow up.
You can withdraw a risk acceptance at any time, and disconnect any connected source in the app. Disconnecting removes that source’s connection record and its findings; the ledger entry recording the disconnection remains, because the ledger is append-only.
To also revoke our access at the provider: uninstall the GitHub App from your organisation’s settings — we hold no GitHub token, so there is nothing left on our side; revoke the OAuth app in your Supabase dashboard under Organization → OAuth Apps; and for Google Workspace, disconnecting in Myla asks Google to revoke the grant before deleting our record — but that call is best-effort: if it fails, we delete our copy of the token anyway and log the failure, so you should confirm the removal in your Google account’s third-party access settings. A domain connection holds no credential, so removing it is simply deleting the row.
Deleting your account. You can do it yourself: Settings → Danger zone → Delete account. You have to type DELETE to arm it, and the server checks that too, not just the screen. There is no trash and no undo.
It runs as a single database function, in one transaction, so it either all happens or none of it does — a failure cannot leave you half-deleted. It removes everything we hold for your workspace: your findings, your connected sources and the tokens stored with them, the whole activity ledger, your agents and the tokens you issued to coding agents — along with their pinned tools, sessions and the record of what they read — your tasks, your fixes and any pending fix approvals, your Gate approvals and the requests behind them, your Deep Check history, and, keyed to you rather than the workspace, your access requests and your Learn-mode preferences. Which workspace and which person are both taken from your signed-in session and never from the request, so this can only ever delete your own. When it succeeds you are signed out and sent back to the start.
What deliberately survives: your sign-in account itself, which is your Myla login rather than this product’s data — email us if you want that removed as well; your workspace and its membership rows, which are the tenancy the rest of the app is built on; and the salted counters behind the public scanner’s rate limit, which are keyed to nobody. The deletion is not recorded in the ledger, because the ledger is one of the things being deleted — it is recorded in our server log, as the workspace id, your user id and a timestamp.
While your account is open we keep your findings, your ledger and your account data. The ledger is the product — a permanent, verifiable record of what was decided — so its entries persist for as long as the account does.
Deleting your account in Settings is immediate, not scheduled — the transaction above either completes or changes nothing. For the deliberate exceptions, such as removing your sign-in account, and for a request sent to us by email instead, we act within 30 days. If you disconnect a source, its findings are removed immediately and the rest within 30 days. Error reports are kept for 30 days, and only if error reporting is enabled at all.
Open question: these retention periods are commitments, not behaviour observed in the code — there is no scheduled deletion job. Either build one or state them as the manual process they currently are.
Questions about any of this, or a request about your data: support@mylasecurity.app.