- Status Closed
-
Assigned To
cbay - Private
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:
- 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.
Loading...
Available keyboard shortcuts
- Alt + ⇧ Shift + l Login Dialog / Logout
- Alt + ⇧ Shift + a Add new task
- Alt + ⇧ Shift + m My searches
- Alt + ⇧ Shift + t focus taskid search
Tasklist
- o open selected task
- j move cursor down
- k move cursor up
Task Details
- n Next task
- p Previous task
- Alt + ⇧ Shift + e ↵ Enter Edit this task
- Alt + ⇧ Shift + w watch task
- Alt + ⇧ Shift + y Close Task
Task Editing
- Alt + ⇧ Shift + s save task
Hello,
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