Skip to content

🐛 Docker push fails when token requests contain multiple scopes #1

Description

@YusongXiao

Description

Docker push can fail when it attempts to reuse image layers from another repository through a cross-repository blob mount.

For example, when pushing an image from:

registry.example.com/1/networktest

to:

registry.example.com/2/networktest

Docker requests authorization for both the source and target repositories:

scope=repository:1/networktest:pull
scope=repository:2/networktest:pull,push

This produces a token request containing repeated scope query parameters:

GET /v2/token?service=ret2shell&scope=repository%3A1%2Fnetworktest%3Apull&scope=repository%3A2%2Fnetworktest%3Apull%2Cpush

Actual behavior

The token endpoint returns:

400 Bad Request
Failed to deserialize query string: scope: duplicate field `scope`

Docker then fails to authorize the cross-repository mount, resulting in errors similar to:

pushing with mount from 1/networktest
failed to authorize

A token request containing only one scope parameter works normally.

Expected behavior

The token endpoint should accept multiple scope parameters, authorize each requested repository scope, and include every authorized scope in the token's access entries.

Root cause

AuthRequest currently models the query parameter as a single optional string:

pub scope: Option<String>

The token handler extracts the query with Axum's default Query<AuthRequest>. When the query contains scope=A&scope=B, deserialization treats the second value as a duplicate struct field and rejects the request before the handler runs.

The token generation logic also processes at most one scope, so query parsing alone is not sufficient: every requested scope must also be authorized and added to the generated token.

Impact

This primarily affects Docker pushes that use cross-repository blob mounts. Docker cannot obtain a token containing both source pull and target pull,push permissions, preventing it from reusing existing layers and potentially causing the push to fail.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions