knadh/listmonk · error
failed to verify captcha solution: %w
Error message
failed to verify captcha solution: %w
What it means
verifyAltcha wraps an error returned by altcha.VerifySolution when the submitted Altcha payload cannot even be processed — malformed base64/JSON payload, signature check error, or other altcha internal failure. This differs from a mere incorrect solution (which returns 'captcha verification failed'); here the payload itself could not be evaluated.
Source
Thrown at internal/captcha/captcha.go:190
}
var r hCaptchaResp
if err := json.Unmarshal(body, &r); err != nil {
return err, true
}
if !r.Success {
return fmt.Errorf("hCaptcha failed: %s", strings.Join(r.ErrorCodes, ",")), false
}
return nil, true
}
// verifyAltcha verifies an Altcha response.
func (c *Captcha) verifyAltcha(payload string) (error, bool) {
valid, err := altcha.VerifySolution(payload, c.altcha.HMACKey, true)
if err != nil {
return fmt.Errorf("failed to verify captcha solution: %w", err), false
}
if !valid {
return fmt.Errorf("captcha verification failed"), false
}
// Disallow token reuse.
if _, err := tmptokens.Check(payload); err == nil {
return fmt.Errorf("captcha token already used"), false
}
tmptokens.Set(payload, 5*time.Minute, nil)
return nil, true
}
View on GitHub (pinned to 670c01717d)
Solutions
- Unwrap the error to see whether it is a base64/JSON parse error or a signature error.
- Ensure server and client use the same altcha algorithm version and HMAC key.
- Reject with 400 immediately — malformed payloads indicate bots or broken clients, not retryable server issues.
- After rotating the HMAC key, invalidate old challenges (they fail signature checks).
Example fix
// before: same handling for parse errors and wrong solutions
valid, err := altcha.VerifySolution(payload, c.altcha.HMACKey, true)
// after: distinguish client error from verification failure
if _, ok := err.(*base64.CorruptInputError); ok {
return errors.New("malformed captcha payload"), false // 400
} Defensive patterns
Strategy: validation
Validate before calling
payload := r.PostFormValue("altcha")
if payload == "" {
return errors.New("altcha payload missing")
}
decoded, err := base64.StdEncoding.DecodeString(payload)
if err != nil {
return errors.New("altcha payload is not valid base64")
}
var p map[string]any
if err := json.Unmarshal(decoded, &p); err != nil {
return errors.New("altcha payload is not valid JSON")
} Type guard
func isWellFormedAltchaPayload(payload string) bool {
decoded, err := base64.StdEncoding.DecodeString(payload)
if err != nil {
return false
}
var probe struct {
Algorithm string `json:"algorithm"`
Challenge string `json:"challenge"`
Salt string `json:"salt"`
Signature string `json:"signature"`
}
return json.Unmarshal(decoded, &probe) == nil && probe.Challenge != "" && probe.Signature != ""
} Try / catch
if err, ok := captcha.Verify(payload); !ok {
if err != nil && strings.Contains(err.Error(), "failed to verify captcha solution") {
// unparseable payload: client error, not retryable server-side
log.Warn("malformed altcha payload (possible bot or version mismatch)", "err", err)
http.Error(w, "invalid captcha payload", http.StatusBadRequest)
return
}
} Prevention
- Keep the client altcha widget and server altcha library versions in sync
- Pre-validate base64/JSON shape of the payload before calling Verify
- Coordinate HMAC key rotations with frontend deployments
- Rate-limit the verification endpoint — malformed payloads usually come from bots
When it happens
Trigger: Calling Verify with ProviderAltcha where the payload string is not a valid base64-encoded signed challenge response — truncated payloads, tampered payloads, payloads generated against a different HMAC key, or non-base64 garbage submitted by clients.
Common situations: Client JS version producing a payload format the server's altcha library can't parse (version mismatch); attacker probing the endpoint with junk payloads; HMAC key rotated server-side while old pages still hold challenges signed with the previous key.
Related errors
- captcha verification failed
- failed to create Altcha challenge: %w
- failed to marshal Altcha challenge: %w
- hCaptcha failed: %s
- no captcha provider enabled
AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01).
Data as JSON: /api/errors/aadffb021e79cfc1.
Report an issue: GitHub.