Summary
The CloudflareApiToken detector does not match a 40-character token whose
final character is -. Cloudflare API tokens are [A-Za-z0-9_-]{40}, so a
token ending in - or _ is a valid token that is silently skipped.
This looks like a trailing \b word boundary in the detector's pattern: \b
cannot assert a boundary after a non-word character, so the match fails when
the 40th character is -.
Reproduction
Two tokens, identical in their first 39 characters, differing only in the last.
Both are exactly 40 characters and both are valid Cloudflare API token shapes.
#!/usr/bin/env bash
set -eu
BASE="zymMlopiWfqUyHRSIf8NFmAUNLnY5Yx0y3RnjDQ" # exactly 39 chars
[ "${#BASE}" -eq 39 ] || { echo "BASE must be 39 chars"; exit 1; }
for LAST in "A" "-"; do
TOKEN="${BASE}${LAST}"
D=$(mktemp -d)
printf 'cloudflare:\n auth:\n apiToken: %s\n' "$TOKEN" > "$D/c.yml"
N=$(trufflehog filesystem "$D" --json --no-update --log-level=-1 \
--no-verification --results=verified,unknown,unverified 2>/dev/null \
| grep -c CloudflareApiToken || true)
printf "final char %-4s len=%s -> %s\n" "'$LAST'" "${#TOKEN}" \
"$([ "$N" -gt 0 ] && echo DETECTED || echo MISSED)"
rm -rf "$D"
done
Actual output
final char 'A' len=40 -> DETECTED
final char '-' len=40 -> MISSED
Expected
Both should be detected. - is in the documented token alphabet and carries no
less signal than A.
Versions affected
Reproduced identically on 3.94.3 and 3.97.5 (current at time of filing),
macOS arm64, Homebrew builds. 4/4 with independently generated high-entropy
39-character prefixes, so it is not specific to the value above.
Why it matters in practice
Found while running TruffleHog over a large repository estate. A real, live
Cloudflare API token committed in a serverless.yml was not reported, and its
only distinguishing feature versus tokens that were reported is that it ends
in -. The same detector concurrently produced ~2,364 matches on 40-character
hex strings in a single yarn.lock — so in that estate the detector had a high
false-positive rate on lockfile hashes while missing the genuine credential.
A second scanner using a generic high-entropy rule did report it, which is how
the gap surfaced.
Suggested fix
Anchor the trailing edge on something that tolerates a non-word final
character — e.g. a lookahead for a non-token character or end-of-input rather
than \b — so the full [A-Za-z0-9_-]{40} alphabet is matched. The same
consideration likely applies to any other detector whose alphabet includes
- or _ and which relies on a trailing \b.
Summary
The
CloudflareApiTokendetector does not match a 40-character token whosefinal character is
-. Cloudflare API tokens are[A-Za-z0-9_-]{40}, so atoken ending in
-or_is a valid token that is silently skipped.This looks like a trailing
\bword boundary in the detector's pattern:\bcannot assert a boundary after a non-word character, so the match fails when
the 40th character is
-.Reproduction
Two tokens, identical in their first 39 characters, differing only in the last.
Both are exactly 40 characters and both are valid Cloudflare API token shapes.
Actual output
Expected
Both should be detected.
-is in the documented token alphabet and carries noless signal than
A.Versions affected
Reproduced identically on 3.94.3 and 3.97.5 (current at time of filing),
macOS arm64, Homebrew builds. 4/4 with independently generated high-entropy
39-character prefixes, so it is not specific to the value above.
Why it matters in practice
Found while running TruffleHog over a large repository estate. A real, live
Cloudflare API token committed in a
serverless.ymlwas not reported, and itsonly distinguishing feature versus tokens that were reported is that it ends
in
-. The same detector concurrently produced ~2,364 matches on 40-characterhex strings in a single
yarn.lock— so in that estate the detector had a highfalse-positive rate on lockfile hashes while missing the genuine credential.
A second scanner using a generic high-entropy rule did report it, which is how
the gap surfaced.
Suggested fix
Anchor the trailing edge on something that tolerates a non-word final
character — e.g. a lookahead for a non-token character or end-of-input rather
than
\b— so the full[A-Za-z0-9_-]{40}alphabet is matched. The sameconsideration likely applies to any other detector whose alphabet includes
-or_and which relies on a trailing\b.