How the sensitive parts are held

This product asks for broker credentials, so it owes you a plain account of how they are stored — including what is not built yet.

Signing in

A code, not a password
Sign-in is a six-digit code sent to your email. Codes are stored only as a salted hash, expire in minutes, allow a fixed number of attempts, and are rate-limited per address.
Sessions you can revoke
Access tokens are short-lived and refreshed against a stored refresh token. Reuse of a refresh token is treated as theft: the session is invalidated rather than renewed.
Nothing sensitive in a cookie
The session lives in your browser’s local storage, and the site sets no tracking cookie.

Broker credentials

Encrypted with a managed key
Your Kite API secret, TOTP seed and password are sealed with a key from a key-management service. The plaintext is never written to the database and never written to a log.
The API cannot read them back
The application role holds INSERT and not SELECT on the credential table. An endpoint that returned your key could not be written even by mistake — the database grant is the guarantee, not the code’s good intentions.
Deleted when you disconnect
Disconnecting the broker or switching automated execution off removes the encrypted rows.
Read-only where read-only is enough
The optional Zerodha connection that compares your holdings against what the product thinks you hold cannot place an order, even when automated execution is on.

What is not built yet

There is no second factor on credential intake. Step-up authentication exists as an interface and refuses every request, because no verifier is enrolled — so a valid session is currently enough to submit broker credentials. That is weaker than this data deserves. It is recorded in the code beside the route it protects, and it is recorded here, because you are deciding whether to hand over a Kite password and the decision is worse if you have to discover this afterwards.

Around the system

Transport
HTTPS everywhere, with certificates renewed automatically. The app never asks you to enter credentials on a page whose address bar is hidden.
Separation by role
The API, the scheduled worker and administration each connect as different database roles with different privileges. Row-level security scopes user data to its owner inside the database, not only in application code.
An audit trail
Security-relevant actions are appended to a hash-chained log with a correlation identifier, so a question about what happened has a checkable answer.
Orders are never retried blind
An order whose outcome is unknown is never resent — the one behaviour that could double a position without anybody asking for it.

Reporting a problem

Email support@tradeorskip.com with what you found and how to reproduce it. Reports are read by a person and answered. Please do not test against other people’s accounts, and give us a reasonable chance to fix an issue before publishing it.

There is no paid bug bounty. Saying so is more useful than implying one exists.

This page describes controls that are implemented today. It is not a certification, an audit report, or a claim of compliance with any security standard. What is stored, and for how long.