DEV Community

Cover image for Before you give a Polymarket bot your private key: a 15-minute checklist
Andrey Schurko
Andrey Schurko

Posted on

Before you give a Polymarket bot your private key: a 15-minute checklist

In 2026, "Polymarket copy-trading bot" became one of the most effective lures on GitHub.

The pattern repeated all year. In February, an attacker took over a legitimate organisation's GitHub account and published more than twenty malicious repositories, several of them Polymarket copy-trading bots. Following their setup instructions installed a hidden npm dependency that read the private key from .env, sent it to the attacker's server and opened an SSH backdoor (StepSecurity's write-up). In July, a fake "arbitrage bot" collected dozens of stars and forks before researchers tied it to thirty malicious npm packages.

Here is the uncomfortable part: a self-hosted trading bot legitimately needs your private key. It has to sign orders. So "never give a bot your key" is not useful advice. "Know exactly what the bot does with it" is.

I maintain Garnet, a self-hosted Polymarket copy-trading engine. Below is the checklist I'd want anyone to run on any bot, mine included, before putting a funded key into its .env. It takes about fifteen minutes and needs no security background.

1. Who asks for what?

  • A seed phrase is an instant no. A bot needs one signing key, never a 12- or 24-word mnemonic. A mnemonic controls every account derived from it.
  • A hosted service that wants your key is a different trust model from software you run yourself. Neither is automatically wrong, but you should know which one you're choosing.
  • Promises of returns are a red flag on their own. No copy-trading tool can promise profit, because the result depends entirely on the wallets you copy.

2. Read the dependency list, not the README

Most stealers in 2026 hid in dependencies, not in the code you'd read. The bot's own code looked clean, and the payload sat in a package installed during setup.

For a JavaScript or TypeScript project:

cat package.json                 # look at every dependency, not just the famous ones
npm ls --all | less              # the full tree you are about to install
Enter fullscreen mode Exit fullscreen mode

Look for names one letter off from popular packages (big-nunber instead of bignumber), packages with almost no downloads, and postinstall scripts.

For a Rust project:

cargo tree                       # the full dependency tree
cargo install cargo-audit && cargo audit   # known advisories
Enter fullscreen mode Exit fullscreen mode

Check that a lockfile exists and is committed (package-lock.json, Cargo.lock). Without one, what you install today may differ from what was reviewed yesterday.

3. Find every place the key is read

Search for the variable name:

grep -rn "PRIVATE_KEY" --include="*.ts" --include="*.js" --include="*.py" --include="*.rs" .
Enter fullscreen mode Exit fullscreen mode

Every hit should lead to signing, and nowhere else. A key that gets read and then concatenated into a string, serialised, logged or passed to an HTTP call is the whole attack in one line.

4. List every host the code talks to

grep -rhoE '(https?|wss?)://[a-zA-Z0-9.-]+' . | sort -u
Enter fullscreen mode Exit fullscreen mode

For a Polymarket bot, the expected list is short: Polymarket's own hosts (clob.polymarket.com, gamma-api, data-api, ws-live-data), a Polygon RPC endpoint, and maybe Telegram's API if it has a Telegram interface. Every other host needs an explanation. Remember that this only covers the bot's own code, which is why step 2 matters.

5. Check what ends up in the logs

Bots usually print their configuration at startup. Run it without real keys, or with a throwaway key, and read the log. Your key, API secret and passphrase should appear redacted, if at all. If the bot logs them in full, that log file, journald or your hosting provider's console now holds your key.

6. Start without the key

A well-built bot can do something useful before you hand over a key: paper trading on real market data. If the only way to see it work is to fund a wallet first, you're being asked to trust it blind.

7. When you do go live

  • Use a dedicated wallet with only the money you're prepared to lose. Never your main wallet.
  • Keep .env out of git and readable only by you: chmod 600 .env.
  • Run it on a server you control, and re-run steps 2–4 after every update.

How Garnet answers this checklist

I wrote Garnet's README to be checked against exactly this list, so here are its answers:

  • One signing key, never a seed phrase. The key lives in .env on your machine and signs orders locally (EIP-712). The signature goes to the exchange; the key does not.
  • No npm. The engine is Rust end to end. Every dependency is pinned in Cargo.lock, and the Polymarket SDK is pinned to an exact version. cargo audit is clean apart from one advisory in a crate that sits in the lockfile but isn't compiled into any binary, and the README says so.
  • The key is read in exactly two places, both handing it straight to the signer as a SecretString.
  • The README lists every host the code talks to, with the grep above to verify it.
  • Logs show `REDACTED`, and a test named the_private_key_never_reaches_a_log_line holds that line.
  • No keys, no live path. With no keys in the environment the live path doesn't start at all, and shadow mode trades on paper on public data, paying the same fees as live would.

You don't have to take any of that on trust. That's the point of the checklist.


If you find a way the key could leak, please report it privately as described in SECURITY.md instead of in a public issue.

Top comments (0)