diff --git a/modules/ensemble/test/safe_view_group_payload_index_test.dart b/modules/ensemble/test/safe_view_group_payload_index_test.dart index f129b0bfa..8652a01f3 100644 --- a/modules/ensemble/test/safe_view_group_payload_index_test.dart +++ b/modules/ensemble/test/safe_view_group_payload_index_test.dart @@ -15,5 +15,10 @@ void main() { expect(safeViewGroupPayloadIndex(0, 0), 0); expect(safeViewGroupPayloadIndex(5, 0), 0); }); + + test('returns 0 when payload length is invalid', () { + expect(safeViewGroupPayloadIndex(0, -1), 0); + expect(safeViewGroupPayloadIndex(10, -3), 0); + }); }); } diff --git a/modules/ensemble/test/upload_path_security_test.dart b/modules/ensemble/test/upload_path_security_test.dart index e5f4546bb..8e629f953 100644 --- a/modules/ensemble/test/upload_path_security_test.dart +++ b/modules/ensemble/test/upload_path_security_test.dart @@ -1,3 +1,4 @@ +import 'package:ensemble/framework/data_context.dart' show File; import 'package:ensemble/util/upload_utils.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -17,5 +18,42 @@ void main() { expect(uploadPathContainsParentSegment('..'), true); expect(uploadPathContainsParentSegment('../etc/passwd'), true); }); + + test('treats only a full path segment ".." as traversal', () { + expect(uploadPathContainsParentSegment('photo..jpg'), false); + expect(uploadPathContainsParentSegment('.../x'), false); + expect(uploadPathContainsParentSegment(r'a\..\b'), true); + }); + + test('normalises backslashes before splitting', () { + expect(uploadPathContainsParentSegment(r'var\..\evil'), true); + }); + }); + + group('UploadUtils.uploadFiles path guard', () { + test('throws before any network I/O when path contains ".."', () async { + final files = [ + File(null, null, null, '/tmp/../outside.jpg', null), + ]; + + await expectLater( + UploadUtils.uploadFiles( + taskId: 't1', + method: 'POST', + url: 'http://127.0.0.1:9/should-not-connect', + headers: const {}, + fields: const {}, + files: files, + fieldName: 'file', + ), + throwsA( + isA().having( + (e) => e.message, + 'message', + contains('..'), + ), + ), + ); + }); }); }