Docker Desktop Extensions

A threat model, not a campaign · roster measured 18 September 2026 against all 50 listed extensions

What this is. No malicious Docker Desktop extension has been publicly reported — not in Docker's Extensions Marketplace, not sideloaded — as of 18 September 2026. Docker's own statement, from September 2024, is that "No existing extensions exploiting the vulnerabilities were found in the Extensions Marketplace", and nothing published since says otherwise. So this page is not a list of campaigns with names and hashes, as the VS Code and Hugging Face pages are. It is three things: what Docker itself documents an extension can do, what Docker itself has fixed and changed about extensions — up to pausing new Marketplace submissions on 16 June 2026 — and what our 11-check roster (D1–D11) reads and found when run against every one of the 50 extensions the Marketplace lists: 50 PASS, 0 REVIEW, 0 BLOCK, with no image pulled. Neither the absence of a reported incident nor the 50 passes is a guarantee — see "What this doesn't mean".

What an extension can do, in Docker's words

A Docker Desktop extension is a Docker Hub image. Its metadata.json declares up to three parts: a ui (a dashboard tab), a vm backend — "a backend service that runs inside the Desktop VM", defined by an image or a compose file — and host binaries, "executables that Docker Desktop copies on the host". Docker's SDK security page, added in October 2025, states the consequence without softening it:

"Extensions are executed with the same permissions as the Docker Desktop user. Extension capabilities include running any Docker commands (including running containers and mounting folders), running extension binaries, and accessing files on your machine that are accessible by the user running Docker Desktop."

"Note that extensions are not restricted to execute binaries that they list in the host section of the extension metadata: since these binaries can contain any code running as user, they can in turn execute any other commands as long as the user has rights to execute them."

The overview page's "Security and trust" section, added in April 2026, says the same in fewer words: extensions "run with elevated privileges on your host machine. They have direct access to the Docker Engine, can read and write files on your filesystem, and can install and run native binaries." Two further facts from Docker's own settings documentation shape the roster: containers created by extensions are "hidden from the list of containers in the Docker Desktop Dashboard and the Docker CLI" by default, and the backend's compose file may mount host paths, add privileges and mount the Docker socket — which is full control of the engine.

The research that put this together first is SensePost's "an offensive look at docker desktop extensions" (Leon Jacobs, 30 May 2023, tested on Docker Desktop 4.19.0). Its findings, in its words: a backend "can have more privileges than you would be comfortable to give by adding extra port/volume/privilege labels to the extensions docker-compose.yml file"; a malicious extension could omit the UI and "have a service VM running without it being visible in Docker Desktop"; and "Extensions can execute arbitrary operating system commands, even if there isn't a specific binary shipped with the extension" — a command injection Docker's security team called "a non-issue" at the time, never assigned a CVE, and now described by Docker's own documentation as the designed behaviour quoted above. Its conclusion is the reason this roster exists: "Unless an extension author makes their extension open source, the only way to see what it is really doing is to manually inspect / reverse engineer the extension itself."

What Docker itself has fixed and changed

Every entry below is from Docker's release notes, its security announcements page or its documentation's own change history; the CVE figures are the ones Docker filed as the numbering authority.

What "reviewed" meant before the pause matters for D1 and D5. Docker's manual review of extensions was paused on 9 January 2024 — "We are pausing the extension manual validation process, and want publishers to go directly to the automated submission form" — and from then until June 2026 the gate was automated validation, which "checks if the extension's Dockerfile specifies all the required labels and if the metadata file is valid against the JSON schema file", plus a Docker staff member adding a label to the submission. No security criterion appears in either process. Docker's Marketplace page still says it: "Marketplace extensions are reviewed by Docker, but are not subject to a full security audit." And of anything outside the Marketplace: "Extensions installed outside the Marketplace have not been reviewed at all."

What the roster reads, without pulling the image

Three sources, all public. The Docker Hub API gives the repository record (pull and star counts, registration date, last push), its latest tag and the publisher's account (its badge, its join date). Docker's marketplace index — desktop.docker.com/extensions/marketplace.json, 50 image references, frozen since the pause — answers whether the image is listed at all. And the registry gives what the image declares: a pull token, the OCI index, the linux/amd64 manifest, the config blob with the listing labels, and then the twelve smallest layers in parallel, because the Extensions SDK's build puts metadata.json and the backend's compose file in their own layers of a few hundred bytes. A 502 MB image (the SQLcl extension, the largest listed) is read for a few kilobytes. No image is pulled, no layer above 512 KB is fetched, and the code inside the image is never read.

The gradings follow what the Marketplace actually looks like. On an extension that is listed and established (in Docker's index and at least 90 days on the Hub), a host binary, a VM backend, an unbadged publisher and a missing source label are notes — because, as the table below shows, that is the ordinary shape of the listed Marketplace. On an image that is not in the frozen index, or whose publisher joined the Hub recently, the same shapes are findings. Since the index cannot grow, an image not in it is sideloaded or private by definition, and D5 is the sharpest check on this platform.

Measured on the whole marketplace

Run on 18 September 2026 against all 50 listed extensions — the whole Marketplace, 45 publishers — locally through the same code that answers /v1/dde/score, anonymously against the registry, in two halves of 25 because the registry allows 100 anonymous manifest reads an hour: 50 PASS, 0 REVIEW, 0 BLOCK, no errors, no partial scans, labels read on all 50, metadata.json read on 49 (one extension's sits outside its twelve smallest layers, so its D6 and D7 are listed as not checked). Median 3.1 seconds per extension from Australia. The youngest listed repository is 853 days old; the median is 1,447 days.

What the roster foundExtensions (of 50)Listed and establishedUnlisted or new
Listed in Docker's index (D5)50INFOHIGH — sideloaded or private
Publisher with no Hub badge (D1)39INFOHIGH
Declares host binaries (D6)21INFOHIGH per binary
Declares a VM backend (D7)29INFOMED
… whose compose file mounts the Docker socket12INFOHIGH
… joins the host network · adds capabilities · maps devices · runs privileged · binds a host path4 · 3 · 3 · 1 · 1INFOHIGH each
No source repository in the labels (D8)23INFOMED, or HIGH when new
Source declared — assessed through the 22 on the same pass27 (17 same owner, 10 another owner)note: 25 REVIEW, 2 PASS, 0 BLOCK, none campaign-listedHIGH on a BLOCK, CRIT when campaign-listed
Listing link to a site other than the publisher's, GitHub or Docker (D9)16INFOINFO
Listing URL with a non-http scheme (D9)0HIGHHIGH
Not pushed in over a year (D10)33INFOINFO
Repository under 30 days · pulls without age · lookalike name (D2, D3, D4)0HIGHHIGH

Read plainly: half the listed Marketplace installs native code on the host and more than half runs a backend in the VM, twelve of them with the engine's socket mounted — Grafana's backend mounts the socket, maps /dev/kmsg and binds the host's root filesystem, /proc, /sys and /var/lib/docker read-only; Tailscale's ships six host binaries and joins the host network with NET_ADMIN and /dev/net/tun; one, the Mesos extension, runs privileged: true. That is what the platform is for, and on a listed, four-year-old extension the roster records it and moves on. Thirty-nine of the fifty come from a publisher without Docker's verified-publisher or official badge, Tailscale, Lens and ngrok among them, which is why the badge is a note here and not a finding; and thirty-three have not been pushed in a year, which is what a paused marketplace looks like from the inside. The 27 declared source repositories were scored through the 22 GitHub checks on the same pass: 2 PASS, none BLOCK, and 25 REVIEW on their own account — six of them not assessable at all, because the repository the label names no longer answers on GitHub (four of Docker's own among them), the rest for a stale release, a missing licence, an archived repository, a single contributor or a devcontainer — so D8 carried each as a note and none changed a verdict.

Two controls, run separately. library/nginx — a Docker Hub image that is no Docker Desktop extension — comes back REVIEW 64: not in the index, no verified badge on the namespace, no source label; the sideloaded shape the roster is graded for. And the fixture the test suite carries — an image not in the index, from a publisher who joined the Hub last month, declaring a host binary and a socket-mounting backend — is REVIEW on the personal profile and BLOCK on org-strict, where an unlisted image is a block.

What the roster would see on a malicious one — and would not

Stated as inference, because there is no exemplar. An extension built to abuse the surface Docker documents would most likely arrive by image reference rather than through the frozen Marketplace, from a namespace created for it, and would declare — because the SDK makes it declare — a host binary or a backend beside the socket. That shape fires D5, D1 and D6 or D7 at HIGH, a REVIEW on the personal profile and a BLOCK on org-strict before anything is installed; a source repository that is campaign-listed is a BLOCK everywhere through D8. Since Docker Desktop 4.31.0 the same image needs the marketplace-only setting switched off first, and since 4.74.0 extensions themselves are off by default — two settings a person has to change, which is why the roster grades an unlisted image HIGH rather than CRIT.

What the roster would not see is what the binary or the backend does. D6 lists the executables the image declares, and Docker's own words above say the list is not a limit; D7 reads the compose file's line shapes, not the container's behaviour. A listed extension whose tag is repointed after we looked is a separate case: Docker now installs Marketplace extensions by pinned digest, and RepoGates scores the latest tag at the moment of asking, so a verdict is about the image the tag named then. The HTML-bearing description and changelog labels behind the 2022 and 2024 fixes are not assessed at all. Reading the image is a deep scan, decided and not started on the roadmap; until it exists a PASS here means the provenance and the declared install surface show none of what these checks look for, never that the image's contents were inspected. There is no image-signature check either: none of the sampled Marketplace images carries a cosign signature, so a check for one would fire on all fifty and tell a reader nothing. And no platform: dde entry exists in RepoGates' campaign blocklist, because there is nothing to list.

What this doesn't mean

Docker's own words: Marketplace extensions "are not subject to a full security audit", and Docker "does not guarantee the security of any extension". Neither does this page. An extension that scores PASS today was checked today, on its publisher, its listing, its declared install surface and its declared source — never a claim that its binaries or its backend are benign, never a claim about the tag it is repointed to tomorrow. RepoGates assesses a Docker Desktop extension on request — through the API, the MCP server (platform="dde") and the preflight for docker extension install. It does not see an extension installed from Docker Desktop's own Extensions Marketplace tab, which is the app's own fetch; the board inside Docker Desktop is not built, and cannot be — its marketplace is a native window no browser extension sees. The image is never pulled and its code is not read: a PASS means the provenance and the declared install surface are clean, never that the backend or the host binaries were inspected. Every one of the eleven checks has its own page under the docs, stating what it reads and what it does not.