The staticToken factory in arcp-core/src/main/java/dev/arcp/core/auth/BearerVerifier.java around line 12 compares the incoming bearer token to the expected token with !expected.equals(token). Java's String.equals short-circuits on the first differing character, which makes the comparison observably faster when an attacker submits a token that shares more leading characters with the secret. Over enough probes — and bearer tokens are exactly the kind of secret an attacker can probe rapidly — that signal is enough to recover the token byte by byte. The Javadoc describes this verifier as "suitable for development and tests," which is correct as guidance but does not stop production deployments from picking it up; ARCP's quick-start examples make it easy to copy. Even the acceptAny helper directly below has a related issue: the principal id is derived as Integer.toHexString(token.hashCode()), which means two different tokens whose hashCode happens to collide produce the same principal — different users observably authenticate as the same identity.\n\nFix prompt: In arcp-core/src/main/java/dev/arcp/core/auth/BearerVerifier.java rewrite staticToken to convert both expected and incoming tokens to UTF-8 byte arrays and compare with java.security.MessageDigest.isEqual(expectedBytes, incomingBytes), which is the JDK's constant-time array comparison. Reject the token first if its byte length differs from the expected length (length leak is inherent to bearer tokens and does not warrant constant-time padding). Update the Javadoc to drop "development and tests" wording in favor of a single line stating that the helper performs constant-time token comparison and may be used in production for static credentials. For acceptAny, replace the hashCode-derived principal with a SHA-256 digest of the token bytes, hex-encode the first 16 bytes for the principal id, and add a unit test that constructs two tokens whose hashCode collides (easy with crafted strings) and asserts the two principals are distinct.
The staticToken factory in arcp-core/src/main/java/dev/arcp/core/auth/BearerVerifier.java around line 12 compares the incoming bearer token to the expected token with
!expected.equals(token). Java'sString.equalsshort-circuits on the first differing character, which makes the comparison observably faster when an attacker submits a token that shares more leading characters with the secret. Over enough probes — and bearer tokens are exactly the kind of secret an attacker can probe rapidly — that signal is enough to recover the token byte by byte. The Javadoc describes this verifier as "suitable for development and tests," which is correct as guidance but does not stop production deployments from picking it up; ARCP's quick-start examples make it easy to copy. Even the acceptAny helper directly below has a related issue: the principal id is derived asInteger.toHexString(token.hashCode()), which means two different tokens whose hashCode happens to collide produce the same principal — different users observably authenticate as the same identity.\n\nFix prompt: In arcp-core/src/main/java/dev/arcp/core/auth/BearerVerifier.java rewrite staticToken to convert both expected and incoming tokens to UTF-8 byte arrays and compare withjava.security.MessageDigest.isEqual(expectedBytes, incomingBytes), which is the JDK's constant-time array comparison. Reject the token first if its byte length differs from the expected length (length leak is inherent to bearer tokens and does not warrant constant-time padding). Update the Javadoc to drop "development and tests" wording in favor of a single line stating that the helper performs constant-time token comparison and may be used in production for static credentials. For acceptAny, replace the hashCode-derived principal with a SHA-256 digest of the token bytes, hex-encode the first 16 bytes for the principal id, and add a unit test that constructs two tokens whose hashCode collides (easy with crafted strings) and asserts the two principals are distinct.