A simple typo of ghcr.io to ghrc.io would normally be a small goof. You’d typically get a 404 or similar error, finally work out the issue, fix it, and move along. But in this case, that typo appears to be doing something very malicious, stealing GitHub credentials. First, a quick bit of background. ghcr.io is an OCI conformant registry for container images and OCI artifacts used by a lot of projects. It’s part of GitHub and is a very popular image and artifact repository used by open source projects. ghrc.io Is Just a Default Nginx# At first glance, ghrc.io is just a default nginx install: $ curl -i https://ghrc.io/ HTTP/2 200 server: nginx date: Fri, 22 Aug 2025 17:58:01 GMT content-type: text/html content-length: 615 last-modified: Tue, 23 Apr 2024 14:04:32 GMT etag: "6627bff0-267" strict-transport-security: max-age = 31536000 ; includeSubDomains accept-ranges: bytes Welcome to nginx!

Welcome to nginx!

If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.

Thank you for using nginx.

Even checking other links gives a typical 404 error: $ curl -i https://ghrc.io/404/ HTTP/2 404 server: nginx date: Fri, 22 Aug 2025 17:58:04 GMT content-type: text/html content-length: 146 strict-transport-security: max-age = 31536000 ; includeSubDomains 404 Not Found

404 Not Found


nginx
Why Is It Malicious?# The concerning part comes in when looking at the OCI API’s. Those are all under the /v2/ prefix for legacy reasons. Looking at ghrc.io , suddenly it’s not acting like a default nginx install anymore: $ curl -i https://ghrc.io/v2/ HTTP/2 401 server: nginx date: Fri, 22 Aug 2025 17:56:36 GMT content-type: application/json content-length: 72 www-authenticate: Bearer realm = "https://ghrc.io/token" { "errors" : [{ "code" : "UNAUTHORIZED" , "message" : "authentication required" }]} Compare that to some other registries and you’ll see the 401 status, www-authenticate header, and error message look very similar: $ curl -i https://ghcr.io/v2/ HTTP/2 401 content-type: application/json docker-distribution-api-version: registry/2.0 strict-transport-security: max-age = 63072000 ; includeSubDomains ; preload www-authenticate: Bearer realm = "https://ghcr.io/token" ,service = "ghcr.io" ,scope = "repository:user/image:pull" date: Fri, 22 Aug 2025 17:51:36 GMT content-length: 73 x-github-request-id: DA46:5B047:5EDB5D:66E5C2:68A8AE28 { "errors" : [{ "code" : "UNAUTHORIZED" , "message" : "authentication required" }]} $ curl -i https://registry-1.docker.io/v2/ HTTP/2 401 date: Sun, 24 Aug 2025 17:31:43 GMT content-type: application/json content-length: 87 docker-distribution-api-version: registry/2.0 www-authenticate: Bearer realm = "https://auth.docker.io/token" ,service = "registry.docker.io" strict-transport-security: max-age = 31536000 { "errors" : [{ "code" : "UNAUTHORIZED" , "message" : "authentication required" , "detail" :null }]} $ curl -i https://quay.io/v2/ HTTP/2 401 date: Sun, 24 Aug 2025 17:32:18 GMT content-type: text/html ; charset = utf-8 content-length: 4 server: nginx/1.22.1 www-authenticate: Bearer realm = "https://quay.io/v2/auth" ,service = "quay.io" docker-distribution-api-version: registry/2.0 true The (optional) error message is defined by the OCI Distribution Spec along with the various OCI APIs under the /v2/ prefix. Authentication hasn’t been standardized by OCI, yet, but projects all use the token auth workflow currently defined by the distribution project. The important detail is this www-authenticate header is telling OCI clients, like Docker, containerd, podman, and the various CRI’s used by Kubernetes, to send their user credentials to that https://ghrc.io/token API. There is no legitimate reason to configure this header on a default nginx install, and other parts of the server indicate that this is not a container registry. All signs point to this being a credential stealing typo-squatting attack. Credentials would be stolen only if you stored credentials for the ghrc.io registry, because clients won’t send credentials for a different host to ghcr.io . Some scenarios that would result in credentials being leaked include: Running docker login ghrc.io . . A GitHub action with uses: docker/login-action and with registry: ghrc.io . and with . Creating a Kubernetes secret with registry credentials for ghrc.io and then trying to pull an image from that typoed host. Simply trying to push or pull an image to this registry without logging in will not leak credentials and will not leak any data other than your repository name. These commands default to trying to acquire an anonymous token, which will quickly fail. What Should You Do?#