Security
Security.
The controls in place today, where each one lives, and how to report a problem.
This page lists only the controls that are in place today. Each one names the code or server file that does it. When a control ships, it is added here; nothing is listed ahead of time.
Report a problem
Write to hello@zten.in. Our security.txt says the same. Please give us a reasonable time to fix an issue before you make it public.
Orders and your Zerodha account
| Control | Where it lives |
|---|---|
| MyZTEN can make only six Kite calls: four reads (profile, funds, positions, orders) plus the daily session exchange and logout. Any other call, such as an order, is refused before it leaves the server. | MyZTEN backend/app/kite.py |
Tests fail if order code appears anywhere in the MyZTEN backend, or if any file other than kite.py calls Kite. | MyZTEN backend/tests/test_kite.py |
| Your Kite secret and each day's access token are stored encrypted (Fernet), never returned to the browser and never logged. The API key is only ever shown masked. | MyZTEN backend/app/kite.py, backend/app/db.py |
| Your Zerodha password and 2FA are typed on Zerodha's page. MyZTEN gets only that day's access token, which Zerodha expires at 6:00 am. | MyZTEN backend/app/kite.py |
| The Zerodha login callback is tied to your account by a signed code that lasts 15 minutes. | MyZTEN backend/app/security.py |
| Disconnect logs the token out at Zerodha and deletes the key, secret and token. | MyZTEN backend/app/kite.py |
Accounts
| Control | Where it lives |
|---|---|
| Passwords are stored as bcrypt hashes (over a SHA-256 pre-hash), never in plain text. | MyZTEN backend/app/security.py, ZTEN core/shadow/auth.py |
| Sign-in, sign-up and one-time-code entry allow 5 tries in 15 minutes, then refuse. | MyZTEN backend/app/routers/auth.py, ZTEN core/shadow/guard.py |
| The MyZTEN session is a signed token in a cookie that scripts cannot read (HttpOnly), sent only over HTTPS (Secure) and only to my.zten.in (SameSite=Strict). It lasts 1 day. | MyZTEN backend/app/routers/auth.py, backend/app/security.py |
| Sign-up and reset codes expire after 10 minutes. | MyZTEN backend/app/security.py, ZTEN main.py |
| ZSIM Lab's guest limit keeps a salted hash of the IP address, never the address. | MyZTEN backend/app/db.py |
Market data
| Control | Where it lives |
|---|---|
| Today's paper fill and exit prices are held back by the server until the 15:30 close, not only hidden on screen. | MyZTEN backend/app/dics/engine.py |
| ZTEN Shadow does not send option leg prices to the browser. | ZTEN core/shadow/ic_data.py |
Web servers
| Control | Where it lives |
|---|---|
| Every site is served over HTTPS only, with HSTS. | nginx site files |
| Every site sends X-Frame-Options DENY, X-Content-Type-Options nosniff, a strict Referrer-Policy and a Permissions-Policy that turns off camera, microphone, location, payment and USB. A Content Security Policy runs in report-only mode while we check it breaks nothing. | nginx snippets/zten-security-headers.conf |
| The server does not reveal its software version. | nginx nginx.conf (server_tokens off) |
Server files live on our server, and our code repositories are private. The rules a strategy follows are public in the MyZTEN config panel.