{"record":{"id":"4483d5801ec69ef0","repo":"fish2018/pansou","slug":"unexpected-signing-method","errorCode":null,"errorMessage":"unexpected signing method","messagePattern":"unexpected signing method","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/jwt.go","lineNumber":53,"sourceCode":"\ttoken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)\n\treturn token.SignedString([]byte(secret))\n}\n\n// ValidateToken 验证JWT token\nfunc ValidateToken(tokenString string, secret string) (*Claims, error) {\n\tif tokenString == \"\" {\n\t\treturn nil, errors.New(\"token cannot be empty\")\n\t}\n\tif secret == \"\" {\n\t\treturn nil, errors.New(\"secret cannot be empty\")\n\t}\n\n\tclaims := &Claims{}\n\n\ttoken, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {\n\t\t// 验证签名算法\n\t\tif _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {\n\t\t\treturn nil, errors.New(\"unexpected signing method\")\n\t\t}\n\t\treturn []byte(secret), nil\n\t})\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !token.Valid {\n\t\treturn nil, errors.New(\"invalid token\")\n\t}\n\n\treturn claims, nil\n}\n","sourceCodeStart":35,"sourceCodeEnd":68,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/util/jwt.go#L35-L68","documentation":"During jwt.ParseWithClaims the keyfunc checks that the token's alg header is an HMAC signing method; anything else (e.g. RS256, none) is rejected with \"unexpected signing method\". This prevents algorithm-confusion attacks where a token signed/unsigned with another alg is accepted.","triggerScenarios":"Presenting a JWT whose header declares a non-HMAC alg to ValidateToken; a forged token with alg=none; tokens issued by a service using RS/ES algorithms being validated by this HMAC-only code.","commonSituations":"Migrating between JWT libraries or services with different signing algorithms; an attacker crafting alg=none tokens; copy-pasted tokens from another project.","solutions":["Ensure the token was signed with the same HMAC algorithm (HS256) and secret as this validator","Inspect the token header (base64-decode the first segment) to see its alg value","If you must support other algorithms, extend the keyfunc to handle them explicitly — never accept alg=none","Regenerate tokens with the correct signing method after fixing the issuer"],"exampleFix":"// before\nif _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {\n    return nil, errors.New(\"unexpected signing method\")\n}\n// after (tighter)\nif _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok || token.Header[\"alg\"] != \"HS256\" {\n    return nil, fmt.Errorf(\"unexpected signing method: %v\", token.Header[\"alg\"])\n}","handlingStrategy":"try-catch","validationCode":"// decode token header client-side\nseg := strings.Split(tokenString, \".\")[0]\nhdr, _ := base64.RawURLEncoding.DecodeString(seg)\n// verify alg is HS256 before sending","typeGuard":null,"tryCatchPattern":"claims, err := util.ValidateToken(tokenString, secret)\nif err != nil && strings.Contains(err.Error(), \"unexpected signing method\") {\n    // token from wrong issuer/algorithm: reject as untrusted\n}","preventionTips":["Sign all tokens with HS256 and the shared secret","Never accept alg=none or tokens from other algorithm families","Pin the expected algorithm in the keyfunc"],"tags":["jwt","security","algorithm-confusion","go"],"backgroundTag":"invalid-argument-value","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}