Skip to content
Exploit for CVE-2026

Exploit for CVE-2026

Sploitus • November 6, 2026

[![CI](

[![PyPI version](

[![License: MIT](

Find Dockerfiles that ship an sshd exposed to

[*sshole (CVE-2026-123158)]( with one command and

That scans every Dockerfile under the current folder. No install, no Docker,

no network access: it only reads files. (`pipx run check-sshole` or

.devcontainer/Dockerfile:2: sshd from 'openssh' on 'python:3.12-alpine3.15' accepts password logins: exposed to *sshole (CVE-2026-123158)

why: Alpine 3.15 never got a fixed openssh build

fix: turn password logins off: RUN echo 'PasswordAuthentication no' >> /etc/ssh/sshd_config

(or start sshd with -o PasswordAuthentication=no)

or: move to Alpine 3.16 or newer and require its fixed openssh build

more: (to silence, put '# check-sshole: ignore' above line 2)

services/sftp/Dockerfile:2: sshd from 'openssh-server' on 'alpine:3.22' accepts password logins: exposed to *sshole (CVE-2026-123158)

why: a fresh build may pull the fixed package, but nothing here requires it; older or cached builds have the bug

fix: turn password logins off: RUN echo 'PasswordAuthentication no' >> /etc/ssh/sshd_config

(or start sshd with -o PasswordAuthentication=no)

or: if you need password logins, require a fixed build: apk add 'openssh-server>=10.0_p1-r11'

more: (to silence, put '# check-sshole: ignore' above line 2)

check-sshole: 2 findings in 3 Dockerfiles

*sshole is a password authentication bypass in OpenSSH's sshd before 10.6p2

when sshd is built against musl libc without PAM. That is how Alpine builds

its default `openssh-server`, so a container that installs sshd with `apk`

and leaves password logins on (the OpenSSH default) is exposed. Accounts whose

password field is `*` (key-only users, and `root` on Alpine) are the ones at

risk. Debian, Ubuntu, RHEL and other glibc images are not affected.

check-sshole flags a Dockerfile stage when all of these are true:

| Condition | What check-sshole looks at |

| sshd is installed | `apk add openssh`, `openssh-server`, `openssh-server-pam` or `openssh-server-krb5`, in shell form, exec form, `sh -c` and heredocs; `apk del` is followed |

| the base is musl | the stage uses apk and is not Wolfi/Chainguard (those are glibc) |

| password logins are on | nothing sets `PasswordAuthentication no` or a password-free `AuthenticationMethods`, in `RUN`, `CMD`/`ENTRYPOINT` (`sshd -o …`), sshd config files COPY'd from the repository, or COPY heredocs; `UsePAM yes` with `openssh-server-pam` also counts as off |

| no fixed build is required | the package is not pinned (`=`, `>=`, `~`) to a fixed build |

Multi-stage builds are followed: a stage inherits what its `FROM `

parent installed and configured, and only stages that no other stage builds

check-sshole # every Dockerfile under the current folder

check-sshole services/ Dockerfile # some folders and files

check-sshole --format json . # machine-readable

It picks up `Dockerfile`, `Containerfile`, `Dockerfile.` and

`.Dockerfile`, and skips `.git`, `node_modules` and virtualenvs.

Files you name are checked whatever they are called.

| 2 | a path does not exist or could not be read |

- repo:

To check every Dockerfile once, not only the ones a commit touches:

`pre-commit run check-sshole --all-files`.

# path: services/ Dockerfile # default: the whole repository

Findings show up as annotations on the pull request and in the job summary,

and fail the job. The action runs on the runner's own Python and installs

| `path` | `.` | files or folders to scan, separated by spaces |

| `format` | `github` | `github` (annotations and a job summary), `text` or `json` |

## Fixed openssh builds per Alpine branch

| 3.15 and older | none: turn password logins off or move to a newer branch |

Source: the aports commits "main/openssh: fix password authentication"

check-sshole reads Dockerfiles, so it cannot see what an existing image

actually contains. To check one, read its installed build and compare it with

docker run --rm --entrypoint apk IMAGE list --installed openssh-server

# openssh-server-10.0_p1-r11 aarch64 {openssh} (SSH-OpenSSH) [installed]

`sshd -V` and `ssh -V` do not show the Alpine revision (`-r11`), and

`apk info -v` does not print the version, so use `apk list --installed`.

Rebuilding an image without `--no-cache` can keep an old, vulnerable layer.

Put `# check-sshole: ignore` on the line above the `RUN` that installs sshd,

or above `FROM` to skip a whole stage (and the stages built on it):

# check-sshole: ignore (sshd only listens on the internal network)

- It only reads Dockerfiles and the sshd config files they COPY from the

repository. It never builds or pulls images and never connects to a host.

- It does not see an sshd that comes with the base image (for example

`FROM linuxserver/openssh-server`), or sshd config that an entrypoint script

changes at runtime. Check those images with the command above.

pytest --cov # fails below 100% coverage

Releases are cut by publishing a GitHub release tagged `vX.Y.Z`; the publish

workflow builds the package and uploads it to PyPI.

Extracted Entities

Platforms (1)