Risks and mitigation strategies for Keycard in a payment network

Following Guy-Louis’ post we wanted to share and discuss the risk and possible mitigation strategies that we see when using Keycard in a payment network. Some mitigation strategies are a bit complex and I have linked a more technical document describing them in details. In particular the reputation system is a complex topic and I am still working on it (and I am actually wondering if it is too risky to use). Any feedback is very welcome.


First we need to understand what security risks we incur and why. The main considerations to keep in mind is that Keycard does not have any user input output capability so interaction must always happen through a second device. Additionally, the card does not have a battery and as such cannot keep a clock. In a payment scenario this device belongs to the merchant and not to the card holder, making it inherently untrusted. Unlike existing payment networks, we want transactions to be possible through any device, meaning the POS will not have a certification process and remain an untrusted element.

From this perspective, it becomes clear that a malicious merchant can:

  1. Create a transaction for an amount larger than agreed with the customer (the POS screen can lie). Since the balance of an account can be easily enquired a transaction can take 100% of what is stored
  2. Create several transactions, possibly with different recipient wallets and send them at a later time to cover its track and mask malicious activity
  3. Log any input provided by the user through their terminal

Mitigation strategies

These are the options we have come up with so far. Some options can be used together, some are mutually exclusive and some can be impractical. Proposal of new strategies or challenging the proposed ones is the main goal of this post.

Basic strategies

These are the basic mitigation strategy that will surely be implemented or are implemented already

  1. Keep a payment wallet separate from the main fund wallet, limiting the fraud potential to an amount the user considers acceptable
  2. Do not share credentials between the main wallet and the payment wallet. Even if it might sound counterintuitive, we found the most acceptable solution is to make payments completely pinless. Another solution would be to have a separate payment PIN but this is likely to confuse the user and very likely to be correlated to the main PIN if chosen by the user
  3. Use a smartcontract to limit per-transaction amount, possibly also allowing a cooldown period between two transactions and hard daily/monthly limits

Mitigation of multiple transaction attacks

When performing a POS transaction, we want the terminal to only sign a single transaction following the rule of one tap/one signature. However the POS can send as many SIGN commands as it wants, eluding this measure. Here are some possible strategies.

  1. Only allow one SIGN command to be processed per power-up. Although useful, the terminal can reset the card relatively quickly so while this certainly limits the amount of transactions signed in the timeframe of a tap, it cannot guarantee that only one transaction will be signed.
  2. Add a timestamp field to the SIGN command. The timestamp must be signed by an authority the card trusts. The card can then store the timestamp and refuse all successive SIGN command with a timestamp which is not at least 1 minute in the future (let’s assume a tap lasts no more than two seconds and is usually much quicker). Although this adds an authority in the process, there are several public timestamp servers already operating which can be used. The additional remote request will slow things down a little.
  3. Add a transaction counter limit on-card. The card will refuse to perform more than X SIGN commands until the user, through an authorized command on their trusted device, allows X more. This is similar to the timestap approach in goal but simpler for all involved parties. However the user must remember to allocate transactions regularly for this to work.

Reducing unauthorized transactions

  1. Use a transaction pre-approval mechanism. The card will only SIGN transaction hash previously signed by an online pre-approval service. The POS will query the card for the address of server, meaning that as long as the API is respected, the card holder can choose any service or even run their own service. The pre-approval server performs a risk assessment on the transaction according to user defined policies. Some examples include whitelisting, blacklisting, capping transaction amount/count for unknown merchant. The service could send a notification on each preapproved transaction or even require user confirmation. This approach is the most flexible in regards of policies and does not involve central authorities. More technical details here.
  2. Use a reputation system. Allows the user to dispute transactions by staking a small amount of tokens ($5-10 equivalent?) within x (10-30?) days after the transaction has been performed. Each merchant will have a reputation score based on the number and value of performed transactions, heavily weighted towards recent transactions so that it does not accumulate over time. Each open dispute lowers the merchant score and if it gets negative, the disputes are won by the buyer, otherwise they are won by the merchant. The scoring formulas must be tuned so that the ratio of performed transactions in the last x days and open disputes must be below a certain percentage (15-20%?) for the score to remain positive. This system relies on using smartcontract accounts for all transactions with regulated transfer from/to EOA. As any reputation/dispute system, the outcome of the dispute will not always be just and it will take some fine-tuning to the formula to maximize accuracy. I think however that a very high accuracy can be obtained, especially since it can deter bad behaviour. The goal of this system is to revert transactions performed by fraudsters, not to resolve case-by-case disputes, because honest merchants would win those easily, since they would get a dispute once in a blue moon. More technical details here (WIP).
  3. Adding a screen and a button on the card. This would allow the user to check the transaction amount and confirm transactions individually, pressing the buttons. This is the most effective mitigation measure, but it would greatly increase the complexity and cost of the hardware. With current technology, implementing such a device in card format is possible but the resulting device is not bound to be very durable because solder joints on a flexible PCB will break easily. The price for flexible PCBs, batteries and screens is also high as of today.

Limiting theft

Since a PIN is not required to perform payments, theft or skimming are viable attack routes. Possible mitigation strategies are

  1. Allowing the user, through their main wallet account, to revoke signing rights to the smartcontract holding the funds. The main wallet account is PIN protected on card and should be backed up either using Keycard facilities or as a regular BIP39 seed. The smartcontract should also allow the user to assign new cards as signers.
  2. Encourage physical security measures against skimming. Reading a card through a wallet or clothes is not easy and can be effectively prevented by using either an RFID-shielded wallet or a simple RFID-shielded pouch.
  3. Adding an on/off switch on card can be a sure way to deny any proximity attacks. The cost at manufacturing should be minimal, because placing a toggle or push button between the chip and the coil is enough, the chip does not need to be aware of the switch.
  4. Adding a biometric sensor would be a good substitute for a PIN, since the card would be able to authenticate it autonomously. This could greatly affect the cost of the card though

If Merchants are staking in a network and collecting fees for securing the network, this could also be used as a ‘certification’ process in the sense that if someone challenges their fraudulent transaction their stake could be slashed, merchants would only be able to process transactions up to the amount they have staked, you could also give a small award to the challenger upon successful transactions (and penalising for false claims, by a similar staking mechanism)

How a fraud claim would be confirmed is unknown, maybe it’s majority vote or confirmation from end user or some arbitration process.

This would create a market for fraudulent transaction monitors of the payment network, which wouldn’t necessarily requite the end user to be aware of fraudulent transactions.


Using a smart contract that can undo transactions don’t seems a simple solution because it would require a whole technical and social infrastructure for it to work, and this looks like the role of a company like VISA or MasterCard.
While Keycard would not implement that, it could support this type of “super-visioned” payments for users buying from non trusted sites, but also develop solutions to secure payment between trusted parties, like addresses to whom you commonly transfer for, only needing the nonce signature, and merchant would withdraw from user account - or use a statechannel…

The Chip itself can be considered a smart contract, but differently from regular smart contracts, this one have a private key that can sign messages. Key card is a wallet contract that accepts payments by providing the PIN and transaction data.
Based on this we could implement multiple keys or allowances by using different pins, but this would be horrible from UX perspective.

Education is an option aswell, but risky if the only approach.
Keycard is not a credit card, nor a debit card, is a key card :slight_smile:. It not only can do do payments, but it can also be your self soverign identity, and more - so you should not just put it on other people scanners.


I see, the reputation system in the proposal goes more or less in that direction, although the stake from the merchant is “dynamic” in that it consists of performed transactions in the cooldown period. The fraud claim also has a stake system and the decision is basically a vote in the sense that a certain amount of disputes makes the reputation of the merchant go negative and they lose their transactions. However I think it is complex to adjust all stakes/reputation formulas so that neither part is able to cheat the system without risking huge amounts of tokens. We could also add an initial stake as you proposed to make the barrier of entry for fraudsters higher. The hard part is settings the amount in such a way not to hinder adoption but still deter potential fraudsters

The issue we are trying to tackle here is in-person transactions with the classical card/PoS pair. For remote transactions you have a lot of instruments to decide if a vendor is trustworthy or not (including review sites) so the situation wouldn’t be much different from what it is now. Reversing transactions is indeed dangerous, the reputation system we are working on will surely get some decisions wrong. The question here is what percentage and how hard/expensive it is to trick.

We decided to go PINless for PoS payments because a PIN can be logged if inserted on a third party device and if you have several PINs it is likely that revealing one can reveal the pattern with which you choose PINs, so it is safer not to give one. The card also receives only the transaction hash so it cannot really apply any rule directly. The reason for this, is that we either limit the card to a very restricted subset of known tokens or the card would have no way to understand the actual value of the transactions since it does not have access to exchange rates or things like that. Also the card does not have Keccak so it cannot generate the hash autonomously

Education is the main approach we originally planned to adopt, but it was met with a lot of skepticism, so we started looking for more complex solutions. Personally, I am very fond of the pre-approval service idea (is in the list of solutions in this Discuss post) since it can prevent a lot of bad transactions without needing reversal and gives a lot of flexibility.


Another risk mitigation strategy is to have velocity control in the card. i.e. the card evaluates the transaction and checks if the sum of amounts sent over a period of time (e.g. trailing 24 hours) is below a certain value. The trusted timestamp mechanism mentioned above would be required. Storage of amounts with timestamps would also be needed.

Different cards for the same wallet could implement different velocity limits. The high limit card could be left in a secure location for occasional use.

A physical switch or touch button could also be used to switch to a different velocity limit.

1 Like

that’s a great input, however one immediate issue is that keycard only signs the transaction hash (and wouldn’t be powerful enough with current available javacards to get the transaction and sign it), so the card has not clue of what it’s signing :frowning:

Could you expand on that? what is the operation that the card is not powerful enough to perform? Is it the sha3?

I do see that it takes ~7 seconds based on this impl: https://github.com/MiragePV/OptimizedJCAlgs/tree/master/Sha3

yeah a software SHA3 implementation is too slow for real usage. Also it is difficult to check amounts on card because of ERC20 transactions. Just summing together raw amounts of different coins/eth does not make much sense and the card has no way of knowing the exchange rates.

There is also the question of flexibility, by only signing a hash the card is compatible with all cryptocurrencies using the SECP256k1 curve. This is something we’d have to give up if we were to inspect the transaction (we could support multiple currencies of course, but that will make the applet quite large and complex).

The timestamp can be used for velocity checks through, simply by counting the number of signed transactions. That would at least avoid a terminal sending multiple transactions in a window of a few seconds. A smartcontract can be used instead to limit max spending in a 24h window as you suggested.

On further thought, I realized that the contract can use sha256 for authorization. For example, we could adapt simple-multisig contract with sha256 replacing keccak. This would eliminate the slow hashing issue.

Re ERC20 - the velocity controls can be specific to the coin being transacted. i.e. the card would be configured with rules, such as “if transferring USDT, keep the velocity under 100 tokens/hour”, etc. Alternatively, could have a set of oracles publishing signed exchange rates, and provide these to the secure card.

I don’t think the secure card would add much value if it signs blindly without understanding the transaction - for non-smart-contract chains like BTC. With blind signing, the card would happily sign a transaction that empties the wallet.

1 Like

What would be the advantage of doing it on-card instead of on-contract? The applet would become more complex and require more memory. Applets also do not have a trivial way to be upgraded without losing stored data, so any subsequent change to the applet to fix bugs/support extended formats will be quite inconvenient to deploy.

It can add convenience to the payment experience. If the account used for payments only holds small amounts it can be considered an acceptable risks in many situations.

To chime in I would never be confortable with using the keycard on another device, I thought of keycard as a very simple and verifiable secure enclave that I can trust more than my device. So I always expected that PoS would be about scanning a QR code and taping the card on my phone.
I doesn’t have to be through status, could be a super light wallet, but I would want to use my device, and it would feel more secure than a credit card.

1 Like

We have discussed about that solution, that’d be the easiest to implement. However since the user experience in that case would be quite poor (both for you and those in line behind you) we want to replicate the current workflow used by credit cards. That’s why we are thinking on how to make paying with the Keycard as secure as possible. The first and most important part is already there: the PINless account is separate from other accounts and the POS never gets pairing/PIN so it cannot do anything nefarious to the wallet.

I don’t think it’s a poor experience, the keycard already starts status when you tap it on the phone, you can even store the pin in the secure enclave so that basically you tap once to open qr code reader and once to pay and done. you could also tap the terminal to get the payment info instead of a qr code and then tap the card to confirm. Personally I hate credit cards because I give the card and PIN to an unknown terminal, so I have to trust the owner and backup that trust with my bank in case something goes wrong. I can trust my phone enough to display the right information about the payment and we don’t have all the complexity of managing a separate account with limited founds to steal. For that I can use cash already.

@yenda this is a different scenario. it’s like using a burner wallet on you card, that can be installed together with the keycard wallet applet. so for keycard as hardware wallet for your cold accounts you will still use pairing password and pin.

I have found myself using my phone more and more for payments with its integrated wallet app, I’m pulling out my credit card less often opting instead to just tap my phone on the card reader (which is just a convenient proxy for my credit card). The security I get is with the dispute resolution from my credit card company. For crypto I would be fine for paying directly from phone for small amounts but for amounts over a certain threshold a second factor like keycard would give me the same comfort level as using credit cards.

Hi guys,

trying to address the following problems:

  • trust for users.
  • ability to revert transactions (as in MC/Visa now).

When you go to a shop, you usually get a receipt or bill, this can be used together with a whitelisted merchant list to allow some kind of legal investigation.

what about a contract with the following pseudo-code:

pragma solidity 0.5.2;

// wallet for one keycard, both derivation path registered as Spenders with different limits
contract KeycardWallet {

  struct Payment {
    address from;
    address dest;
    uint256 value;
    bytes receipt; // what has been bought? used for police/court investigations

  struct Spender {
    address sigAddr;
    uint256 dailyLimit;
  mapping(uint256 => Spender) spenders; // pinless and pin-accounts have an entry here

  uint256 public lastDay;
  uint256 public spentToday;

  function isUnderLimit(uint amount) internal returns (bool) {
    if (now > lastDay.add(24 hours)) {
      lastDay = now;
      spentToday = 0;
    // not using safe math because we don't want to throw;
    if (spentToday + amount > dailyLimit || spentToday + amount < spentToday) {
      return false;
    return true;

  function payment(bytes spenderSig, bytes merchantSig, Payment data) public {
    // the merchant registry whitelists all merchants,
    // and holds a legal address for police/court investigations
    MerchReg merchRegistry = MerchReg(merchRegAddr);
    address merchAddr = ecrecover(merchSig, data);
    require(merchRegistry.isMerch(merchAddr) == true, "not valid merchant");
    address spenderAddr = ecrecover(spenderSig, data);

    require(data.value > 0); // no dust outputs
    uint256 newDate;
    require(isUnderLimit(data.value) == true, "exceeding limit with this account");
    newDate = (lastDay > now) ? lastDay : now;

    spentToday = spentToday.add(data.value);
    ERC20 token = ERC20(data.tokenAddr);
    token.transfer(merchantAddr, data.value);
    emit Payment(data.from, data.dest, data.value, data.receipt);

  function addSpender() {
    // todo:


we use a simple sliding-window implementation in the contract and create spenders with different limits.

A PoS would act as follows:

  1. read address from card.
  2. read UTXO’s for wallet contract of that address.
  3. construct a transaction with payment amount.
  4. PoS asks keycard to sign the transaction.
  5. PoS tries to publish tx on blockchain. 2 things can happen:
  • tx passes, we were under the limit, flow done.
  • tx rejected, daily limit hit, continue to 6.
  1. PoS checks if wallet contract has signer with higher limit, we find the derivation path that requires pin.
  2. PoS constructs transaction again, and now pushes transaction to be signed in the cloud (websocket to user’s phone).
  3. phone gives notification and asks users to tap and sign again with pin-derivation path
  4. transaction is published, PoS receives notification.

if there are payments with the pin-less derivation path that the user didn’t know. the information in the receipt bytes (what has been bought) and the address from the merchant registry can be used to initiate a police investigation.


I add here an alternative to the timestamp field sent to the SIGN command that we talked about in the last days. With this implementation we don’t need changes in the keycard applet and the check is done on chain.

The idea is that the network “operators” update a “random salt” on a smart contract every N blocks.
The meta tx sent by the point of sale to the keycard contains merchant address, value, nonce, and the random salt taken from that contract.
Even if a bad merchant signs 2 txs, it can’t send the second one in the future, because the salt in the contract will change and the tx will be invalid.
So basically after N blocks, the customer can be sure that the balance cannot change until the next time the keycard is used.

what do you think?

hey @johba, thank you!
That’s very similar to what we are testing now with the merchant registry, but it adds the second signer for txs with higher value and I like the idea!