# Rotating all integration and user API keys on compromised instance

**URL:** <https://forum.ghost.org/t/rotating-all-integration-and-user-api-keys-on-compromised-instance/62811>\
**Category:** Using Ghost\
**Created:** [May 7, 2026, 4:05pm UTC](https://forum.ghost.org/t/rotating-all-integration-and-user-api-keys-on-compromised-instance/62811 "2026-05-07T16:05:26Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jameson\_Lopp](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/jameson_lopp/32/40416_2.png) [@Jameson\_Lopp](https://forum.ghost.org/u/Jameson_Lopp)\
**Post date:** [May 7, 2026, 4:05pm UTC](https://forum.ghost.org/t/rotating-all-integration-and-user-api-keys-on-compromised-instance/62811/1 "2026-05-07T16:05:26Z")

</div>

Hi all,

I recently posted about my [self hosted instance being compromised](https://forum.ghost.org/t/if-you-are-on-ghost-6-19-1-you-really-need-to-update/62706) via an unpatched security vulnerability.

I upgraded my instance, removed the fake user the attacker created, and rotate my admin API keys.

However, a week later the instance was compromised again and it appears that the “zapier” integration (that I never even activated) API key was used to deface all of my historical posts and inject malware again.

I don’t see any obvious way to rotate all of the API keys for default integrations; what are my options?

---

<div class="post-metadata">

**Author:** ![Jameson\_Lopp](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/jameson_lopp/32/40416_2.png) [@Jameson\_Lopp](https://forum.ghost.org/u/Jameson_Lopp)\
**Post date:** [May 7, 2026, 7:58pm UTC](https://forum.ghost.org/t/rotating-all-integration-and-user-api-keys-on-compromised-instance/62811/2 "2026-05-07T19:58:08Z")

</div>

Here’s what I did to clean up as much as I could find from mysql:

delete from sessions; // wipe out sessions for previously created malicious users  
delete from api\_keys where user\_id IS NULL; // wipe out all default integration api keys  
delete from tokens;  
select id from settings where ‘key’ = “mailgun\_api\_key”;  
update settings set value = “REDACTED” where id = MAILGUN\_API\_KEY\_ID;  
update posts set codeinjection\_foot = NULL; // remove malicious code injections

---

<div class="post-metadata">

**Author:** ![Cathy\_Sarisky](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/cathy_sarisky/32/25750_2.png) [@Cathy\_Sarisky](https://forum.ghost.org/u/Cathy_Sarisky)\
**Post date:** [May 7, 2026, 8:00pm UTC](https://forum.ghost.org/t/rotating-all-integration-and-user-api-keys-on-compromised-instance/62811/3 "2026-05-07T20:00:25Z")

</div>

You also need to regenerate your Zapier token - in /ghost \> settings \> integrations, click ‘configure’ next to zapier and regenerate the token

---

<div class="post-metadata">

**Author:** ![Jameson\_Lopp](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/jameson_lopp/32/40416_2.png) [@Jameson\_Lopp](https://forum.ghost.org/u/Jameson_Lopp)\
**Post date:** [May 7, 2026, 8:32pm UTC](https://forum.ghost.org/t/rotating-all-integration-and-user-api-keys-on-compromised-instance/62811/4 "2026-05-07T20:32:08Z")

</div>

Upon further review, it looks like there are several other internal service keys such as the Ghost Internal Frontend, Ghost Backup, and Ghost Scheduler keys that need to be regenerated, but I don’t see a way to do so in the UI…

My front end signup form is currently broken because of the missing Frontend key.

---

<div class="post-metadata">

**Author:** ![Cathy\_Sarisky](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/cathy_sarisky/32/25750_2.png) [@Cathy\_Sarisky](https://forum.ghost.org/u/Cathy_Sarisky)\
**Post date:** [May 7, 2026, 8:55pm UTC](https://forum.ghost.org/t/rotating-all-integration-and-user-api-keys-on-compromised-instance/62811/5 "2026-05-07T20:55:15Z")

</div>

I don’t know if there is one. Hopefully someone from Ghost will weigh in.

You might also consider doing a content export, members export, and then loading that into a fresh ghost install, along with copying over /content and the theme files. That’s lossy (you’d lose member analytics and comments), but would get your ghost into a state with fresh keys.

---

<div class="post-metadata">

**Author:** ![Jameson\_Lopp](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/jameson_lopp/32/40416_2.png) [@Jameson\_Lopp](https://forum.ghost.org/u/Jameson_Lopp)\
**Post date:** [May 7, 2026, 8:56pm UTC](https://forum.ghost.org/t/rotating-all-integration-and-user-api-keys-on-compromised-instance/62811/6 "2026-05-07T20:56:56Z")

</div>

This seems to work:

insert into api\_keys set id=RANDOM\_24\_BYTE\_HEX,type =“content”,secret=“RANDOM\_64\_BYTE\_HEX”,integration\_id=(select id from integrations where name =“Ghost Internal Frontend”),created\_at=NOW();

---

<div class="post-metadata">

**Author:** ![jesse\_nz](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/jesse_nz/32/37780_2.png) [@jesse\_nz](https://forum.ghost.org/u/jesse_nz)\
**Post date:** [May 11, 2026, 12:31pm UTC](https://forum.ghost.org/t/rotating-all-integration-and-user-api-keys-on-compromised-instance/62811/7 "2026-05-11T12:31:21Z")

</div>

My site got hit too, via the Zapier integration. Have upgraded to v6, but wondering if Ghost should add some sort of CLI command that could regenerate all the internal keys that could have been compromised.

---

<div class="post-metadata">

**Author:** ![Jameson\_Lopp](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/jameson_lopp/32/40416_2.png) [@Jameson\_Lopp](https://forum.ghost.org/u/Jameson_Lopp)\
**Post date:** [May 11, 2026, 5:49pm UTC](https://forum.ghost.org/t/rotating-all-integration-and-user-api-keys-on-compromised-instance/62811/8 "2026-05-11T17:49:12Z")

</div>

A CLI command to rotate all API keys and other credentials that could have been compromised would be quite helpful. It’s incredibly onerous to have to manually sift through the database and code to try to find all of the sensitive data.

---

<div class="post-metadata">

**Author:** ![vikaspotluri123](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/vikaspotluri123/32/24_2.png) [@vikaspotluri123](https://forum.ghost.org/u/vikaspotluri123)\
**Post date:** [May 12, 2026, 4:53am UTC](https://forum.ghost.org/t/rotating-all-integration-and-user-api-keys-on-compromised-instance/62811/9 "2026-05-12T04:53:01Z")

</div>

Looks like there’s some explorations into adding supporting this:

> <https://github.com/TryGhost/Ghost/pull/27820>
>
> ref https://linear.app/ghost/issue/BER-3628/danger-zone-rotate-api-keys
> ref http…s://linear.app/ghost/issue/BER-3629/danger-zone-reset-all-staff-passwords
> 
> \## Problem
> 
> After a site is upgraded following a security event, there's no admin UI for:
> \- Rotating all API keys in one action — owners would have to visit each integration manually
> \- Forcing a password reset across all staff users — owners would have to log out and reset each user manually
> 
> Neither action exists today, which is exactly the post-upgrade hygiene the project description calls out.
> 
> \## Solution
> 
> Two new entries in Settings → Advanced → Danger Zone. Each opens a confirmation modal that requires typing the site URL — the same destructive-action gate the project description suggested.
> 
> \- \*\*Rotate API keys\*\* (admin-authenticated): iterates every API key and refreshes its secret in a single transaction. Success state reports the count rotated with a reminder that integrations may need updating.
> \- \*\*Reset all staff passwords\*\* (owner-only): locks every Owner/Admin/Editor/Author user, triggers the existing password-reset email flow per user, and invalidates every active session including the triggering owner's own. The triggering owner is signed out and must reset their own password.
> 
> Both actions write to the audit log. Both are gated behind a host-settings flag (default visible) so managed hosts can hide them in their customer-facing UI — the gating mechanism is a TODO awaiting BER-3633 to formalize the config key.
> 
> Also includes scripts/build-e2e-image.sh, a local helper that mirrors the CI flow for producing \`ghost-e2e:local\` so developers can run e2e in build mode without \`pnpm dev\` and the host-side watchers.
