From bc7d9cc78e0149df4e46294cdfe0c7cd95ce861c Mon Sep 17 00:00:00 2001 From: "Thibault \"bui\" Koechlin" Date: Fri, 11 Sep 2026 16:32:24 +0200 Subject: [PATCH] [bot-detection] drop the URI from the cookie (#4656) --- pkg/appsec/challenge/challenge_test.go | 25 ++++++++++++++++++++++- pkg/appsec/challenge/fingerprint_proto.go | 9 ++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/pkg/appsec/challenge/challenge_test.go b/pkg/appsec/challenge/challenge_test.go index 9eda071bc..235938410 100644 --- a/pkg/appsec/challenge/challenge_test.go +++ b/pkg/appsec/challenge/challenge_test.go @@ -14,6 +14,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/crowdsecurity/crowdsec/pkg/appsec/challenge/pb" ) func TestHasLeadingZeroBits(t *testing.T) { @@ -525,10 +527,31 @@ func TestValidateChallengeResponse_FingerprintRoundTrip(t *testing.T) { require.NoError(t, err) require.NotNil(t, cd) assert.Equal(t, submitted.FSID, cd.Fingerprint.FSID) - assert.Equal(t, submitted.URL, cd.Fingerprint.URL) + // URL intentionally dropped to save space. + assert.Empty(t, cd.Fingerprint.URL) assert.Equal(t, c.powDifficulty, cd.PowDifficulty) } +// fpscanner reports window.location.href, so the URL is site-controlled and +// unbounded. It used to be sealed into the cookie, and a long enough query +// string pushed the envelope past the size browsers guarantee: the seal failed +// and the visitor could never pass the challenge. +func TestSealCookieWithOversizedFingerprintURL(t *testing.T) { + fp := FingerprintData{ + FSID: "FS1_00001000000000_00010h02ba", + URL: "https://example.com/landing?utm=" + strings.Repeat("x", 8000), + } + + key := make([]byte, 32) + + encoded, err := sealCookieV0(&pb.ChallengeCookie{ + Fingerprint: fp.ToProto(), + PowDifficulty: PowDifficultyMedium, + }, key, time.Now().Add(time.Hour).Unix(), 0, "", []byte("ua"), MaxCookieLen) + require.NoError(t, err) + assert.LessOrEqual(t, len(encoded), MaxCookieLen) +} + func TestValidateChallengeResponse_MultipleConcurrentClients(t *testing.T) { c := newTestRuntimeWithDifficulty(8) diff --git a/pkg/appsec/challenge/fingerprint_proto.go b/pkg/appsec/challenge/fingerprint_proto.go index 8919b98b9..bb4ab7e40 100644 --- a/pkg/appsec/challenge/fingerprint_proto.go +++ b/pkg/appsec/challenge/fingerprint_proto.go @@ -332,10 +332,11 @@ func (f *FingerprintData) ToProto() *pb.FingerprintData { Locale: f.Signals.Locale.toProto(), Contexts: f.Signals.Contexts.toProto(), }, - Fsid: f.FSID, - Nonce: f.Nonce, - Time: f.Time, - Url: f.URL, + Fsid: f.FSID, + Nonce: f.Nonce, + Time: f.Time, + // Url is deliberately not carried: fpscanner report window.location.href. + // It can be big and it ain't useful to us outside on_challenge_submit. FastBotDetection: bool(f.FastBotDetection), FastBotDetectionDetails: f.FastBotDetectionDetails.toProto(), Bot: f.Bot.toProto(),