Security

We run generated code.
Here's how that's contained.

A product that executes Python written by a language model has an obvious question hanging over it. This page answers it in specifics rather than adjectives, including the parts that are still imperfect.

The sandbox

Generated Python never runs in the web page and never runs in the API process. It is handed to a separate execution service that does one thing: run a strategy and return numbers.

Before a single line executes, the code goes through a static check. If it fails, nothing runs — the request is rejected outright rather than being run with monitoring.

Static allowlist

The code is parsed into an abstract syntax tree and walked. It is rejected unless every import, name and call is on an allowlist. Concretely, that means:

  • Imports are limited to the libraries a backtest actually needs — backtesting, pandas, numpy, math and a short list beside them. os, sys, subprocess, socket, shutil and their relatives are refused.
  • Dynamic execution is refused: eval, exec, compile, __import__, globals, locals.
  • Attribute escapes are refused — the __subclasses__ / __globals__ style of sandbox break-out is blocked at the AST level, not by string matching.
  • File and network access is refused. A strategy has no reason to open a socket, and one that tries does not run.
An allowlist is used rather than a blocklist deliberately. A blocklist has to anticipate every escape; an allowlist only has to enumerate the small set of things a backtest legitimately does.

Process isolation

Code that passes the check still runs as though it had not been trusted:

  • A separate subprocess, so a crash or a hang takes nothing with it.
  • A scrubbed environment. The child gets an explicit allowlist of variables — path, home, temp, certificates — and nothing else. Service credentials are never in its environment to be read.
  • A hard timeout, after which the whole process tree is killed rather than just the parent.
  • Output scrubbing. As a backstop, if anything a strategy printed contains our internal execution secret, the response is discarded instead of returned.
  • Bearer authentication between our API and the executor, compared in constant time, and required — the executor fails closed when deployed rather than open.

What we store

The short version: as little as will still make the product work.

DataStored?Why
Email addressYesIt is your account. Handled by our auth provider, not by us directly.
PasswordNever in readable formHashed by the auth provider. We cannot see it and cannot recover it.
Saved strategiesYes, if you save oneSo you can re-run them. Row-level security means your rows are readable only by your account.
Backtest resultsYes, if signed inYour history. Same row-level isolation.
Payment detailsNoThere is nothing to pay for yet, so there is no card field anywhere in the product.
Voice from the mic buttonNoTranscription happens in your browser via its own speech API. No audio reaches us.
Third-party analyticsNoNo trackers, no advertising pixels, no session recording.

The privacy policy covers retention and deletion in full.

Transport and headers

  • HTTPS everywhere, with HSTS.
  • A Content Security Policy on every page, restricting scripts, styles, fonts and connections to an explicit set of origins.
  • Framing denied, so the app cannot be embedded and clickjacked.
  • Requests are authenticated with a signed session token, verified server-side on every backtest — not merely checked in the browser.
  • Rate limiting per account on the execution endpoint.

Known limits

Things a security page usually omits. These are real and we would rather you heard them from us.

  • Rate limiting is per-instance and in-memory. It resets on a cold start and is not shared across instances. It is a courtesy limit, not a defence against a determined abuser.
  • The demo run limit is client-side. Five free runs are counted in your browser's local storage. Clearing it resets the count. It is a trial boundary, not a security control, and we have not pretended otherwise.
  • Same-user process inspection. The executor's subprocess runs as the same OS user as its parent, so on Linux it could in principle read the parent's process environment. We accepted this because that machine holds no other secrets — but it is a real gap rather than a theoretical one.
  • No formal audit. Nobody independent has reviewed any of this. It is a young product built by a small team, and claiming otherwise would be the kind of thing this page exists to avoid.

Reporting a problem

If you find something, tell us before you tell anyone else and we will fix it fast. Email security@alphaback.app with enough detail to reproduce it.

We do not run a paid bug bounty — there is no revenue to fund one yet. What we can offer is a same-day acknowledgement, a real fix, and public credit if you want it. Please do not run automated scanners against the live service; they mostly generate noise and cost us the time we would rather spend on your actual finding.

Questions we didn't answer?

Ask directly. Security questions get answered by a person, not a form letter.