We accept read-only keys and nothing else

A key with trading or withdrawal rights is refused at the moment you submit it. We do not take your word for the permissions: we ask the exchange what the key is allowed to do — Bybit through /v5/user/query-api, Binance through /sapi/v1/account/apiRestrictions — and a key that comes back as anything other than read-only never reaches storage. The error tells you which permissions to remove.

  • Refused at connect: trading (spot, margin, futures, options), withdrawals, internal transfers, universal transfer.
  • Re-checked on every sync, not only once. A key whose permissions are widened after it was connected is disabled automatically and stops being used.
  • A key the exchange no longer accepts is marked invalid rather than retried forever, and the badge it supported drops off the page.
Why this matters more than encryption does

Storage can always be argued about. Permissions cannot: a read-only key cannot place an order or move a coin, and the exchange enforces that on its side rather than us on ours. Even in the worst case, where an attacker holds our servers, our database and our master key at once, the credentials they hold still cannot take your money.

How the key is stored

  • Both the key and the secret are encrypted before they touch the database (Fernet — AES-128-CBC with an HMAC signature).
  • The master encryption key lives only in the server environment, never in the database and never in our source code. A stolen database dump on its own decrypts nothing.
  • The secret is never displayed again to anyone, including us, after you submit it. There is no screen in our admin that shows it.
  • We keep the last four characters of the public key in the clear so you can tell which key is connected. That is the whole of what stays readable.

And if you would rather not rely on any of that: the read-only restriction above is the guarantee that does not depend on our infrastructure being intact.

What we read from your account, and what we ignore

Every request we make is a signed read. There is no code path in ChainRated that places, modifies, or cancels an order, and with the keys we hold there could not usefully be one.

  • Closed positions — the core of the track: symbol, side, size, leverage, entry and exit price, fees, and the exchange’s own profit figure.
  • Order history — used to see whether stops and take-profits were actually attached to the trades.
  • Account balance — a periodic snapshot, used as the denominator when a drawdown is expressed as a percentage.
  • Deposits, withdrawals and internal transfers — read for one reason only: a percentage drawdown is meaningless unless we know money was not simply added mid-slide. Where an internal transfer carries the sender’s email or account id, we read past it and store neither.
What never leaves your account page

A published track shows percentages, trade counts, drawdown, liquidations and how long the account has been running. It does not show your balance, your position sizes in dollars, or your deposits and withdrawals in any form. Those are ours to compute with and nobody else’s to see.

What you can do on the exchange’s side

  • Restrict the key to our server IP — the connect form shows the address to allow. A key locked to one address is useless to anyone who steals it from anywhere else.
  • Give it an expiry date. When it lapses the sync stops and the badge disappears on its own; reconnecting is a minute of work.
  • Revoke it whenever you like, on the exchange, without telling us. The next sync finds the key dead and cleans up after itself.
  • Never send an API secret to anyone over chat or email, including anyone claiming to be ChainRated support. We ask for a secret in exactly one place: the connect form on your own account page, over HTTPS.

The rest of the platform

  • Admin access sits behind two-factor authentication and a non-default URL, with repeated failed logins locked out per IP and alerted on.
  • Payments are watch-only: we read a public blockchain address to confirm a payment arrived. We hold no private key to any wallet that receives money, ours or yours, and can move nobody’s funds.
  • Secrets live in the server environment rather than the repository, and the database password, session keys and encryption master key are all distinct from one another.
What we do not claim

No platform is unbreakable, and a security page promising otherwise would be the first thing on this site you should disbelieve. The principle we can actually defend is narrower and more useful: we deliberately hold as little dangerous material as possible, so that the damage a breach of ours could do to you stays bounded by what a read-only key allows.

The one private key we do hold

Once a day we write a single number to a smart contract on Arbitrum: the Merkle root of that day’s signal snapshots, which is what lets anyone check on /verify/ that a signal we show today is byte-for-byte the one we recorded then. Signing that transaction needs a private key, so we have one, and it would be easy to describe it in a way that sounds safer than it is. Here is the plain version.

  • It signs one kind of transaction, to one contract we wrote, from an address that holds about five dollars of gas and nothing else. There is no money on it to take.
  • It lives in the server environment file, which every one of our containers can read. It is not in a hardware wallet and not in an isolated signer — that would be a better arrangement and it is not the one we have.
  • It cannot change an anchor that already exists. The contract refuses a second root for a day it has already recorded, so yesterday’s proof cannot be replaced with a more convenient one — not by us, not by anyone holding this key.
  • It cannot touch your funds, your API keys or your account. Different key, different system, nothing shared.
What someone who stole it could do, and what stops it mattering

They could burn our gas and write meaningless roots into days we had not anchored yet, from our address. What they could not do is rewrite an anchored day, or make their transactions count as ours: every batch this site presents as proof must match a registered period — chain, contract, sending address, dates — and that registry lives in our source code, changed by a commit that has an author and a diff, not by a setting or a database row. An anchor written outside it is shown as exactly what it is, and the page says so instead of quietly accepting it. Our response to a leak is to move ownership of the contract to a new key and close the old period; the anchors written before that keep verifying, because they were ours when they were written.

Found a problem?

Tell us before you tell anyone else and we will fix it quickly. Email [email protected] with "security" in the subject line and it reaches the people who can act on it. We will not threaten anyone who reports a vulnerability to us in good faith.