Authorize.Net

Rotate Authorize.Net Transaction and Signature Keys After a WordPress Compromise

Authorize.Net lets merchants keep an old transaction or signature key alive for 24 hours or kill it at once. After a WordPress compromise, its documentation points to the immediate cutoff, and the signature key change has to be matched in webhook code so notifications keep arriving.

At a cafe window on a rainy afternoon, a man turns a small brass key in one hand while typing on a laptop across from a locksmith's key sign, much like a store swapping its Authorize.Net keys after a break-in.

A WordPress store that has had an intruder inside it this fall, through the PHP2Shell flaws in older PHP or the UpdraftCentral breach that planted hidden plugins, has a payment problem that a new admin password does not fix. The Authorize.Net plugin on that site needs the account’s API Login ID and Transaction Key to charge cards, so those values sit in the site’s database or configuration files. Anyone who copied them can keep sending requests to the gateway as the store until the key is replaced.

Authorize.Net’s documentation gives merchants two ways to replace a transaction key or a signature key. One keeps the old key alive for 24 hours. The other kills it at once. Picking the right one, and updating the store and its webhooks in the right order, decides whether a cleanup costs a few minutes of checkout or a day of missed payment notifications.

What each Authorize.Net credential does

Authorize.Net support article KA-07619 describes four values in the API Credentials and Keys section of the Merchant Interface.

  • API Login ID. Identifies the account to the gateway on every request. It cannot be used to sign in to the Merchant Interface.
  • Transaction Key. A 16-character value that authenticates transaction requests alongside the login ID. It is shown only once, when it is generated.
  • Signature Key. A 128-character hexadecimal value used to build HMAC-SHA512 hashes, which are keyed fingerprints that prove a message came from Authorize.Net. It signs webhook notifications and the SHA2 hash in transaction responses, and it was used by the older Server Integration Method (SIM) and Direct Post Method (DPM). Developers convert it to binary before use.
  • Public Client Key. Used by Accept.js and other Accept products in browser or app code. Authorize.Net says it is not used to start transactions and can safely sit in a website.

The transaction key and the signature key are the two secrets worth replacing after a compromise. The Public Client Key is designed to be visible, and the support article does not describe a way to change the API Login ID.

The 24-hour overlap and the immediate cutoff

In the current Merchant Interface (version 2.0), the path is Account, then Account and API Settings, then API Credentials and Keys under Security Settings. Choosing Generate new key under the transaction or signature key brings up two choices for the existing key, Expire in 24 hours or Expire now, followed by a one-time passcode sent by email. The classic interface uses a checkbox labeled Disable Old Transaction/Signature Key Immediately and a PIN.

Leaving the old key active gives the store a day to paste the new one into its plugin without a single failed charge. Authorize.Net’s guide to generating a new transaction key says the immediate option should be used “only if you need to stop transaction processing immediately, for example, in case your transaction key is compromised.” The overlap is meant for routine rotation, such as a developer leaving or a scheduled credential change.

A store that has found an attacker in WordPress fits the documentation’s own example. With the 24-hour option, whoever holds the stolen key keeps working access for another day. The cost of the immediate option is that checkout fails from the moment the old key dies until the new one is saved in the plugin, so the new key should be copied and ready to paste before the store owner confirms the change.

Clean the site before the new key goes in

Rotating the key on a site that still has a backdoor accomplishes little. A new transaction key saved into the same database can be read the same way the old one was. TeamUpdraft has said that one leftover plugin created a fresh administrator account after a site had already been disconnected from UpdraftCentral, which is the kind of foothold that would survive a password reset. The order that follows from that is to remove the unknown plugins and accounts, patch the hole, and then generate the new key.

Stores that cannot finish cleanup quickly still have a reason to cut off the old key at once, even if it means pausing card payments. A stopped checkout is visible and temporary. Requests sent with a stolen key look like the store’s own traffic.

Rotating the signature key without losing webhooks

The signature key carries its own risk. Authorize.Net’s page on generating signature keys warns that if the key expires immediately, “your webhooks stop working immediately,” and tells users to pick that option only for an urgent need such as a security issue. With the 24-hour option, the page says to update webhook authentication within that window to avoid interruptions.

Webhooks are the notifications Authorize.Net posts to a store’s server when a payment is captured, refunded or voided, a subscription charges or fails, or a fraud filter holds or releases an order. According to the webhooks developer guide, each one carries an X-ANET-Signature header with an HMAC-SHA512 hash of the message body built from the signature key, and the receiving code should reject a notification whose hash does not match. KA-07619 adds that during the 24-hour overlap the previous key is still used for hash and response validation, including the SHA2 field on transaction responses.

The guide also explains what happens to notifications that fail. Authorize.Net retries up to 10 times until it gets an HTTP 200 response, three times at three-minute intervals, three more at eight-hour intervals and four at 48-hour intervals. If every attempt fails, it treats the URL as out of service, sets the webhook to inactive and stops sending to it. A store that rotates the signature key and forgets to update its verification code could see subscription and refund events pile up for days before the endpoint goes quiet.

Steps for a key change after a compromise

Based on Authorize.Net’s documentation, a store replacing both secrets after an incident can work through these steps.

  • Remove the attacker’s access first, including unknown administrators, hidden plugins and modified files.
  • Generate a new transaction key with Expire now, copy it to a secure place and save it in the payment plugin right away.
  • Run a small test charge and void it to confirm the plugin is working with the new key.
  • Generate a new signature key and update every place that checks it, including the webhook endpoint and any code that validates the SHA2 hash on transaction responses. Choose Expire now if the old key may have been copied.
  • Update scripts that manage webhooks through the Webhooks REST API, which uses the API Login ID and Transaction Key for HTTP Basic authentication.
  • Check the webhook list for anything set to inactive, then call GET /rest/v1/notifications with deliveryStatus=Failed and a date range to find events that never arrived.
  • Review recent transactions and refunds in the Merchant Interface for activity the store did not initiate.

Stores still running SIM or DPM forms have one more reason to move. Authorize.Net has listed those methods as obsolete and in the process of being phased out, and both depend on the same signature key a store is now replacing.

Why a new password is not enough

Resetting WordPress passwords locks an attacker out of the dashboard, but it does nothing to Authorize.Net credentials already copied from the site. Authorize.Net’s own guidance reserves the immediate cutoff for a compromised key, which is the situation a breached store is in, and accepts a short checkout outage as the price. The signature key needs the same care, because cutting it off without updating the webhook code can leave refunds, subscription charges and fraud holds undelivered until the retries run out. Cleaning the site first, replacing both keys, testing a charge and pulling failed notifications from the history API covers the gap that a password change leaves open.

Sources