Skip to content

CloudflareApiToken detector misses 40-char tokens ending in '-' (trailing \b) #5328

Description

@sumlac

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions