Private, on-device Terraform security review for Chrome
Ferrule collects nothing, transmits nothing, and has no servers.
That is the whole policy. The rest of this document explains what the extension does with your data so the claim can be checked rather than trusted, and points at where in the source each statement is enforced.
Last updated: 2026-08-24.
Your Terraform code. Read from either a GitHub repository you name or a folder you
pick on this machine. It is held in memory for the duration of a scan, passed to the
rule engine, and — if you opt into explanations — into a prompt for a language model
running on your own GPU. It is never uploaded and never sent anywhere. Ferrule does not
store your source on disk; the one thing it keeps is the recent reports described below,
which carry findings, any ferrule:ignore reason text, and model narrations — and those
stay in this browser profile.
Your GitHub personal access token, if you choose to save one. Stored in
chrome.storage.local, which is local to this browser profile on this machine. It is
sent only to api.github.com, only in an Authorization header, and never appears in a
URL, a log, or an error message.
Scan reports, if you have run scans. The most recent few are kept in
chrome.storage.local so the panel can show what changed since last time.
Two more local stores, for completeness. A model you download from the settings page
is kept in this extension’s own CacheStorage (a few gigabytes; the settings page can
delete it), and if you scan a local folder the browser keeps a read-only handle to that
folder in the extension’s IndexedDB so you can rescan it. Both live only in this browser
profile, neither syncs, and both go away with the profile.
chrome.storage.local is deliberate: Chrome also offers chrome.storage.sync, which
replicates data through your Google account. Ferrule never uses it, because that would
send your code and token off this machine.
Three hosts, each only when the relevant feature is used:
| Host | When | Why |
|---|---|---|
api.github.com |
scanning a GitHub repository | read the repository’s .tf files |
huggingface.co |
you press Download on the settings page | fetch the model file |
*.cdn.hf.co |
the same download, one hop later | Hugging Face serves the bytes from its own CDN |
Scanning a local folder makes no network requests at all.
The model download is the only thing those last two hosts are for, and Ferrule will not
start one until you allow it: they are optional permissions, so the install prompt
names GitHub alone, and the first download asks your browser for access to those two
hosts. You can take that access back at any time on the settings page. To be exact about
what the grant enforces: Ferrule’s code does not begin a download without it, and without
it the browser will not let a request bypass CORS; the connect-src policy below is what
guarantees those hosts are the only ones reachable. If you would
rather not grant it, fetch the model file yourself and hand it to the extension with the
side panel’s file picker — that path still works and touches no network.
The download only ever goes one way. Your Terraform is never uploaded anywhere; the model comes to your machine.
This is enforced, not merely promised, by the connect-src directive of the extension’s
Content Security Policy in manifest.json. In Manifest V3 the host_permissions list
does not restrict outbound requests — it grants the ability to make cross-origin ones —
so the policy is what actually confines them.
storage — to save your token and your recent reports locally.sidePanel — to show the panel the extension lives in.https://api.github.com/* — to read repositories you ask it to scan.Optional, requested only when you first download a model, and revocable from the settings page:
https://huggingface.co/* — to fetch the model file.https://*.cdn.hf.co/* — where Hugging Face redirects that fetch to serve the bytes.The source is public and the network surface is small by design: the browser’s fetch
is reached from exactly two places in the codebase — one for GitHub, one for the model
download — and both are injected into code that checks the request origin against a
closed list and refuses a response whose origin, after any redirect, is not on it.
Independent privacy audits of the whole tree are recorded verbatim,
including the findings that were failures, in
docs/privacy-audit.md.
You can also just watch: open DevTools → Network on the side panel and run a scan.
Report a privacy concern by opening an issue on the project’s GitHub repository.