Coldstar + Squads · Running on devnet

An agent wallet where losing the key does not lose the funds

Every agent wallet on Solana bounds the agent off-chain: a policy engine decides what the agent may sign. That stops a hijacked agent, and it does nothing at all about a stolen key, because whoever holds the key signs with a standard library and never touches the policy. The fix is not a better policy engine. It is a second bound that lives on the chain.

The two failures are different, so one control cannot cover both

Off-chain, local

A misbehaving agent

Prompt injection, a poisoned tool result, a model that simply gets it wrong. The agent proposes something it should not. A policy signer refuses before a signature exists, and can escalate to a human. Fast, expressive, and completely bypassed if the attacker has the key.

On-chain, unavoidable

A stolen key

An exfiltrated key, a leaked log, a bad dependency. The attacker does not run your agent or your policy engine. Only a limit the chain enforces still applies, and it applies to everyone equally, including them.

So the interesting design is not one or the other. It is a session key that is simultaneously bounded by a local policy and by a spending limit the Solana program itself enforces.

How it is put together

AloneLayered
Squads vaultSpending limits the program enforces, but members typically sign from a hot browser wallet. Its own documentation routes hardware wallets through Phantom or Solflare with blind signing.The member is a cold-rooted session key under local policy.
Coldstar signerCold root, local limits, escalation to a human — all defeated by a stolen session key.A stolen key is still bounded by the on-chain limit, whoever holds it.

Funds sit in the Squads vault. The agent's session key is a member of a spending limit with an amount, a period and an allowed destination. The root key that authorises the local policy never comes online. When the agent wants to pay, it builds the Squads instruction, Coldstar decides whether to sign it, and then the program decides whether to honour it.

Coldstar reads Squads rather than trusting it. Allowlisting the program as opaque would leave the local limits meaningless, because a transfer through it moves no lamports of its own. The spending-limit instruction is decoded down to the amount, the mint and the destination, so per-transaction, daily and per-token limits still apply on top of the chain's.

Running on devnet

This is not a diagram. One command creates the multisig, adds a spending limit naming the agent's session key, funds the vault, and runs three cases. The local policy is deliberately tighter than the chain's, 0.01 SOL per transaction against the vault's 0.05 per day, so you can see the bounds act independently.

── 1. the agent spends 0.005 SOL, inside both bounds
  [policy] AUTO_SIGN within policy
  -> landed on chain, payee received 0.005 SOL from the vault

── 2. the agent asks for 0.04 SOL — the VAULT would allow it, the local policy does not
  [policy] ESCALATE  amount 0.04 SOL exceeds escalate threshold 0.01
  -> no signature exists, so this never reached the chain

── 3. the agent tries to raise its own ceiling
  [policy] ESCALATE  squads multisig_add_spending_limit (raises the agent's own ceiling)
  -> refused before signing

The confirmed transfer is on devnet, from vault Dmpcz9MA…HY9r. Reproduce it with node examples/squads-devnet-demo.mjs --funder <devnet keyfile>, about 0.03 SOL.

Why the third case matters most

Raising a spending limit is a different instruction from using one. An agent that could sign the first has no meaningful limit at all, whatever the second one says. So Coldstar refuses those instructions by name: adding or removing a spending limit, changing the multisig configuration, executing an arbitrary vault transaction, creating or voting on proposals.

In the demo the chain would have refused it too, because the session key is not the configuration authority. That is the correct belt-and-braces answer, and it is also the point: the request never got signed, so it never consumed a fee, never hit an RPC, and never had to rely on the second layer being configured correctly.

What this still does not do

An on-chain limit bounds the loss from a stolen key; it does not prevent it. Inside the limit, a thief spends freely until you revoke, which is why grants are short and revocation is published on chain. Coldstar remains beta and pre-audit. And a vault does nothing about the offline machine: if the root is compromised where it is decrypted, none of this helps. That is written up in full in the threat model, including the parts we would rather you knew before trusting it.

Frequently asked questions

Why is an off-chain policy not enough?

It stops the agent from proposing something it should not, which covers prompt injection and a hijacked agent. It does nothing about a stolen session key, because the holder signs with a standard library and never touches the policy engine.

Is the on-chain limit alone enough?

It bounds the loss, but it does not stop a misbehaving agent inside the limit, it cannot wake a human, and vault members usually sign from a hot wallet. The layers cover different things.

Does this need a partnership with Squads?

No. Squads v4 is AGPL and permissionless on mainnet and devnet, so anyone can build against it. The tests here construct their instructions with the Squads SDK itself.

What stops the agent raising its own limit?

Changing a limit is a separate instruction, and Coldstar refuses those by name. The agent can spend inside its limit and cannot change the limit.

Does it work for USDC and other tokens?

Yes. A spending limit can be denominated in any mint, and Coldstar applies per-mint limits in base units on top. Token instructions it cannot bound, Approve in particular, escalate to a human.

Set it up Read the code Coldstar vs Squads, in full What it does not protect

Last reviewed 2026-09-07.