Scary "Grampus" Jerry 👻 on Nostr: There are major account take-over problems happening right now on mastodon instances ...
There are major account take-over problems happening right now on mastodon instances - all appearances are that the actor is using stolen passwords, probably from malware running on desktops. I've suspended hundreds of compromised accounts over the past 48 hours, but only two on mine.
If you run a mastodon instance, here is a postgres query I use to randomize the passwords of accounts that have been inactive for 6 months or more. It also removes logged in sessions. This doesn't lock people out, just makes them perform a password reset. Yes, I wish I didn't have to do this, but here we are. I hope it helps someone else.
BEGIN;
CREATE TEMP TABLE dormant_batch ON COMMIT DROP AS
SELECT u.id AS user_id
FROM users u
WHERE COALESCE(u.current_sign_in_at, u.created_at) < now() - interval '6 months'
AND NOT u.otp_required_for_login
AND NOT EXISTS (SELECT 1 FROM webauthn_credentials w WHERE w.user_id = u.id)
AND NOT EXISTS (SELECT 1 FROM oauth_access_tokens t
WHERE t.resource_owner_id = u.id
AND t.revoked_at IS NULL
AND t.last_used_at > now() - interval '6 months');
UPDATE users u
SET encrypted_password = '$2a$10$' || left(replace(gen_random_uuid()::text || gen_random_uuid()::text, '-', ''), 53),
updated_at = now()
FROM dormant_batch b
WHERE u.id = b.user_id;
UPDATE oauth_access_tokens t SET revoked_at = now()
FROM dormant_batch b
WHERE t.resource_owner_id = b.user_id AND t.revoked_at IS NULL;
DELETE FROM session_activations s
USING dormant_batch b
WHERE s.user_id = b.user_id;
SELECT COALESCE(y::text, 'total') AS last_seen_year, count(*) AS locked
FROM (SELECT date_part('year', COALESCE(u.current_sign_in_at, u.created_at))::int AS y
FROM dormant_batch b JOIN users u ON u.id = b.user_id) s
GROUP BY ROLLUP (y) ORDER BY y NULLS LAST;
COMMIT;
Published at
2026-10-17 15:50:19 UTCEvent JSON
{
"id": "8ebea3494c443c9cec1552e93f7e6b46d97ee171f8c7d880ba69c1279ae9a439",
"pubkey": "a69cac96fd8b825a67e39aa0aa526220f64b5fff88d3e49d7cfa45d54d3ea842",
"created_at": 1792252219,
"kind": 1,
"tags": [
[
"proxy",
"https://infosec.exchange/users/jerry/statuses/117457041484080186",
"activitypub"
],
[
"client",
"Mostr",
"31990:6be38f8c63df7dbf84db7ec4a6e6fbbd8d19dca3b980efad18585c46f04b26f9:mostr",
"wss://relay.ditto.pub"
]
],
"content": "There are major account take-over problems happening right now on mastodon instances - all appearances are that the actor is using stolen passwords, probably from malware running on desktops. I've suspended hundreds of compromised accounts over the past 48 hours, but only two on mine. \n\nIf you run a mastodon instance, here is a postgres query I use to randomize the passwords of accounts that have been inactive for 6 months or more. It also removes logged in sessions. This doesn't lock people out, just makes them perform a password reset. Yes, I wish I didn't have to do this, but here we are. I hope it helps someone else.\n\nBEGIN;\n\nCREATE TEMP TABLE dormant_batch ON COMMIT DROP AS\nSELECT u.id AS user_id\nFROM users u\nWHERE COALESCE(u.current_sign_in_at, u.created_at) \u003c now() - interval '6 months'\n AND NOT u.otp_required_for_login\n AND NOT EXISTS (SELECT 1 FROM webauthn_credentials w WHERE w.user_id = u.id)\n AND NOT EXISTS (SELECT 1 FROM oauth_access_tokens t\n WHERE t.resource_owner_id = u.id\n AND t.revoked_at IS NULL\n AND t.last_used_at \u003e now() - interval '6 months');\nUPDATE users u\nSET encrypted_password = '$2a$10$' || left(replace(gen_random_uuid()::text || gen_random_uuid()::text, '-', ''), 53),\n updated_at = now()\nFROM dormant_batch b\nWHERE u.id = b.user_id;\n\nUPDATE oauth_access_tokens t SET revoked_at = now()\nFROM dormant_batch b\nWHERE t.resource_owner_id = b.user_id AND t.revoked_at IS NULL;\n\nDELETE FROM session_activations s\nUSING dormant_batch b\nWHERE s.user_id = b.user_id;\n\nSELECT COALESCE(y::text, 'total') AS last_seen_year, count(*) AS locked\nFROM (SELECT date_part('year', COALESCE(u.current_sign_in_at, u.created_at))::int AS y\n FROM dormant_batch b JOIN users u ON u.id = b.user_id) s\nGROUP BY ROLLUP (y) ORDER BY y NULLS LAST;\n\nCOMMIT;",
"sig": "0857a61dc09fae79535e114b7e2c0a310c5e0b901526b06698b64445859c1404f95b84f129f1031afed9d070355532a77817ef2bed3bc0f2a6d8f70242b07a9a"
}