fix: add CSV field sanitization, injection detection, and row count l…#145
Open
kimanicode wants to merge 1 commit into
Open
fix: add CSV field sanitization, injection detection, and row count l…#145kimanicode wants to merge 1 commit into
kimanicode wants to merge 1 commit into
Conversation
…imit - Add CSV_MAX_ROWS (10,000) limit enforced on both client and mock server - Add FIELD_MAX_LENGTHS per-field character limits - Add INJECTION_PATTERN to detect formula injection (=, +, -, @) and control chars - Add sanitizeField() to strip control characters and truncate before preview - Add validateField() to return ValidationMessage[] for length/injection violations - Row count guard in parseRecipientsCsv rejects oversized files with clear error - Per-field validation loop added in buildLocalValidation - Mock handler returns HTTP 422 for oversized CSVs and flags bad fields per-column Closes ChainForgee#121
kilodesodiq-arch
requested changes
Jun 18, 2026
kilodesodiq-arch
left a comment
Contributor
There was a problem hiding this comment.
Direction is right @kimanicode, but two blockers before this lands:
- No unit tests for the sanitization logic. For a security fix this is a hard requirement — please add tests that prove the injection patterns (
=,+,-,@, control chars) are rejected and that legitimate values (incl. leading+phone numbers, plain names, plain wallets) still pass. - The injection regex
/^[=+\-@\t\r]/...will reject legitimate phone numbers like+15550100even after trim. International numbers routinely start with+. Either narrow the leading-char rule to columns that won't see phones, or only treat the leading@as risky and let+/-through.
Happy to merge once both land.
Contributor
|
Thanks @kimanicode for tackling #121. The sanitization logic looks correct, but I don't see any CI checks configured on this PR, so we can't verify it doesn't break the CSV import flow end-to-end. Could you wire up the relevant CI job for the backend (or at minimum include a regression test for the sanitization path) so we can land this safely? Holding the merge until then. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #121
This PR adds a proper validation and sanitization layer to the CSV import flow in
ImportRecipientsWizard. Previously,papaparseparsed CSV data and passed itdirectly to the UI and backend with no defense against malformed rows, excessively
long field values, or formula injection characters.
Changes
app/frontend/src/lib/csv-validation.tsCSV_MAX_ROWS = 10_000constant — enforces a hard row cap on the clientFIELD_MAX_LENGTHS— per-field character limits (e.g. wallet: 64, name: 120, phone: 20)INJECTION_PATTERNregex — detects formula injection triggers (=,+,-,@) and control/null characterssanitizeField()— strips control characters and truncates values to their field limit before they ever reach the preview tablevalidateField()— returnsValidationMessage[]for length overflow and injection pattern matchesparseRecipientsCsv()— rejects files exceeding 10,000 rows with a clear user-facing error; sanitizes every field value before building the rows arraybuildLocalValidation()— runsvalidateField()across all fields in every row after existing presence checksapp/frontend/src/lib/mock-api/handlers.tsMAX_ROWS,MAX_FIELD_LENGTH,DEFAULT_MAX,INJECTION_RE) insiderecipientsImportValidateHandler422with a descriptive message if the CSV exceeds 10,000 rowsdataLines.map()— checks every header's value for length overflow and injection characters, appending errors to the row'smessagesarraySecurity Issues Addressed
=SUM(...),=cmd|...)INJECTION_PATTERNrejects values starting with=,+,-,@\x00–\x08,\x0B,\x0C,\x0E–\x1F,\x7FFIELD_MAX_LENGTHSwith 255-char defaultparseRecipientsCsvbefore preview rendersTesting
tsc --noEmitpasses with no type errors introduced by these changeseslintpasses with no new lint errorsChecklist