fix(lib): default CookieExpiration to CookieDefaultExpirationTime when zero#1586
Open
crishoj wants to merge 1 commit into
Open
fix(lib): default CookieExpiration to CookieDefaultExpirationTime when zero#1586crishoj wants to merge 1 commit into
CookieExpiration to CookieDefaultExpirationTime when zero#1586crishoj wants to merge 1 commit into
Conversation
…n zero
Options.CookieExpiration time.Duration has a zero value of 0. When
left unset, both the cookie's Expires attribute and the JWT's exp
claim are computed as time.Now().Add(0) = now:
http.go SetCookie:
Expires: time.Now().Add(cookieOpts.Expiry)
// cookieOpts.Expiry falls back to s.opts.CookieExpiration when zero
anubis.go signJWT:
claims["exp"] = time.Now().Add(s.opts.CookieExpiration).Unix()
Result: browser solves PoW, libanubis issues an expired-on-arrival
cookie, browser re-requests, libanubis sees no valid cookie, serves
the challenge again. Infinite loop.
The Anubis CLI is unaffected because the --cookie-expiration-time
flag carries its own default of anubis.CookieDefaultExpirationTime
(7 days). Library consumers that construct Options directly — e.g.
plugins for other web servers — hit the zero-value bug.
Apply the same default in lib.New() so the library has the same safe
behavior as the CLI.
Test verifies both the option round-trip (srv.opts.CookieExpiration
filled to the constant) and the end-to-end cookie Expires attribute
on a real PassChallenge response.
Assisted-by: Claude Opus 4.7 via Claude Code
Signed-off-by: Christian Rishøj <christian@rishoj.net>
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.
Options.CookieExpiration time.Durationhas a zero value of0. When left unset, both the cookie'sExpiresattribute and the JWT'sexpclaim are computed astime.Now().Add(0)= now:Result: browser solves PoW, libanubis issues an expired-on-arrival cookie, browser re-requests, libanubis sees no valid cookie, serves the challenge again. Infinite loop.
The Anubis CLI sidesteps this because
--cookie-expiration-time(added in #389) carries its own default ofanubis.CookieDefaultExpirationTime(7 days). Library consumers that constructOptionsdirectly — for example, plugins for other web servers — hit the zero-value bug.This change applies the same default in
lib.New()so the library has the same safe behavior as the CLI.Test
TestCookieDefaultExpirationFilledverifies:srv.opts.CookieExpirationis filled toanubis.CookieDefaultExpirationTimeafterNew()when the caller leaves it unset.PassChallengehas itsExpiresattribute well in the future, not "now-ish".Context
I noticed this while building a Caddy plugin against
libanubis. Browser successfully solved the PoW but kept looping back to the challenge page. Workaround was to setCookieExpiration: anubis.CookieDefaultExpirationTimeexplicitly in the consumer; the proper fix is here, in the library.Checklist:
[Unreleased]section ofdocs/docs/CHANGELOG.mdTestCookieDefaultExpirationFilledinlib/anubis_test.go)npm run test:integration— partialFrame.Goto http://[::]:port: playwright: bad URLon every test, pre-existing env/playwright-webkit issue parsing IPv6 unspecified-address URLs (also seen onmain)