For evaluators

What leaves the browser, and what never does

Leaves the browserNever leaves
The ciphertext (IV, encrypted bytes, GCM tag)The plaintext
The plaintext length, as display metadataThe file name: it is inside the ciphertext, in the SGMETA envelope
A content_type_hint the sender chooses; keep it genericThe decryption key: it is in the link's fragment, which browsers do not send
The access token, in a request header, to the API host onlyThe vault key, the read key, the keyring: this host receives nothing at all
For a vault: encrypted objects, refs and the write key's hex in a header, which the server stores only as a hashThe passphrase the vault key is made of

The API host, api.send.sgit.ai, is GitHub Pages: it serves files and has no way to receive a request body. The server the modules talk to is send.sgraph.ai or whichever endpoint the page configures, and what that server can and cannot see is written up at sgit.ai's security page.

Two secrets that must not be confused

The access token says who may upload. The decryption key says who may read. They are unrelated values with unrelated jobs, and the failure that matters is silent: an access token in a URL lands in proxy logs and browser history; a key in a request reaches a server that should never have it. send-transfers.js puts the token in x-sgraph-access-token and nowhere else, and the tests assert that neither value appears in any logged request path.

The supply chain of a release

Verify the live host yourself

curl -s https://api.send.sgit.ai/releases.json | python3 -m json.tool
curl -s https://api.send.sgit.ai/v0.1.1/manifest.json > manifest.json
python3 - <<'PY'
import hashlib, json, urllib.request
m = json.load(open('manifest.json'))
for f, e in m['entries'].items():
    b = urllib.request.urlopen(f"https://api.send.sgit.ai/v0.1.1/{f}").read()
    print('ok ' if hashlib.sha256(b).hexdigest() == e['sha256'] else 'BAD', f)
PY

That is the same check tools/live_check.py runs at the end of every deploy. Until the DNS for this host is in place (what needs a human), run it against the repository instead: python3 tools/release.py check.

What this does not prove