Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

Key Vault: ChallengeAuthPolicy request-replay fix (#47742) not ported to azure-keyvault-secrets / -certificates, and absent from all stable releases

Abierto
#48,508 2 comentarios 1 reacción 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
68/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Tranquilo
Stack tecnológico
azure, python

Línea de trabajo

Empieza con azure/keyvault/secrets/_shared/challenge_auth_policy.py y azure/keyvault/certificates/_shared/challenge_auth_policy.py, comparándolos con la copia corregida de keys y con la prueba de regresión test_request_body_not_reused_across_requests de #47742. Ejecuta la reproducción con Mock sin red contra ambas policies no portadas; se considera terminado cuando las solicitudes posteriores conservan su método, URL y body, y el fix está incluido en una versión estable.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Client customer-reported KeyVault needs-team-attention question
Summary

The ChallengeAuthPolicy request-replay bug fixed by #47742 ("Fix Challenge Auth replay bug and update tests", merged 2026-07-08) was applied to azure-keyvault-keys and azure-keyvault-administration, but not to azure-keyvault-secrets or azure-keyvault-certificates, which vendor their own copies of _shared/challenge_auth_policy.py.

Separately, the fix is not present in any stable release yet — every current stable Key Vault package predates the merge, including azure-keyvault-keys itself.

To be clear about severity: I am not reporting this as a security vulnerability. The replayed request goes back to the vault that originally received it, and the bearer token is the shared https://vault.azure.net/.default audience that vault was already sent. verify_challenge_resource additionally blocks the cross-resource case. This is a correctness bug — an intended request is silently replaced by a duplicate of an earlier one.

Current state at HEAD

Occurrence count of _request_copy in each package's _shared/challenge_auth_policy.py:

Package _request_copy at HEAD Status
azure-keyvault-keys 1 fixed by #47742
azure-keyvault-administration 0 fixed
azure-keyvault-securitydomain 0 not affected
azure-keyvault-secrets 4 unported
azure-keyvault-certificates 4 unported

In the unfixed copies the stash is stored on the policy instance, which is created once per client rather than once per request:

  • self._request_copy: Optional[HttpRequest] = None — client-level state
  • self._request_copy = request.http_request — stores the in-flight request
  • if self._request_copy: request.http_request = self._request_copy — transplants it onto a later request
Stable releases
Package Latest stable Uploaded Contains fix?
azure-keyvault-secrets 4.11.0 2026-04-17 no
azure-keyvault-certificates 4.11.1 2026-05-05 no
azure-keyvault-keys 4.11.1 2026-05-19 no — predates the 2026-07-08 merge
azure-keyvault-administration 4.7.0 2026-05-19 no — predates the merge

The fix currently ships only in the pre-release azure-keyvault-keys 4.12.0b3.

Reproduction

This is the regression test added by #47742 (test_request_body_not_reused_across_requests), re-pointed at the unported packages. No Azure account, no network — the transport is a Mock.

pip install azure-keyvault-secrets==4.11.0 azure-keyvault-certificates==4.11.1 azure-keyvault-keys==4.12.0b3

Send a bodied POST to vault-A (elicits a challenge), then a bodiless GET to vault-B through the same client, and inspect the 4th outbound request:

=== azure-keyvault-keys 4.12.0b3 (POSITIVE CONTROL - contains #47742) ===
  4th request method : GET    (expected GET)
  4th request url    : https://vault-b.vault.azure.net/secrets/unrelated
  4th request body   : None   (expected None)
  RESULT: ok (per-request stash)

=== azure-keyvault-secrets 4.11.0 (UNPORTED) ===
  4th request method : POST   (expected GET)
  4th request url    : https://vault-a.vault.azure.net/secrets/db-password
  4th request body   : b'a duck'   (expected None)
  RESULT: prior request replayed

=== azure-keyvault-certificates 4.11.1 (UNPORTED) ===
  ... identical: POST, vault-a URL, body b'a duck'

The positive control discriminates: the fixed package passes under the identical harness, so the result is a property of the code under test rather than of the test.

Full reproduction script
import time
from unittest.mock import Mock

from azure.core.pipeline import Pipeline
from azure.core.rest import HttpRequest
from azure.core.credentials import AccessToken

CHALLENGE = Mock(
    status_code=401,
    headers={
        "WWW-Authenticate": 'Bearer authorization="https://authority.net/tenant", '
        "resource=https://vault.azure.net"
    },
)


def exercise(policy_cls, label):
    first_content = b"a duck"
    first_url = "https://vault-a.vault.azure.net/secrets/db-password"
    second_url = "https://vault-b.vault.azure.net/secrets/unrelated"
    seen = {}

    class C:
        n = 0

    def send(request):
        C.n += 1
        if C.n == 1:
            return CHALLENGE
        if C.n == 2:
            return Mock(status_code=200)
        if C.n == 3:
            return CHALLENGE
        if C.n == 4:
            seen["method"], seen["url"], seen["body"] = request.method, request.url, request.body
            return Mock(status_code=200)
        raise ValueError("unexpected request")

    cred = Mock(spec_set=["get_token"],
                get_token=Mock(return_value=AccessToken("token", time.time() + 3600)))
    pipeline = Pipeline(policies=[policy_cls(credential=cred)], transport=Mock(send=send))

    req = HttpRequest("POST", first_url)
    req.set_bytes_body(first_content)
    pipeline.run(req)
    pipeline.run(HttpRequest("GET", second_url))

    replayed = seen.get("body") == first_content or seen.get("url") == first_url
    print(f"\n=== {label} ===")
    print(f"  4th request method : {seen.get('method')}   (expected GET)")
    print(f"  4th request url    : {seen.get('url')}")
    print(f"    expected         : {second_url}")
    print(f"  4th request body   : {seen.get('body')!r}   (expected None)")
    print("  RESULT: " + ("prior request replayed" if replayed else "ok (per-request stash)"))
    return replayed


if __name__ == "__main__":
    from azure.keyvault.keys._shared.challenge_auth_policy import ChallengeAuthPolicy as KeysPolicy
    from azure.keyvault.secrets._shared.challenge_auth_policy import ChallengeAuthPolicy as SecretsPolicy
    from azure.keyvault.certificates._shared.challenge_auth_policy import ChallengeAuthPolicy as CertsPolicy

    exercise(KeysPolicy, "azure-keyvault-keys (POSITIVE CONTROL - fixed by #47742)")
    exercise(SecretsPolicy, "azure-keyvault-secrets (UNPORTED)")
    exercise(CertsPolicy, "azure-keyvault-certificates (UNPORTED)")
Impact

A call intended for one vault is emitted as a duplicate of an earlier call — the intended operation does not happen, and the earlier one is repeated. For secrets and certificates the replayed body is secret material being written a second time, so an unintended duplicate write or rotation is possible.

Suggested fix

Port #47742 to azure-keyvault-secrets and azure-keyvault-certificates (make the stash per-request rather than per-policy), and ship it in a stable release — the fix currently exists only in the pre-release azure-keyvault-keys 4.12.0b3.

Root cause of the divergence is the duplicated _shared directories: each package vendors its own copy of challenge_auth_policy.py, so a fix in one does not propagate. The .NET and Java SDKs are unaffected — they use a single shared implementation.

Lenguaje dominante
Python
Estrellas
5.6k
Forks
3.4k
Merge medio
1 d 18 h
PR fusionados (30 d)
202

Preparar el entorno

Abrir en Codespaces

Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de Azure/azure-sdk-for-python

Todos los issues de Azure/azure-sdk-for-python

Issues similares

Más issues de Python

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.