Repository navigation
Conversation
RFC 8555, section 7.1.6, says that if the client attempts to fulfill a challenge and fails, the authorization transitions to "invalid". Authorization.UpdateStatus only ever moved a pending authorization to "valid" (or to "invalid" on expiry), so an authorization with an invalid challenge stayed "pending" until it expired 24 hours later. Clients such as certbot and Caddy/acmez kept polling it for that whole time. Mark the authorization invalid, and copy the error of the failed challenge into it, when no challenge is valid but at least one is invalid. A valid challenge still takes precedence.
This was referenced Sep 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
RFC 8555, section 7.1.6:
Authorization.UpdateStatusonly moves a pending authorization tovalid(when a challenge is valid) or to
invalid(when it has expired). If achallenge becomes
invalid, for example because the key authorization doesnot match, the authorization stays
pendinguntil it expires, 24 hours bydefault. Clients like certbot and Caddy/acmez poll the authorization, and
through it the order, for that whole time instead of reporting the error.
Change
In
UpdateStatus, if no challenge is valid but at least one is invalid, setthe authorization to
invalidand copy the error of the first invalidchallenge into
az.Error. The existingOrder.UpdateStatusthen marks theorder
invalidas well. A valid challenge still takes precedence over aninvalid one.
The check does not depend on the challenge type, but it only applies once a
challenge is actually
invalid. dns-01 is unaffected in practice:dns01Validatenever marks a challenge invalid, so a failed TXT lookup or aTXT record with the wrong value still leaves it
pendingfor anotherattempt.
Behavior change: after one challenge has failed, a client can no longer try
a different challenge type in the same authorization. It has to create a
new order. This matches the RFC and what Let's Encrypt does.
Tests
TestAuthorization_UpdateStatus: new casesok/invalid-challengeandok/valid-wins-over-invalid.TestAuthorizationInvalidAfterFailedChallenge: checks that theauthorization is saved with status
invalidand the challenge's error.It fails without the change. The two table cases only assert inside the
UpdateAuthorizationmock, so they also pass without the change; theyguard the new code path against regressions.
go test ./acme/... ./authority/...passes with Go 1.26.8 and 1.27.1.