From d69d5da99b5da6e806519c54995a4fdd31337271 Mon Sep 17 00:00:00 2001 From: Brandon Stalnaker Date: Mon, 9 Mar 2026 12:16:04 -0400 Subject: [PATCH] fix: Add Defensive Code when Building URL Signatures --- .../ObjCTests/MPURLRequestBuilderTests.m | 19 ++++++++ .../Network/MPURLRequestBuilder.m | 46 +++++++++++++++++-- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/UnitTests/ObjCTests/MPURLRequestBuilderTests.m b/UnitTests/ObjCTests/MPURLRequestBuilderTests.m index b935b804c..0f6011280 100644 --- a/UnitTests/ObjCTests/MPURLRequestBuilderTests.m +++ b/UnitTests/ObjCTests/MPURLRequestBuilderTests.m @@ -225,6 +225,25 @@ - (void)testURLRequestComposition { } } +- (void)testBuildReturnsNilWhenConfigQueryExceedsMaxLength { + NSMutableString *longQueryValue = [NSMutableString stringWithCapacity:9000]; + for (NSInteger i = 0; i < 9000; i++) { + [longQueryValue appendString:@"a"]; + } + + NSString *urlString = [NSString stringWithFormat:@"https://config2.mparticle.com/v4/unit_test_app_key/config?plan_id=%@", longQueryValue]; + NSURL *defaultURL = [NSURL URLWithString:urlString]; + NSURL *modifiedURL = [NSURL URLWithString:urlString]; + XCTAssertNotNil(defaultURL); + XCTAssertNotNil(modifiedURL); + + MPURL *url = [[MPURL alloc] initWithURL:modifiedURL defaultURL:defaultURL]; + MPURLRequestBuilder *builder = [MPURLRequestBuilder newBuilderWithURL:url message:nil httpMethod:@"GET"]; + NSMutableURLRequest *request = [builder build]; + + XCTAssertNil(request); +} + - (void)testEtag { NSDictionary *configuration1 = @{ @"id":@42, diff --git a/mParticle-Apple-SDK/Network/MPURLRequestBuilder.m b/mParticle-Apple-SDK/Network/MPURLRequestBuilder.m index 1cfef05f2..a5f522351 100644 --- a/mParticle-Apple-SDK/Network/MPURLRequestBuilder.m +++ b/mParticle-Apple-SDK/Network/MPURLRequestBuilder.m @@ -28,6 +28,8 @@ @interface MPURLRequestBuilder() { @end +static const NSUInteger kMPURLRequestBuilderMaxQueryLength = 8192; + @implementation MPURLRequestBuilder @@ -161,11 +163,29 @@ - (NSMutableURLRequest *)build { return nil; } NSString *audienceQuery = [urlRequest.URL query]; + if (audienceQuery.length > kMPURLRequestBuilderMaxQueryLength) { + MPILogError(@"Cannot build URL request — audience query exceeds max supported length"); + return nil; + } NSString *audienceSignature; if (audienceQuery) { - audienceSignature = [NSString stringWithFormat:@"%@\n%@\n%@?%@", _httpMethod, date, audienceRelativePath, audienceQuery]; + NSMutableString *signatureBuilder = [NSMutableString stringWithCapacity:_httpMethod.length + date.length + audienceRelativePath.length + audienceQuery.length + 4]; + [signatureBuilder appendString:_httpMethod ?: @""]; + [signatureBuilder appendString:@"\n"]; + [signatureBuilder appendString:date ?: @""]; + [signatureBuilder appendString:@"\n"]; + [signatureBuilder appendString:audienceRelativePath]; + [signatureBuilder appendString:@"?"]; + [signatureBuilder appendString:audienceQuery]; + audienceSignature = [signatureBuilder copy]; } else { - audienceSignature = [NSString stringWithFormat:@"%@\n%@\n%@", _httpMethod, date, audienceRelativePath]; + NSMutableString *signatureBuilder = [NSMutableString stringWithCapacity:_httpMethod.length + date.length + audienceRelativePath.length + 3]; + [signatureBuilder appendString:_httpMethod ?: @""]; + [signatureBuilder appendString:@"\n"]; + [signatureBuilder appendString:date ?: @""]; + [signatureBuilder appendString:@"\n"]; + [signatureBuilder appendString:audienceRelativePath]; + audienceSignature = [signatureBuilder copy]; } MPILogVerbose(@"Audience Signature:\n%@", audienceSignature); NSString *hmacSha256Encode = [self hmacSha256Encode:audienceSignature key:secret]; @@ -243,10 +263,28 @@ - (NSMutableURLRequest *)build { } NSString *query = [_url.defaultURL query]; + if (query.length > kMPURLRequestBuilderMaxQueryLength) { + MPILogError(@"Cannot build URL request — config query exceeds max supported length"); + return nil; + } if (query) { - signatureMessage = [NSString stringWithFormat:@"%@\n%@\n%@?%@", _httpMethod, date, relativePath, query]; + NSMutableString *signatureBuilder = [NSMutableString stringWithCapacity:_httpMethod.length + date.length + relativePath.length + query.length + 4]; + [signatureBuilder appendString:_httpMethod ?: @""]; + [signatureBuilder appendString:@"\n"]; + [signatureBuilder appendString:date ?: @""]; + [signatureBuilder appendString:@"\n"]; + [signatureBuilder appendString:relativePath]; + [signatureBuilder appendString:@"?"]; + [signatureBuilder appendString:query]; + signatureMessage = [signatureBuilder copy]; } else { - signatureMessage = [NSString stringWithFormat:@"%@\n%@\n%@", _httpMethod, date, relativePath]; + NSMutableString *signatureBuilder = [NSMutableString stringWithCapacity:_httpMethod.length + date.length + relativePath.length + 3]; + [signatureBuilder appendString:_httpMethod ?: @""]; + [signatureBuilder appendString:@"\n"]; + [signatureBuilder appendString:date ?: @""]; + [signatureBuilder appendString:@"\n"]; + [signatureBuilder appendString:relativePath]; + signatureMessage = [signatureBuilder copy]; } }