CVE-2023-46300: Improper Encoding or Escaping of Output (CWE-116)
value: iTerm2 before 3.4.20 allow (potentially remote) code execution because of mishandling of certain escape sequences related to tmux integration.
CWE description: The product prepares a structured message for communication with another component, but encoding or escaping of the data is either missing or done incorrectly. As a result, the intended structure of the message is not preserved.
CVSS v3 base score: 9.8
Published: 2023-10-22T04:15Z
Repository: https://github.com/gnachman/iTerm2
Language: Objective-C
Files changed: sources/VT100Terminal.m
Commit date: 2023-08-07 21:56:12 -0700
Commit message: Fixes for method 1.

Remove DECSCPP and DECNLS.
Sanitize title reports to remove risky characters.

Diff: diff --git a/sources/VT100Terminal.m b/sources/VT100Terminal.m
index 06df7db58..1a39efb3d 100644
--- a/sources/VT100Terminal.m
+++ b/sources/VT100Terminal.m
@@ -2796,20 +2796,20 @@ - (void)reallyExecuteToken:(VT100Token *)token {
             [_delegate terminalSendReport:[s dataUsingEncoding:NSUTF8StringEncoding]];
             break;
         }
         case XTERMCC_REPORT_ICON_TITLE: {
             NSString *s = [NSString stringWithFormat:@"\033]L%@\033\\",
-                           [_delegate terminalIconTitle]];
+                           [self reportSafeTitle:[_delegate terminalIconTitle]]];
             [_delegate terminalSendReport:[s dataUsingEncoding:NSUTF8StringEncoding]];
             break;
         }
         case XTERMCC_REPORT_WIN_TITLE: {
             // NOTE: In versions prior to 2.9.20150415, we used "L" as the leader here, not "l".
             // That was wrong and may cause bug reports due to breaking bugward compatibility.
             // (see xterm docs)
             NSString *s = [NSString stringWithFormat:@"\033]l%@\033\\",
-                           [_delegate terminalWindowTitle]];
+                           [self reportSafeTitle:[_delegate terminalWindowTitle]]];
             [_delegate terminalSendReport:[s dataUsingEncoding:NSUTF8StringEncoding]];
             break;
         }
         case XTERMCC_PUSH_TITLE: {
             switch (token.csi->p[1]) {
@@ -3458,18 +3458,10 @@ - (NSString *)decrqssDECSLRM {
 - (NSString *)decrqssDECSLPP {
     const int height = MAX(24, [self.delegate terminalSizeInCells].height);
     return [@(height) stringValue];
  }
 
-- (NSString *)decrqssDECSCPP {
-    return self.columnMode ? @"132" : @"80";
-}
-
-- (NSString *)decrqssDECNLS {
-    return [@([self.delegate terminalSizeInCells].height) stringValue];
-}
-
 - (iTermPromise<NSString *> *)decrqssPayloadPromise:(NSString *)pt {
     if ([pt isEqualToString:@"m"]) {
         return [iTermPromise promiseValue:[self decrqssSGR]];
     }
     if ([pt isEqualToString:@"\"p"]) {
@@ -3488,16 +3480,11 @@ - (NSString *)decrqssDECNLS {
         return [iTermPromise promiseValue:[self decrqssDECSLRM]];
     }
     if ([pt isEqualToString:@"t"]) {
         return [iTermPromise promiseValue:[self decrqssDECSLPP]];
     }
-    if ([pt isEqualToString:@"$|"]) {
-        return [iTermPromise promiseValue:[self decrqssDECSCPP]];
-    }
-    if ([pt isEqualToString:@"*|"]) {
-        return [iTermPromise promiseValue:[self decrqssDECNLS]];
-    }
+    // DECSCPP and DECNLS not supported for security reasons.
 
     return [iTermPromise promiseDefaultError];
 }
 
 + (NSOrderedSet<NSString *> *)sgrCodesForCharacter:(screen_char_t)c
@@ -5301,10 +5288,24 @@ - (NSString *)subtitleFromIconTitle:(NSString *)title {
         return nil;
     }
     return [title substringFromIndex:NSMaxRange(newlineRange)];
 }
 
+// Convert a title into a string that is safe to transmit in a report.
+// The goal is to make it hard for an attacker to issue a report that could be part of a command.
+- (NSString *)reportSafeTitle:(NSString *)unsafeTitle {
+    NSCharacterSet *unsafeSet = [NSCharacterSet characterSetWithCharactersInString:@"|;\r\n\e"];
+    NSString *result = unsafeTitle;
+    NSRange range;
+    range = [result rangeOfCharacterFromSet:unsafeSet];
+    while (range.location != NSNotFound) {
+        result = [result stringByReplacingCharactersInRange:range withString:@" "];
+        range = [result rangeOfCharacterFromSet:unsafeSet];
+    }
+    return result;
+}
+// This is used for titles received from the remote host.
 - (NSString *)sanitizedTitle:(NSString *)unsafeTitle {
     // Very long titles are slow to draw in the tabs. Limit their length and
     // cut off anything after newline since it wouldn't be visible anyway.
     NSCharacterSet *newlinesCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"\r\n"];
     NSRange newlineRange = [unsafeTitle rangeOfCharacterFromSet:newlinesCharacterSet];

Vulnerable code:                            [_delegate terminalIconTitle]];
                           [_delegate terminalWindowTitle]];
- (NSString *)decrqssDECSCPP {
    return self.columnMode ? @"132" : @"80";
}

- (NSString *)decrqssDECNLS {
    return [@([self.delegate terminalSizeInCells].height) stringValue];
}

    if ([pt isEqualToString:@"$|"]) {
        return [iTermPromise promiseValue:[self decrqssDECSCPP]];
    }
    if ([pt isEqualToString:@"*|"]) {
        return [iTermPromise promiseValue:[self decrqssDECNLS]];
    }
Fixed code:                            [self reportSafeTitle:[_delegate terminalIconTitle]]];
                           [self reportSafeTitle:[_delegate terminalWindowTitle]]];
    // DECSCPP and DECNLS not supported for security reasons.
// Convert a title into a string that is safe to transmit in a report.
// The goal is to make it hard for an attacker to issue a report that could be part of a command.
- (NSString *)reportSafeTitle:(NSString *)unsafeTitle {
    NSCharacterSet *unsafeSet = [NSCharacterSet characterSetWithCharactersInString:@"|;\r\n\e"];
    NSString *result = unsafeTitle;
    NSRange range;
    range = [result rangeOfCharacterFromSet:unsafeSet];
    while (range.location != NSNotFound) {
        result = [result stringByReplacingCharactersInRange:range withString:@" "];
        range = [result rangeOfCharacterFromSet:unsafeSet];
    }
    return result;
}
// This is used for titles received from the remote host.