{"record":{"id":"ba8b0d4cd73a5db7","repo":"apache/pulsar","slug":"invalid-signed-text","errorCode":null,"errorMessage":"Invalid signed text: ","messagePattern":"Invalid signed text: ","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"pulsar-broker-auth-sasl/src/main/java/org/apache/pulsar/broker/authentication/SaslRoleTokenSigner.java","lineNumber":74,"sourceCode":"            throw new IllegalArgumentException(\"NULL or empty string to sign\");\n        }\n        String signature = computeSignature(str);\n        return str + SIGNATURE + signature;\n    }\n\n    /**\n     * Verifies a signed string and extracts the original string.\n     *\n     * @param signedStr the signed string to verify and extract.\n     *\n     * @return the extracted original string.\n     *\n     * @throws AuthenticationException thrown if the given string is not a signed string or if the signature is invalid.\n     */\n    public String verifyAndExtract(String signedStr) throws AuthenticationException {\n        int index = signedStr.lastIndexOf(SIGNATURE);\n        if (index == -1) {\n            throw new AuthenticationException(\"Invalid signed text: \" + signedStr);\n        }\n        String originalSignature = signedStr.substring(index + SIGNATURE.length());\n        String rawValue = signedStr.substring(0, index);\n        String currentSignature = computeSignature(rawValue);\n        if (!MessageDigest.isEqual(originalSignature.getBytes(), currentSignature.getBytes())){\n            throw new AuthenticationException(\"Invalid signature\");\n        }\n        return rawValue;\n    }\n\n    /**\n     * Returns the signature of a string.\n     *\n     * @param str string to sign.\n     *\n     * @return the signature for the string.\n     */\n    protected String computeSignature(String str) {","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker-auth-sasl/src/main/java/org/apache/pulsar/broker/authentication/SaslRoleTokenSigner.java#L56-L92","documentation":"SaslRoleTokenSigner.verifyAndExtract verifies HMAC-signed strings (format: payload + SIGNATURE marker + signature). If the input string does not contain the SIGNATURE separator at all, it is not a signed string produced by sign(), so an AuthenticationException is thrown with the offending text appended.","triggerScenarios":"Calling verifyAndExtract() with a plain, unsigned, empty, or malformed string that lacks the signature separator (e.g. token truncated before the signature, or a value fetched from the wrong config/cookie field).","commonSituations":"SASL authentication handshakes where the client sent a raw role token instead of the signed one; proxy/load-balancer stripping or truncating the token; manually constructed credentials in tests or scripts.","solutions":["Ensure the string passed to verifyAndExtract() comes from SaslRoleTokenSigner.sign() (or an equivalent client using the same secret) and was not truncated","Check that no intermediary (proxy, header parser) strips or mangles the signed token before it reaches the broker","Log/inspect the received string to confirm where the signature part was lost"],"exampleFix":"// before\nString role = signer.verifyAndExtract(rawToken); // throws if rawToken unsigned\n// after\nif (rawToken == null || !rawToken.contains(SaslRoleTokenSigner.SIGNATURE)) {\n    throw new AuthenticationException(\"token missing signature\");\n}\nString role = signer.verifyAndExtract(rawToken);","handlingStrategy":"validation","validationCode":"if (signedStr == null || !signedStr.contains(SIGNATURE)) {\n    throw new AuthenticationException(\"not a signed token\");\n}","typeGuard":"static boolean isSigned(String s) {\n    return s != null && s.lastIndexOf(SaslRoleTokenSigner.SIGNATURE) >= 0;\n}","tryCatchPattern":"try {\n    String role = signer.verifyAndExtract(signedStr);\n} catch (AuthenticationException e) {\n    // reject request / force re-auth\n}","preventionTips":["Only pass tokens obtained from signer.sign()","Beware proxies truncating headers","Add contains-check before verifying"],"tags":["authentication","sasl","signature","security"],"backgroundTag":"invalid-signed-token","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}