@@ -238,6 +238,22 @@ final class ExportService: ObservableObject {
238238 }
239239 }
240240
241+ /// Sanitize a name for use in SQL comments to prevent comment injection
242+ ///
243+ /// Removes characters that could break out of SQL comments:
244+ /// - Newlines (could start new SQL statements)
245+ /// - Comment terminators (* /)
246+ private func sanitizeForSQLComment( _ name: String ) -> String {
247+ var result = name
248+ // Replace newlines with spaces
249+ result = result. replacingOccurrences ( of: " \n " , with: " " )
250+ result = result. replacingOccurrences ( of: " \r " , with: " " )
251+ // Remove comment terminators (remove the asterisk-slash sequence)
252+ result = result. replacingOccurrences ( of: " */ " , with: " " )
253+ result = result. replacingOccurrences ( of: " -- " , with: " " )
254+ return result
255+ }
256+
241257 // MARK: - File Helpers
242258
243259 /// Create a file at the given URL and return a FileHandle for writing
@@ -268,8 +284,10 @@ final class ExportService: ObservableObject {
268284 currentTable = table. qualifiedName
269285
270286 // Add table header comment if multiple tables
287+ // Sanitize name to prevent newlines from breaking the comment line
271288 if tables. count > 1 {
272- try fileHandle. write ( contentsOf: " # Table: \( table. qualifiedName) \n " . toUTF8Data ( ) )
289+ let sanitizedName = sanitizeForSQLComment ( table. qualifiedName)
290+ try fileHandle. write ( contentsOf: " # Table: \( sanitizedName) \n " . toUTF8Data ( ) )
273291 }
274292
275293 // Fetch all data from table
@@ -477,17 +495,31 @@ final class ExportService: ObservableObject {
477495 progress = 1.0
478496 }
479497
480- /// Escape a string for JSON output
498+ /// Escape a string for JSON output per RFC 8259
499+ ///
500+ /// Escapes:
501+ /// - Quotation mark, backslash (required)
502+ /// - Control characters U+0000 to U+001F (required by spec)
481503 private func escapeJSONString( _ string: String ) -> String {
482504 var result = " "
505+ result. reserveCapacity ( string. count)
483506 for char in string {
484507 switch char {
485508 case " \" " : result += " \\ \" "
486509 case " \\ " : result += " \\ \\ "
487510 case " \n " : result += " \\ n "
488511 case " \r " : result += " \\ r "
489512 case " \t " : result += " \\ t "
490- default : result. append ( char)
513+ case " \u{08} " : result += " \\ b " // Backspace
514+ case " \u{0C} " : result += " \\ f " // Form feed
515+ default :
516+ // Escape other control characters (U+0000 to U+001F) as \uXXXX
517+ if let scalar = char. unicodeScalars. first,
518+ scalar. value < 0x20 {
519+ result += String ( format: " \\ u%04X " , scalar. value)
520+ } else {
521+ result. append ( char)
522+ }
491523 }
492524 }
493525 return result
@@ -578,8 +610,9 @@ final class ExportService: ObservableObject {
578610 let sqlOptions = table. sqlOptions
579611 let tableRef = qualifiedTableRef ( for: table)
580612
613+ let sanitizedName = sanitizeForSQLComment ( table. qualifiedName)
581614 try fileHandle. write ( contentsOf: " -- -------------------------------------------------------- \n " . toUTF8Data ( ) )
582- try fileHandle. write ( contentsOf: " -- Table: \( table . qualifiedName ) \n " . toUTF8Data ( ) )
615+ try fileHandle. write ( contentsOf: " -- Table: \( sanitizedName ) \n " . toUTF8Data ( ) )
583616 try fileHandle. write ( contentsOf: " -- -------------------------------------------------------- \n \n " . toUTF8Data ( ) )
584617
585618 // DROP statement
@@ -597,9 +630,10 @@ final class ExportService: ObservableObject {
597630 }
598631 try fileHandle. write ( contentsOf: " \n \n " . toUTF8Data ( ) )
599632 } catch {
600- let warningMessage = " Warning: failed to fetch DDL for table \( table. qualifiedName) : \( error) "
633+ // Use sanitizedName (already defined above) for safe comment output
634+ let warningMessage = " Warning: failed to fetch DDL for table \( sanitizedName) : \( error) "
601635 print ( warningMessage)
602- try fileHandle. write ( contentsOf: " -- \( warningMessage) \n \n " . toUTF8Data ( ) )
636+ try fileHandle. write ( contentsOf: " -- \( sanitizeForSQLComment ( warningMessage) ) \n \n " . toUTF8Data ( ) )
603637 }
604638 }
605639
0 commit comments