Unicode Normalization in Chi with Firestore
Unicode Normalization in Chi with Firestore — how this specific combination creates or exposes the vulnerability
Unicode normalization inconsistencies arise when different byte sequences represent the same character. In Chi, route parameters and query strings are often bound directly to Firestore document IDs or field values. If an attacker supplies a specially crafted Unicode string that normalizes to an identical visual representation but a different binary form, the application may treat the values as distinct keys while Firestore handles them differently depending on how the client library normalizes input.
This mismatch can lead to BOLA/IDOR-like conditions: a user might inadvertently access or reference a document that belongs to another user because the normalized identifier used by Chi does not match the stored key. For example, a profile lookup using a user-supplied handle could resolve to a different document ID if the handle contains combining characters or varied Unicode forms. Firestore does not implicitly normalize strings; it stores what is provided. If Chi does not normalize inputs before constructing Firestore queries, the application may expose endpoints where access control assumptions break down.
Additionally, normalization issues can compound other findings such as Input Validation and Property Authorization. An attacker might leverage homoglyphs or decomposed characters to bypass pattern-based allowlists or to trigger unexpected behavior in Firestore queries, such as retrieving more documents than intended. Because Firestore indexes are sensitive to exact byte sequences, inconsistent normalization can lead to duplicate entries or missed query results, undermining data integrity. The scanner checks for these risks under the BOLA/IDOR and Input Validation categories, highlighting cases where route parameters flow into Firestore without canonical normalization.
Real-world patterns include using NFC (Normalization Form C) as the canonical form for storage and comparison. Chi applications should normalize incoming identifiers before using them in Firestore calls to ensure that visually identical strings map to the same logical key. Without this step, the attack surface expands, particularly in multi-tenant scenarios where tenant isolation relies on precise identifier matching.
Firestore-Specific Remediation in Chi
To mitigate Unicode normalization issues when integrating Chi with Firestore, normalize all user-controlled inputs before using them in queries or document ID lookups. Use a consistent Unicode form, such as NFC, across your codebase. In Chi, this can be done in route handlers or middleware before constructing Firestore references.
Example using Dart’s normalize function from the characters package to ensure canonical form:
import 'package:characters/characters.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:http_parser/http_parser.dart';
String normalizeToNFC(String input) {
return input.normalize(NFC);
}
void handleUserProfile(String rawHandle) {
String handle = normalizeToNFC(rawHandle);
DocumentReference ref = FirebaseFirestore.instance.collection('profiles').doc(handle);
// Use ref for get, set, or delete operations
}
For query-based lookups, normalize the search term before passing it to Firestore:
Future<QuerySnapshot> searchUsers(String rawTerm) async {
String term = normalizeToNFC(rawTerm);
return await FirebaseFirestore.instance.collection('users')
.where('username', isEqualTo: term)
.get();
}
If you accept identifiers in URL paths, apply normalization early in the request pipeline, for example in a Chi middleware or guard, so downstream handlers work with canonical values:
import 'package:charcode/charcode.dart';
import 'package:characters/characters.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:router/router.dart';
Middleware normalizeFirestoreIds() {
return (handler) async (context) {
String? id = context.params['id'];
if (id != null) {
String normalizedId = id.normalize(NFC);
context = context.rebuild((b) => b..params['id'] = normalizedId);
}
return handler(context);
};
}
void applyRoutes(ChiRouter router) {
router.use(normalizeFirestoreIds());
router.get('/profile/:id', (context) async {
String id = context.params['id']!;
DocumentSnapshot snap = await FirebaseFirestore.instance.collection('profiles').doc(id).get();
// process snap data
});
}
In the Pro plan, continuous monitoring can detect patterns where normalization-related discrepancies contribute to authentication or authorization anomalies. The dashboard highlights such findings with severity and remediation guidance, helping teams enforce consistent handling across endpoints that involve Firestore.