Guide · Backend
Docker Hub's October 2026 GhostPat Flaw Explained: When a Token Changes Owners
18 min readUpdated By Saket Bhatnagar
Researched and drafted with AI, reviewed and edited by Saket Bhatnagar.
In short
- The Docker Hub GhostPat vulnerability is tracked as CVE-2026-105445, a public ID for a security flaw. It let whoever held an access token (a long password that tools use) act as another Docker Hub user at the registry, the image store.
- From 26 August 2024, converting a personal account into an organisation (a shared team space) moved its personal access tokens to the new owner. These PATs are long passwords for tools, and their secrets did not change.
- Docker fixed Docker Hub on 30 September 2026 and switched off transferred PATs on 8 October, unless the account holder opted out. The CVE record scores it 9.4 out of 10, critical.
- Docker says it found no evidence of exploitation, and users it did not email need not act. A token review is still good hygiene: revoke unknown tokens, set expiry dates and give machines organisation-owned tokens.
- Beginners can stop after the section on what to do now. Engineers get the rest: a tested toy model of why an owner change is not rotation, token limits, activity-log retention and an interview frame.
What goes wrong when a Docker Hub account becomes an organisation?
From 26 August 2024 until the fix on 30 September 2026, the account's personal access tokens (PATs), long passwords that tools use, moved to the new owner and kept working. Whoever already held a token's secret could then act as that owner at the registry.
This flaw is the Docker Hub GhostPat vulnerability, a name given by the researchers who reported it. Docker tracks it as CVE-2026-105445. This guide explains what happened, what Docker changed and how to check your own tokens.
Picture a common setup. A small team keeps its app's container images, packaged copies of the app that servers download and run, under one personal Docker Hub account. The setup is made up, but the problem is real. The build server logs in with a personal access token called ci-deploy.
Later the team converts that account into an organisation so several engineers can share it. Conversion asks for a new owner, and they type their CTO's own Docker ID. Before the fix, ci-deploy quietly became the CTO's token.
Its secret, already copied onto the build server, now acted as the CTO at the registry, within the token's permission level. That reached every repository and organisation she could reach. Nobody was told.
Which words do you need before learning how GhostPat works?
- Registry: the server that stores container images. Docker Hub runs one, and docker push and docker pull talk to it.
- Docker ID: your Docker Hub username.
- Personal access token (PAT): a long random password for tools. It belongs to one person's account and acts as that person.
- Token secret: the string you paste in. Like a physical key, whoever holds it can use it.
- Permission level: how much a PAT may do with repositories. Levels run from Repo Public Read-only, the default, up to Repo Read, Write, Delete.
- Organisation: a shared Docker Hub space run by its owners. Docker's screens spell it organization.
- Organisation access token (OAT): a token owned by the organisation itself, made for automation. Its scopes list exactly what it may do, per repository and in the organisation.
- Rotation means replacing a secret with a new one and killing the old one. Revocation means switching a token off for good.
- Activity log: an organisation's record of events, such as image pushes and token changes.
What is the Docker Hub GhostPat vulnerability?
The Docker Hub GhostPat vulnerability is a flaw in account-to-organisation conversion, tracked as CVE-2026-105445. A CVE is a public ID for a known security flaw. Conversion re-assigned the account's PATs to the new owner by editing each token's owner record. It never rotated or revoked the secret.
Docker's advisory says the named owner was not asked to confirm and was not notified. So someone could convert an account they controlled, name another user as owner and keep a token that now acted as that user.
The CVE record, published on 13 October 2026, scores it 9.4 on CVSS 4.0, a 0 to 10 severity scale, and labels it critical. It files the bug under CWE-266, incorrect privilege assignment. In plain words, the system gave power to the wrong account.
How did a converted account hand over a working token?
Every token has two separate parts: a record that says who owns it, and a secret that decides who can use it. Conversion changed the record and left the secret alone. The diagram shows both paths, before and after the fix.
What conversion did to a PAT, before and after the fix
Drag to exploreFollow the Before the fix branch: only the owner record changed, so the old secret now spoke for the new owner. No step on that branch reached the new owner.
Diagram connections:
- Personal account to Conversion starts (Convert)
- Conversion starts to Before or after the fix? (Check date)
- Before or after the fix? to Owner record edited (Before the fix)
- Owner record edited to Old secret still active (Secret unchanged)
- Before or after the fix? to PATs stop working (After the fix)
- PATs stop working to New owner creates an OAT (Replace)
- Personal account: Owns PAT ci-deploy; secret copied to a server
- Conversion starts: New owner entered as a Docker ID
- Before or after the fix?: Fix live on 30 Sep 2026, 19:10 UTC
- Owner record edited: PAT now listed under the new owner
- Old secret still active: Holder logs in to the registry as the new owner
- PATs stop working: Old secrets from that account are dead
- New owner creates an OAT: Fresh secret, shown once to its creator
The researchers say they tested only with consenting test accounts. They report that the receiving account's inbox stayed empty each time.
Picture a hotel desk that moves your key card from your booking onto another guest's booking, without re-coding the card. Your card now opens their room, and nobody tells them. The booking is the owner record; the card is the secret.
Where the picture breaks: a key card opens one room. A transferred PAT reached every repository and organisation the new owner could reach, within its permission level.
What could someone do with a transferred token?
Within its permission level, a transferred token acted as the new owner at the registry. Docker says it gave no access to the Docker Hub website and could not change the password, email address or two-factor settings. Docker treated this as a software supply-chain risk, because a pushed image carries a trusted name.
| Action | Possible? | Why it matters |
|---|---|---|
| Push images to the new owner's repositories | Yes, at Repo Read & Write level or above | A poisoned image reaches everyone who pulls that name |
| Pull private images | Yes, at Repo Read-only level or above | Code and settings inside images could leak |
| Delete images | Yes, at Repo Read, Write, Delete level | Deploys that pull a deleted tag fail |
| Act in organisations the new owner belongs to | Yes, within the same permission level | One token reached more than one team |
| Use the Docker Hub website as the new owner | No | Docker says the token worked at the registry level, not on the website |
| Change password, email or two-factor settings | No | The account itself could not be taken over |
What did Docker find and change from September to October 2026?
Docker says it found no evidence that the flaw was exploited. It listed every conversion since 26 August 2024 and examined every push made with a transferred token, about 304,000 in all. Each landed in the converted organisation's or the new owner's own repositories.
Logs show when a token is used, not that it exists. A transferred token that was never used leaves no trace, so Docker treated every transferred PAT as possibly exposed and switched them off. As of 19 October 2026, the advisory gives no count of affected users or tokens.
The timeline, August 2024 to October 2026
| Date and source time | India time (IST) | What happened |
|---|---|---|
| 26 Aug 2024, 20:33 UTC | 27 Aug 2024, 02:03 | Conversion starts moving PATs to the new owner |
| 30 Sep 2026, 11:40 am US Eastern | 30 Sep, 21:10 | Report reaches Docker's security team |
| 30 Sep 2026, about 19:10 UTC | 1 Oct, about 00:40 | Fix live on Docker Hub, about 3.5 hours after the report |
| 2 Oct 2026, 5:30 pm US Eastern | 3 Oct, about 03:00 | Emails to exposed users and their organisation owners |
| 8 Oct 2026, 3:45 pm US Eastern | 9 Oct, about 01:15 | Transferred PATs switched off, except where the account holder opted out |
| 12 Oct 2026 | 12 Oct | Docker's advisory and the researchers' write-up go public |
| 13 Oct 2026, 17:35 UTC | 13 Oct, 23:05 | CVE record published with a CVSS 4.0 score of 9.4 |
What changed in the product
- Conversion no longer transfers PATs. Docker's conversion page now says the account's PATs stop working, and the new owner should create an OAT. It also says the new owner now receives a notification email.
- Docker commits to asking a user for consent before naming them an organisation owner. As of 19 October 2026, the conversion page describes no consent step.
- It also commits to an auditable history of every token ownership change, and to reviewing other flows that change who owns a credential.
Why is changing a token's owner not the same as rotating it?
Changing the owner is not rotation, because the secret grants access, not the name on the record. Rotation issues a new secret and kills the old one. An owner change only edits a label.
A safe transfer does three things: it switches off the old secret, asks the new owner to agree and writes an audit record. The toy model below runs both versions of conversion against the same copied secret.
import secrets
def new_token(owner):
return {"owner": owner, "secret": secrets.token_urlsafe(24), "active": True}
def login(store, secret):
for t in store.values():
if t["active"] and t["secret"] == secret:
return t["owner"]
return None
def convert_buggy(store, token_id, new_owner, audit):
store[token_id]["owner"] = new_owner # only the record changes
def convert_safe(store, token_id, new_owner, audit, owner_agreed=True):
if not owner_agreed:
raise PermissionError("new owner must confirm first")
store[token_id]["active"] = False # old secret stops working
audit.append((token_id, store[token_id]["owner"], new_owner))
for convert in (convert_buggy, convert_safe):
store = {"ci-deploy": new_token("team-account")}
held = store["ci-deploy"]["secret"] # copy already on the build server
audit = []
convert(store, "ci-deploy", "cto-id", audit)
print(convert.__name__, "| old secret logs in as:", login(store, held), "| audit:", audit)Run it with python3; it was tested on Python 3.13.16. You should see two lines:
convert_buggy | old secret logs in as: cto-id | audit: []
convert_safe | old secret logs in as: None | audit: [('ci-deploy', 'team-account', 'cto-id')]What just happened? In the buggy run, the copy on the build server logs in as cto-id, and the audit list stays empty. In the safe run, the same copy fails, and the trail records who moved what.
What should Docker Hub users do now?
Docker's advisory says users it did not email on 2 October were not exposed and need not act. A short token review is still worth doing, because a token with no expiry date stays usable until someone switches it off.
Check for Docker's 2 October email
Its subject was Docker Hub Vulnerability Identified & Resolved, and in India it arrived early on 3 October. It listed affected tokens by description and creation date.
Open your token list
Sign in to Docker Home, select your avatar, then Account settings, then Personal access tokens. Note each token's permission level, status, created date and last used date.
Revoke or narrow what you cannot explain
Deactivate or delete tokens you do not recognise or no longer use. For a token you keep, you can lower its permission level later, but not change its expiry.
Look for strange organisations
Check the account switcher for organisations you do not remember joining. That can mean someone named you as an owner.
Move automation to OATs
Give each build server an organisation access token limited to the repositories and scopes it needs, with an expiry date.
Read the activity log
Organisation owners open Docker Home, select the organisation, then Activity. Tag Pushed events, meaning a new image version arrived, can name the PAT or OAT that pushed it.
After moving a build job to an OAT, check the login from that server. With an OAT, the username is the organisation name. The secret comes from standard input, so it is never typed on the command line.
# On the build server; DOCKER_OAT holds the organisation access token
printf '%s' "$DOCKER_OAT" | docker login --username YOUR_ORG_NAME --password-stdin
echo "exit code: $?"
docker logoutA working OAT prints Login Succeeded, then exit code: 0. A switched-off or wrong secret prints an error and a non-zero exit code. In a build script that stops at the first error (bash set -e), a failed login ends the job before the echo line. We ran this with Docker CLI 29.8.2 against a local test registry, not Docker Hub, so Hub's error wording may differ.
In the team's case, the CTO's email listed ci-deploy, and Docker switched it off on 8 October. The team created an OAT for its three app repositories with a 90-day expiry. The build was green again within 20 minutes (made up).
Beginners can stop here. The rest is for engineers: how the two token types differ, how to review tokens by rule and how to tell this story in an interview.
Should you use a personal or an organisation access token?
Use a PAT when a person works by hand, and an OAT when a machine works for the team. A PAT acts as you wherever you have access. An OAT acts only for its organisation, on the repositories you list.
| Question | Personal access token (PAT) | Organisation access token (OAT) |
|---|---|---|
| Who owns it? | One person's account | The organisation; owners, or members with the right custom role, manage it |
| Tied to a person? | Yes, it acts as that person | No, it is not tied to any user account |
| How narrow can access be? | One permission level; it cannot be limited to a single repository | Scopes set per repository, on up to 50 repositories |
| Login username | Your Docker ID | The organisation name |
| Plan needed | Any individual Docker account | Docker Team or Docker Business |
| Works with Docker Desktop? | Yes | No; it also does not work with Image Access Management |
| Default expiry | None | None |
| How many? | The docs state no maximum for tokens you create | 10 per organisation on Team, 100 on Business; expired and deactivated ones count until deleted |
The old ci-deploy PAT could act as the CTO in every organisation she belongs to. The new OAT can touch only the three app repositories, so a leak stops there.
The team's setup after the fix
Drag to exploreMachines use an organisation-owned token with an expiry; people keep their own PATs. Pushes show up in the activity log, which can name the token used.
Diagram connections:
- Build server to OAT: team-ci (Logs in with)
- OAT: team-ci to Team organisation (Push images)
- Team organisation to App servers (Pull images)
- Team organisation to Activity log (Push events)
- CTO's laptop to Team organisation (Pull to test)
- Build server: Builds a new image when code is merged
- OAT: team-ci: Owned by the organisation; 3 repos; 90-day expiry
- Team organisation: Holds the app's three image repositories
- App servers: Pull new images and run them
- Activity log: Tag Pushed events can name the token used
- CTO's laptop: Her own read-only PAT for Docker Desktop
How do you review Docker Hub tokens without missing one?
Treat the token list as an inventory and flag risky tokens by rule, not by memory. The script below checks a list copied by hand from the token page, using fields Docker shows there.
from datetime import date
today = date(2026, 10, 19)
tokens = [ # copied by hand from Account settings, Personal access tokens
{"name": "laptop-cli", "level": "Repo Read-only",
"last_used": date(2026, 10, 18), "expires": date(2027, 1, 10)},
{"name": "old-test", "level": "Repo Read & Write",
"last_used": date(2025, 6, 2), "expires": None},
{"name": "release-bot", "level": "Repo Read, Write, Delete",
"last_used": None, "expires": None},
]
for t in tokens:
problems = []
if t["expires"] is None:
problems.append("no expiry")
if t["last_used"] is None:
problems.append("never used")
elif (today - t["last_used"]).days > 90:
problems.append("unused for 90+ days")
if "Write" in t["level"]:
problems.append("can push: give machines an OAT")
print(t["name"], "->", ", ".join(problems) or "looks fine")What just happened? Tested on Python 3.13.16, it prints three lines. The laptop token looks fine. The other two are flagged for no expiry and push rights, and for being unused or never used.
laptop-cli -> looks fine
old-test -> no expiry, unused for 90+ days, can push: give machines an OAT
release-bot -> no expiry, never used, can push: give machines an OATThe 90-day cut-off is our choice, not a Docker rule. Pick one that matches how often your jobs run.
What the activity log can and cannot tell you
Docker Home keeps organisation activity logs for 90 days and lets you query up to 30 days at a time. The Docker Hub audit logs API covers about the same window, the last 3 months, up to 31 days per request, which suits scripts. Docker's page describes no way to see older events. So on 19 October 2026, your own logs reach back only to about late July 2026, not to August 2024. These limits are from Docker's docs as of 19 October 2026.
Activity logs need a Docker Team or Business plan. Event descriptions can name the Docker username, PAT or OAT behind an action. They cannot show a token that was never used, which is why Docker switched off every transferred PAT.
How do you explain the Docker Hub GhostPat vulnerability in a system design interview?
Tell it as a story about credential ownership. Interviewers want to see that you separate who owns a secret from who holds it.
State the bug in one line
Conversion changed a token's owner record but kept its secret, so whoever held the secret could act as the new owner.
Name the missing checks
No consent, no notification and no rotation. Consent or rotation would have blocked misuse, and notification would have let the new owner spot it.
Describe a safe transfer
Revoke old secrets, ask the receiver to confirm, issue new credentials only to them and write an audit record.
Limit the damage from a leak
Give machines scoped tokens with expiry dates, so a leak reaches a few repositories for a short time.
Show how you would spot misuse
Log which token pushed each image and alert on pushes from unfamiliar tokens. Admit the gap: an unused token leaves no log.
Close with the trade-off
Forced deactivation breaks running jobs, as it did for the team's build. Give owners notice, an opt-out window and a clear path to a new token.
Questions people ask
- What is GhostPat in Docker Hub?
- GhostPat is the researchers' name for CVE-2026-105445, a Docker Hub flaw in account-to-organisation conversion. Conversion moved personal access tokens to the new owner without changing their secrets, so whoever held a secret could act as that owner at the registry. Docker fixed it on 30 September 2026.
- Was the Docker Hub GhostPat vulnerability exploited?
- Docker says it found no evidence of exploitation after examining about 304,000 pushes made with transferred tokens. Each push landed in the converted organisation's or the new owner's own repositories. Unused tokens leave no trace in logs, so Docker still switched off every transferred PAT unless the account holder opted out.
- I got no email from Docker. Am I affected?
- Docker's advisory says users who did not get the 2 October email were not exposed, and neither were members of organisations they administer. You need not act for this flaw. A ten-minute token review is still worth doing: revoke tokens you cannot explain and add expiry dates.
- Do I need to update Docker Desktop or the Docker CLI?
- No. The fix was deployed on Docker Hub itself, which is a hosted service, and the CVE record lists only Docker Hub as affected. Your job is to review your personal access tokens, revoke any you do not recognise and move automation to organisation access tokens.
- Why did my Docker Hub token stop working on 8 October 2026?
- If it stopped on 8 October and was listed in Docker's 2 October email, it was a token that moved during an account conversion. Docker switched those off on 8 October 2026 at 3:45 pm US Eastern, early on 9 October in India, unless the account holder opted out. Tokens also stop when they expire or are revoked. Create a new organisation access token or PAT and update your build jobs.
- What is the CVSS score of CVE-2026-105445?
- The CVE record gives it 9.4 under CVSS 4.0 and labels it critical. Its vector says the attack works over the network with low complexity, needs only a normal account and needs no action from the victim.
- What happens to tokens when you convert a Docker Hub account now?
- Since the 30 September 2026 fix, the account's personal access tokens stop working when it becomes an organisation. Docker's conversion page tells the new owner to create an organisation access token instead. Conversion is also permanent, so plan new tokens before you start.
Sources and further reading
- Docker Hub security advisory for CVE-2026-105445: timeline, impact, investigation and fixes (Docker blog, 12 October 2026)
- CVE-2026-105445 record: CVSS 4.0 score and vector, CWE-266, affected dates (CVE Program, published 13 October 2026)
- GhostPAT technical write-up by Peter Molnar and Krisztian Hozak of mptrdev.com (12 October 2026)
- Convert an account into an organization: PATs stop working after conversion (Docker Docs)
- Create and manage personal access tokens: expiry options and token list (Docker Docs)
- Organization access tokens: plans, 50-repository limit, expiry, Docker Desktop limits (Docker Docs)
- Access token reference: PAT permission levels and OAT scopes (Docker Docs)
- Activity logs: 90-day retention, 30-day queries and the audit logs API (Docker Docs)
Related guides
- TanStack npm Hack Explained: What JavaScript Developers Must Do NowBackend · 18 min read
- GitHub's November 2026 App Token Cutoff Explained: Treat Tokens as OpaqueBackend · 13 min read
- Vercel’s April 2026 Security Breach, Explained: The OAuth Supply-Chain Attack Every Engineering Team Should StudyBackend · 18 min read