Repository: microsoft/terminal (language: cpp)

Issue:
pwsh/powershell VT quirk causes conhost crash when resizing while alt buffer is being used
Repro:

```
while($true){ "`e[?1049h";sleep 0.25;"`e[?1049l"; sleep 0.25}
```

Resize the window horizontally while it's running.

Toggling the alt buffer _from pwsh.exe or powershell.exe_ (specifically) causes us to UAF the outgoing `SCREEN_INFORMATION` here:
https://github.com/microsoft/terminal/blob/71cbdc8a1f6b8da10d130c053489445e99a4fc13/src/host/_stream.cpp#L1038-L1040



Discussion / hints:
note: We greatly reduced the number of places where this can trigger in #13352, but this quirk isn't entirely gone, so this bug persists.
fwiw I think I hit the same issue doing the following:

1. Run weechat in wsl2. Specifically, weechat 3.5 in ubuntu 22.04.1.
2. on the greeting screen (displays "WeeChat" in ascii art), resize Terminal until it crashes

It results in:
```
>	Microsoft.Terminal.Control.dll!Microsoft::Terminal::Core::Terminal::Write(std::basic_string_view<wchar_t,std::char_traits<wchar_t>> stringView) Line 486	C++
 	Microsoft.Terminal.Control.dll!winrt::Microsoft::Terminal::Control::implementation::ControlCore::_connectionOutputHandler(const winrt::hstring & hstr) Line 1515	C++
 	[Inline Frame] Microsoft.Terminal.Control.dll!winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler::{ctor}::__l1::<lambda_212_>::operator()(const winrt::hstring &) Line 507	C++
 	Microsoft.Terminal.Control.dll!winrt::impl::delegate<winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler,`winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler::implementation<winrt::Microsoft::Terminal::Control::implementation::ControlCore,void (__cdecl winrt::Microsoft::Terminal::Control::implementation::ControlCore::*)(winrt::hstring const &)>'::`1'::<lambda_212_>>::Invoke(void * output) Line 174	C++
 	[Inline Frame] TerminalConnection.dll!winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler::operator()(const winrt::param::hstring &) Line 451	C++
 	TerminalConnection.dll!winrt::impl::invoke<winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler,std::wstring>(const winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler & delegate, const std::wstring & <args_0>) Line 5762	C++
 	[Inline Frame] TerminalConnection.dll!winrt::event<winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler>::operator()(const std::wstring &) Line 5897	C++
 	TerminalConnection.dll!winrt::Microsoft::Terminal::TerminalConnection::implementation::ConptyConnection::_OutputThread() Line 659	C++
 	[Inline Frame] TerminalConnection.dll!winrt::Microsoft::Terminal::TerminalConnection::implementation::ConptyConnection::Start::__l3::<lambda_1>::operator()(void *) Line 362	C++
 	TerminalConnection.dll!_Closure_wrapper_1bfe9aa2_14::<lambda_invoker_cdecl>(void * __p1) Line 368	C++
 	kernel32.dll!BaseThreadInitThunk()	Unknown
 	ntdll.dll!RtlUserThreadStart()	Unknown
```

<HTML>
<body>
<!--StartFragment-->


  | Name | Value | Type
-- | -- | -- | --
▶ | this | 0x000002317a8988a0 {_pfnWriteInput={__this=0x000002317d41adc0 {...} } _pfnWarningBell=bind(0x00007fff6542dcd0 {Microsoft.Terminal.Control.dll!winrt::Microsoft::Terminal::Control::implementation::ControlCore::_terminalWarningBell(void)}, 0x000002317d41adc0 {...}) ...} | Microsoft::Terminal::Core::Terminal *
  | cursorPosAfter | Variable is optimized away and not available. |  
▶ | cursorPosBefore | {x=0 X=0 y=32 ...} | til::point
▶ | lock | {_Pmtx=0x000002317a8989c0 {_next_ticket=435 _now_serving=434 } _Owns=true } | std::unique_lock<til::ticket_lock>
▶ | stringView | 0x000002316f86d060 L"\x1b[?1049l" | std::basic_string_view<wchar_t,std::char_traits<wchar_t>>


<!--EndFragment-->
</body>
</HTML>


`\x1b[?1049` appearing in the `stringView` seems suspicious.

This happens somewhat frequently while using WeeChat normally (i.e. not just looking at the greeting screen), so it's quite annoying, and has been occurring for a while.

I'm currently on Terminal 1.14.2282.0

I've just intsalled [Microsoft.WindowsTerminal_Win11_1.15.2525.0_8wekyb3d8bbwe.msixbundle](https://github.com/microsoft/terminal/releases/download/v1.15.2524.0/Microsoft.WindowsTerminal_Win11_1.15.2525.0_8wekyb3d8bbwe.msixbundle) (hopefully that doesn't screw up the package on my system, which was previously just installed via Store...) and the crash is still present.
Whoa, thanks for this! A repro that doesn't involve the powershell quirk (which we just removed!) makes this much more important, too.
I was going to take a crack at fixing this (at least locally), and I find that on my local build of current main branch (commit 1f19ed0cd2e04dd46852300c369960d6fa69a8fa), the crash does not occur. On the current release version (1.15.2875.0) I have installed, the crash still does occur.

What's the likelyhood this was actually fixed as opposed to being fixed by some difference in the build environment? What commit does 1.15.2875.0 relate to? There is no matching git tag.
Strangely I started getting a crash-on-resize again after running a round of Windows Update today (not sure if crash has same root cause though), and doing a clean rebuild of Terminal locally seems to have made the crash go away, again. I also updated VS2022 to current latest, so a lot of moving pieces, but... 🤨
Okay, coming back to this thread now that I'm back from leave and vacation. 

I can't seem to repro this with weechat in `main` anymore. There've been some locking and lifetime changes over the last few months that might have fixed this. @shuffle2 if you can't repro this on `main` anymore, then I suggest we punt this out to the backlog. The set of folks with the busted PsReadline that we still need to quirk for who are resizing their terminal while entering the alt buffer is gonna be samll and only shrinking. We can elevate from the backlog if we see live hits here, but I don't think there are any.

Actually heck, @shuffle2's crash is a different thing anyways. The pwsh VT quirk only applies to conhost, and that stack is firmly in _terminal_ code. I'm gonna punt and assume this was fixed. I vaguely recall some other resizing crash fixes, but 1.17 has been like, 4 months now. 

@zadjii-msft I've just updated Windows and Terminal (from the store) again, and my crash (crash when resizing weechat output) still repros.
The versions are:
Terminal 1.18.2822.0
Windows 10.0.22621.2428

Although, getting the crash to occur isn't very deterministic. It seems to crash less frequently than before :/ Might need to try and compile with some debugging functionality and track it down eventually...unfortunately not much of a helpful update from me, here.

edit: actually, I'm probably hitting yet another crash, just happens to also be while doing my standard "resize weechat test".
The current crash which has happened a few times looks like this:

<details>
<summary>!analyze output</summary>

```
KEY_VALUES_STRING: 1

    Key  : AV.Fault
    Value: Read

    Key  : Analysis.CPU.mSec
    Value: 811

    Key  : Analysis.Elapsed.mSec
    Value: 7809

    Key  : Analysis.IO.Other.Mb
    Value: 42

    Key  : Analysis.IO.Read.Mb
    Value: 0

    Key  : Analysis.IO.Write.Mb
    Value: 149

    Key  : Analysis.Init.CPU.mSec
    Value: 171

    Key  : Analysis.Init.Elapsed.mSec
    Value: 9188

    Key  : Analysis.Memory.CommitPeak.Mb
    Value: 168

    Key  : Failure.Bucket
    Value: INVALID_POINTER_READ_c0000005_Microsoft.Terminal.Control.dll!Microsoft::Terminal::Core::Terminal::Write

    Key  : Failure.Hash
    Value: {39be1696-4bbf-0321-1166-d994398e7f26}

    Key  : Timeline.OS.Boot.DeltaSec
    Value: 508

    Key  : Timeline.Process.Start.DeltaSec
    Value: 21

    Key  : WER.OS.Branch
    Value: ni_release

    Key  : WER.OS.Version
    Value: 10.0.22621.1

    Key  : WER.Process.Version
    Value: 1.18.2310.9002


FILE_IN_CAB:  WindowsTerminal.exe.19076.dmp

NTGLOBALFLAG:  400

PROCESS_BAM_CURRENT_THROTTLED: 0

PROCESS_BAM_PREVIOUS_THROTTLED: 0

APPLICATION_VERIFIER_FLAGS:  0

CONTEXT:  (.ecxr)
rax=000000ace7f0f8c0 rbx=000000250000000a rcx=1bb06e0f88a70000
rdx=000002216288c534 rsi=00000221628ad940 rdi=000002216139d1f0
rip=00007ffd69f0a495 rsp=000000ace7f0f9c0 rbp=000002216139d308
 r8=000000000000000a  r9=0000000000000000 r10=000000ace7f0f8c0
r11=0010000004040001 r12=00000221613a3898 r13=0000000000000000
r14=000000ace7f0fa50 r15=0000000000000000
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
Microsoft_Terminal_Control!til::point::operator!= [inlined in Microsoft_Terminal_Control!Microsoft::Terminal::Core::Terminal::Write+0x7d]:
00007ffd`69f0a495 483b9e10010000  cmp     rbx,qword ptr [rsi+110h] ds:00000221`628ada50=????????????????
Resetting default scope

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 00007ffd69f0a495 (Microsoft_Terminal_Control!til::point::operator!=)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 0000000000000000
   Parameter[1]: 00000221628ada50
Attempt to read from address 00000221628ada50

PROCESS_NAME:  WindowsTerminal.exe

READ_ADDRESS:  00000221628ada50 

ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.

EXCEPTION_CODE_STR:  c0000005

EXCEPTION_PARAMETER1:  0000000000000000

EXCEPTION_PARAMETER2:  00000221628ada50

STACK_TEXT:  
000000ac`e7f0f9c0 00007ffd`69f0a397     : 00000000`00000024 00007ffd`6c3780ea 00000221`5f032240 00000000`00000000 : Microsoft_Terminal_Control!Microsoft::Terminal::Core::Terminal::Write+0x7d
000000ac`e7f0fa30 00007ffd`69f1d8e2     : 00000221`613a3898 00000000`00000000 00000221`6135b6d8 00000221`613a3878 : Microsoft_Terminal_Control!winrt::Microsoft::Terminal::Control::implementation::ControlCore::_connectionOutputHandler+0x37
000000ac`e7f0fa80 00007ffd`6c378b1d     : 00000221`6288c520 00007ffd`00000012 00000859`00000001 00000221`613a3870 : Microsoft_Terminal_Control!winrt::impl::delegate<winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler,`winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler::implementation<winrt::Microsoft::Terminal::Control::implementation::ControlCore,void (__cdecl winrt::Microsoft::Terminal::Control::implementation::ControlCore::*)(winrt::hstring const &)>'::`1'::<lambda_232_> >::Invoke+0x32
000000ac`e7f0fad0 00007ffd`6c3786d4     : 00000000`00000000 00004000`00000000 00000000`00000000 000000ac`e7f0fbb0 : TerminalConnection!winrt::impl::invoke<winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler,std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> > >+0x7d
000000ac`e7f0fb40 00007ffd`6c3792de     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : TerminalConnection!winrt::Microsoft::Terminal::TerminalConnection::implementation::ConptyConnection::_OutputThread+0x154
000000ac`e7f0fc00 00007ffd`9764257d     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : TerminalConnection!`winrt::Microsoft::Terminal::TerminalConnection::implementation::ConptyConnection::Start'::`3'::<lambda_1>::<lambda_invoker_cdecl>+0xe
000000ac`e7f0fc30 00007ffd`98c4aa78     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0x1d
000000ac`e7f0fc60 00000000`00000000     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x28


FAULTING_SOURCE_LINE:  C:\__w\1\s\src\cascadia\TerminalCore\Terminal.cpp

FAULTING_SOURCE_FILE:  C:\__w\1\s\src\cascadia\TerminalCore\Terminal.cpp

FAULTING_SOURCE_LINE_NUMBER:  493

FAULTING_SOURCE_CODE:  
    52:         }
    53: 
    54:         constexpr bool operator!=(const point rhs) const noexcept
    55:         {
>   56:             return __builtin_memcmp(this, &rhs, sizeof(rhs)) != 0;
    57:         }
    58: 
    59:         constexpr explicit operator bool() const noexcept
    60:         {
    61:             return (x > 0) & (y > 0);


SYMBOL_NAME:  Microsoft_Terminal_Control!Microsoft::Terminal::Core::Terminal::Write+7d

MODULE_NAME: Microsoft_Terminal_Control

IMAGE_NAME:  Microsoft.Terminal.Control.dll

STACK_COMMAND:  ~88s; .ecxr ; kb

FAILURE_BUCKET_ID:  INVALID_POINTER_READ_c0000005_Microsoft.Terminal.Control.dll!Microsoft::Terminal::Core::Terminal::Write

OS_VERSION:  10.0.22621.1

BUILDLAB_STR:  ni_release

OSPLATFORM_TYPE:  x64

OSNAME:  Windows 10

IMAGE_VERSION:  1.18.2310.9002

FAILURE_ID_HASH:  {39be1696-4bbf-0321-1166-d994398e7f26}
```

</details>

<details>
<summary>faulting context</summary>

```
0:088> k
 # Child-SP          RetAddr               Call Site
00 000000ac`e7f0e4e8 00007ffd`9658f969     ntdll!NtWaitForMultipleObjects+0x14
01 000000ac`e7f0e4f0 00007ffd`9658f86e     KERNELBASE!WaitForMultipleObjectsEx+0xe9
02 000000ac`e7f0e7d0 00007ffd`976a27f7     KERNELBASE!WaitForMultipleObjects+0xe
03 000000ac`e7f0e810 00007ffd`976a2236     kernel32!WerpReportFaultInternal+0x587
04 000000ac`e7f0e930 00007ffd`9668c92b     kernel32!WerpReportFault+0xbe
05 000000ac`e7f0e970 00007ffd`98c98b3d     KERNELBASE!UnhandledExceptionFilter+0x3db
06 000000ac`e7f0ea90 00007ffd`98c7f1b7     ntdll!RtlUserThreadStart$filt$0+0xac
07 000000ac`e7f0ead0 00007ffd`98c9449f     ntdll!_C_specific_handler+0x97
08 000000ac`e7f0eb40 00007ffd`98c0e456     ntdll!RtlpExecuteHandlerForException+0xf
09 000000ac`e7f0eb70 00007ffd`98c9348e     ntdll!RtlDispatchException+0x286
0a 000000ac`e7f0f2c0 00007ffd`69f0a495     ntdll!KiUserExceptionDispatch+0x2e
0b 000000ac`e7f0f9c0 00007ffd`69f0a397     Microsoft_Terminal_Control!Microsoft::Terminal::Core::Terminal::Write+0x7d [C:\__w\1\s\src\cascadia\TerminalCore\Terminal.cpp @ 493] 
0c 000000ac`e7f0fa30 00007ffd`69f1d8e2     Microsoft_Terminal_Control!winrt::Microsoft::Terminal::Control::implementation::ControlCore::_connectionOutputHandler+0x37 [C:\__w\1\s\src\cascadia\TerminalControl\ControlCore.cpp @ 1804] 
0d (Inline Function) --------`--------     Microsoft_Terminal_Control!winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler::{ctor}::__l1::<lambda_232_>::operator()+0x17 [C:\__w\1\s\src\cascadia\TerminalControl\Generated Files\winrt\Microsoft.Terminal.TerminalConnection.h @ 534] 
0e 000000ac`e7f0fa80 00007ffd`6c378b1d     Microsoft_Terminal_Control!winrt::impl::delegate<winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler,`winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler::implementation<winrt::Microsoft::Terminal::Control::implementation::ControlCore,void (__cdecl winrt::Microsoft::Terminal::Control::implementation::ControlCore::*)(winrt::hstring const &)>'::`1'::<lambda_232_> >::Invoke+0x32 [C:\__w\1\s\src\cascadia\TerminalControl\Generated Files\winrt\Microsoft.Terminal.TerminalConnection.h @ 186] 
0f (Inline Function) --------`--------     TerminalConnection!winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler::operator()+0x3d [C:\__w\1\s\src\cascadia\TerminalConnection\Generated Files\winrt\Microsoft.Terminal.TerminalConnection.h @ 478] 
10 000000ac`e7f0fad0 00007ffd`6c3786d4     TerminalConnection!winrt::impl::invoke<winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler,std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> > >+0x7d [C:\__w\1\s\src\cascadia\TerminalConnection\Generated Files\winrt\base.h @ 5890] 
11 (Inline Function) --------`--------     TerminalConnection!winrt::event<winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler>::operator()+0x54 [C:\__w\1\s\src\cascadia\TerminalConnection\Generated Files\winrt\base.h @ 6043] 
12 000000ac`e7f0fb40 00007ffd`6c3792de     TerminalConnection!winrt::Microsoft::Terminal::TerminalConnection::implementation::ConptyConnection::_OutputThread+0x154 [C:\__w\1\s\src\cascadia\TerminalConnection\ConptyConnection.cpp @ 711] 
13 (Inline Function) --------`--------     TerminalConnection!winrt::Microsoft::Terminal::TerminalConnection::implementation::ConptyConnection::Start::__l3::<lambda_1>::operator()+0xa [C:\__w\1\s\src\cascadia\TerminalConnection\ConptyConnection.cpp @ 427] 
14 000000ac`e7f0fc00 00007ffd`9764257d     TerminalConnection!`winrt::Microsoft::Terminal::TerminalConnection::implementation::ConptyConnection::Start'::`3'::<lambda_1>::<lambda_invoker_cdecl>+0xe [C:\__w\1\s\src\cascadia\TerminalConnection\ConptyConnection.cpp @ 430] 
15 000000ac`e7f0fc30 00007ffd`98c4aa78     kernel32!BaseThreadInitThunk+0x1d
16 000000ac`e7f0fc60 00000000`00000000     ntdll!RtlUserThreadStart+0x28
0:088> .frame /c b
0b 000000ac`e7f0f9c0 00007ffd`69f0a397     Microsoft_Terminal_Control!Microsoft::Terminal::Core::Terminal::Write+0x7d [C:\__w\1\s\src\cascadia\TerminalCore\Terminal.cpp @ 493] 
rax=0000000000000000 rbx=000000250000000a rcx=0000000000000001
rdx=0000000100000000 rsi=00000221628ad940 rdi=000002216139d1f0
rip=00007ffd69f0a495 rsp=000000ace7f0f9c0 rbp=000002216139d308
 r8=000002215f17a280  r9=0000000000000001 r10=0000000000000838
r11=00001b1c89ff7e37 r12=00000221613a3898 r13=0000000000000000
r14=000000ace7f0fa50 r15=0000000000000000
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
Microsoft_Terminal_Control!til::point::operator!= [inlined in Microsoft_Terminal_Control!Microsoft::Terminal::Core::Terminal::Write+0x7d]:
00007ffd`69f0a495 483b9e10010000  cmp     rbx,qword ptr [rsi+110h] ds:00000221`628ada50=????????????????
```

</details>

<details>
<summary>faulting code</summary>

```
    Microsoft_Terminal_Control!Microsoft::Terminal::Core::Terminal::Write:
00007ffd`69f0a418 48895c2418     mov     qword ptr [rsp+18h], rbx
00007ffd`69f0a41d 48896c2420     mov     qword ptr [rsp+20h], rbp
00007ffd`69f0a422 56             push    rsi
00007ffd`69f0a423 57             push    rdi
00007ffd`69f0a424 4156           push    r14
00007ffd`69f0a426 4883ec50       sub     rsp, 50h
00007ffd`69f0a42a 488b05dfdb1a00 mov     rax, qword ptr [Microsoft_Terminal_Control!__security_cookie (7ffd6a0b8010)]
00007ffd`69f0a431 4833c4         xor     rax, rsp
00007ffd`69f0a434 4889442440     mov     qword ptr [rsp+40h], rax
00007ffd`69f0a439 4c8bf2         mov     r14, stringView (rdx)
00007ffd`69f0a43c 488bf9         mov     rdi, this (rcx)
00007ffd`69f0a43f 0f57c0         xorps   xmm0, xmm0
00007ffd`69f0a442 0f11442430     movups  xmmword ptr [lock{._Pmtx(!!)} (rsp+30h)], xmm0
00007ffd`69f0a447 488da918010000 lea     rbp, [rcx+118h]
00007ffd`69f0a44e 48896c2430     mov     qword ptr [lock{._Pmtx} (rsp+30h)], lock (rbp)
00007ffd`69f0a453 488bcd         mov     rcx, rbp
00007ffd`69f0a456 e879000000     call    Microsoft_Terminal_Control!til::recursive_ticket_lock::lock (7ffd69f0a4d4)
00007ffd`69f0a45b c644243801     mov     byte ptr [lock._Owns (rsp+38h)], 1
00007ffd`69f0a460 488bb720080000 mov     rsi, qword ptr [this->_altBuffer{._Mypair._Myval2} (rdi+820h)]
00007ffd`69f0a467 4885f6         test    rsi, rsi
00007ffd`69f0a46a 7507           jne     Microsoft_Terminal_Control!Microsoft::Terminal::Core::Terminal::Write+0x5b (7ffd69f0a473)
00007ffd`69f0a46c 488bb718080000 mov     rsi, qword ptr [this->_mainBuffer{._Mypair._Myval2} (rdi+818h)]
00007ffd`69f0a473 488b9e10010000 mov     rbx, qword ptr [rsi+110h]
00007ffd`69f0a47a 410f2806       movaps  xmm0, xmmword ptr [stringView{._Mydata(!!)} (r14)]
00007ffd`69f0a47e 660f7f442420   movdqa  xmmword ptr [rsp+20h], xmm0
00007ffd`69f0a484 488d542420     lea     rdx, [rsp+20h]
00007ffd`69f0a489 488b8fc8060000 mov     rcx, qword ptr [this->_stateMachine{._Mypair._Myval2} (rdi+6C8h)]
00007ffd`69f0a490 e8db000000     call    Microsoft_Terminal_Control!Microsoft::Console::VirtualTerminal::StateMachine::ProcessString (7ffd69f0a570)
00007ffd`69f0a495 483b9e10010000 cmp     cursorPosBefore (rbx), qword ptr [rsi+110h]                                              <--------------- rsi is unmapped (probably UAF)
00007ffd`69f0a49c 752a           jne     Microsoft_Terminal_Control!Microsoft::Terminal::Core::Terminal::Write+0xb0 (7ffd69f0a4c8)
00007ffd`69f0a49e 488bcd         mov     rcx, rbp
00007ffd`69f0a4a1 e84a140000     call    Microsoft_Terminal_Control!til::recursive_ticket_lock::unlock (7ffd69f0b8f0)
00007ffd`69f0a4a6 488b4c2440     mov     rcx, qword ptr [rsp+40h]
00007ffd`69f0a4ab 4833cc         xor     rcx, rsp
00007ffd`69f0a4ae e83d1c0300     call    Microsoft_Terminal_Control!__security_check_cookie (7ffd69f3c0f0)
00007ffd`69f0a4b3 4c8d5c2450     lea     r11, [rsp+50h]
00007ffd`69f0a4b8 498b5b30       mov     cursorPosBefore (rbx), qword ptr [r11+30h]
00007ffd`69f0a4bc 498b6b38       mov     rbp, qword ptr [r11+38h]
00007ffd`69f0a4c0 498be3         mov     rsp, r11
00007ffd`69f0a4c3 415e           pop     stringView (r14)
00007ffd`69f0a4c5 5f             pop     this (rdi)
00007ffd`69f0a4c6 5e             pop     rsi
00007ffd`69f0a4c7 c3             ret     
00007ffd`69f0a4c8 488bcf         mov     rcx, this (rdi)
00007ffd`69f0a4cb e844140000     call    Microsoft_Terminal_Control!Microsoft::Terminal::Core::Terminal::_NotifyTerminalCursorPositionChanged (7ffd69f0b914)
00007ffd`69f0a4d0 ebcc           jmp     Microsoft_Terminal_Control!Microsoft::Terminal::Core::Terminal::Write+0x86 (7ffd69f0a49e)
00007ffd`69f0a4d2 cc             int     3
00007ffd`69f0a4d3 cc             int     3
```

</details>

Fix patch:
diff --git a/src/buffer/out/TextAttribute.cpp b/src/buffer/out/TextAttribute.cpp
index 65799d1d6f5..f95edf6bea0 100644
--- a/src/buffer/out/TextAttribute.cpp
+++ b/src/buffer/out/TextAttribute.cpp
@@ -65,47 +65,6 @@ void TextAttribute::SetLegacyDefaultAttributes(const WORD defaultAttributes) noe
     gsl::at(s_legacyBackgroundColorMap, s_legacyDefaultBackground) = TextColor{};
 }
 
-// Routine Description:
-// Pursuant to GH#6807
-// This routine replaces VT colors from the 16-color set with the "default"
-// flag. It is intended to be used as part of the "VT Quirk" in
-// WriteConsole[AW].
-//
-// There is going to be a very long tail of applications that will
-// explicitly request VT SGR 40/37 when what they really want is to
-// SetConsoleTextAttribute() with a black background/white foreground.
-// Instead of making those applications look bad (and therefore making us
-// look bad, because we're releasing this as an update to something that
-// "looks good" already), we're introducing this compatibility hack. Before
-// the color reckoning in GH#6698 + GH#6506, *every* color was subject to
-// being spontaneously and erroneously turned into the default color. Now,
-// only the 16-color palette value that matches the active console
-// background color will be destroyed when the quirk is enabled.
-//
-// This is not intended to be a long-term solution. This comment will be
-// discovered in forty years(*) time and people will laugh at our hubris.
-//
-// *it doesn't matter when you're reading this, it will always be 40 years
-// from now.
-TextAttribute TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults(const TextAttribute& attribute) noexcept
-{
-    const auto fg{ attribute.GetForeground() };
-    const auto bg{ attribute.GetBackground() };
-    auto copy{ attribute };
-    if (fg.IsIndex16() &&
-        attribute.IsIntense() == WI_IsFlagSet(s_ansiDefaultForeground, FOREGROUND_INTENSITY) &&
-        fg.GetIndex() == (s_ansiDefaultForeground & ~FOREGROUND_INTENSITY))
-    {
-        // We don't want to turn 1;37m into 39m (or even 1;39m), as this was meant to mimic a legacy color.
-        copy.SetDefaultForeground();
-    }
-    if (bg.IsIndex16() && bg.GetIndex() == s_ansiDefaultBackground)
-    {
-        copy.SetDefaultBackground();
-    }
-    return copy;
-}
-
 // Routine Description:
 // - Returns a WORD with legacy-style attributes for this textattribute.
 // Parameters:
diff --git a/src/buffer/out/TextAttribute.hpp b/src/buffer/out/TextAttribute.hpp
index 44d8563176a..b1d69d1f3bf 100644
--- a/src/buffer/out/TextAttribute.hpp
+++ b/src/buffer/out/TextAttribute.hpp
@@ -93,7 +93,6 @@ class TextAttribute final
     }
 
     static void SetLegacyDefaultAttributes(const WORD defaultAttributes) noexcept;
-    static TextAttribute StripErroneousVT16VersionsOfLegacyDefaults(const TextAttribute& attribute) noexcept;
     WORD GetLegacyAttributes() const noexcept;
 
     bool IsTopHorizontalDisplayed() const noexcept;
diff --git a/src/host/ApiRoutines.h b/src/host/ApiRoutines.h
index 7301c172194..3187f8ff9d7 100644
--- a/src/host/ApiRoutines.h
+++ b/src/host/ApiRoutines.h
@@ -72,13 +72,11 @@ class ApiRoutines : public IApiRoutines
     [[nodiscard]] HRESULT WriteConsoleAImpl(IConsoleOutputObject& context,
                                             const std::string_view buffer,
                                             size_t& read,
-                                            bool requiresVtQuirk,
                                             std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
 
     [[nodiscard]] HRESULT WriteConsoleWImpl(IConsoleOutputObject& context,
                                             const std::wstring_view buffer,
                                             size_t& read,
-                                            bool requiresVtQuirk,
                                             std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
 
 #pragma region ThreadCreationInfo
diff --git a/src/host/_stream.cpp b/src/host/_stream.cpp
index 9c3d3378a80..4dc98cae902 100644
--- a/src/host/_stream.cpp
+++ b/src/host/_stream.cpp
@@ -406,7 +406,6 @@ void WriteClearScreen(SCREEN_INFORMATION& screenInfo)
 [[nodiscard]] NTSTATUS DoWriteConsole(_In_reads_bytes_(*pcbBuffer) PCWCHAR pwchBuffer,
                                       _Inout_ size_t* const pcbBuffer,
                                       SCREEN_INFORMATION& screenInfo,
-                                      bool requiresVtQuirk,
                                       std::unique_ptr<WriteData>& waiter)
 try
 {
@@ -416,22 +415,10 @@ try
         waiter = std::make_unique<WriteData>(screenInfo,
                                              pwchBuffer,
                                              *pcbBuffer,
-                                             gci.OutputCP,
-                                             requiresVtQuirk);
+                                             gci.OutputCP);
         return CONSOLE_STATUS_WAIT;
     }
 
-    const auto restoreVtQuirk = wil::scope_exit([&]() {
-        if (requiresVtQuirk)
-        {
-            screenInfo.ResetIgnoreLegacyEquivalentVTAttributes();
-        }
-    });
-    if (requiresVtQuirk)
-    {
-        screenInfo.SetIgnoreLegacyEquivalentVTAttributes();
-    }
-
     const std::wstring_view str{ pwchBuffer, *pcbBuffer / sizeof(WCHAR) };
 
     if (WI_IsAnyFlagClear(screenInfo.OutputMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT))
@@ -464,7 +451,6 @@ NT_CATCH_RETURN()
 [[nodiscard]] HRESULT WriteConsoleWImplHelper(IConsoleOutputObject& context,
                                               const std::wstring_view buffer,
                                               size_t& read,
-                                              bool requiresVtQuirk,
                                               std::unique_ptr<WriteData>& waiter) noexcept
 {
     try
@@ -477,7 +463,7 @@ NT_CATCH_RETURN()
         size_t cbTextBufferLength;
         RETURN_IF_FAILED(SizeTMult(buffer.size(), sizeof(wchar_t), &cbTextBufferLength));
 
-        auto Status = DoWriteConsole(const_cast<wchar_t*>(buffer.data()), &cbTextBufferLength, context, requiresVtQuirk, waiter);
+        auto Status = DoWriteConsole(const_cast<wchar_t*>(buffer.data()), &cbTextBufferLength, context, waiter);
 
         // Convert back from bytes to characters for the resulting string length written.
         read = cbTextBufferLength / sizeof(wchar_t);
@@ -510,7 +496,6 @@ NT_CATCH_RETURN()
 [[nodiscard]] HRESULT ApiRoutines::WriteConsoleAImpl(IConsoleOutputObject& context,
                                                      const std::string_view buffer,
                                                      size_t& read,
-                                                     bool requiresVtQuirk,
                                                      std::unique_ptr<IWaitRoutine>& waiter) noexcept
 {
     try
@@ -622,7 +607,7 @@ NT_CATCH_RETURN()
 
         // Make the W version of the call
         size_t wcBufferWritten{};
-        const auto hr{ WriteConsoleWImplHelper(screenInfo, wstr, wcBufferWritten, requiresVtQuirk, writeDataWaiter) };
+        const auto hr{ WriteConsoleWImplHelper(screenInfo, wstr, wcBufferWritten, writeDataWaiter) };
 
         // If there is no waiter, process the byte count now.
         if (nullptr == writeDataWaiter.get())
@@ -700,7 +685,6 @@ NT_CATCH_RETURN()
 [[nodiscard]] HRESULT ApiRoutines::WriteConsoleWImpl(IConsoleOutputObject& context,
                                                      const std::wstring_view buffer,
                                                      size_t& read,
-                                                     bool requiresVtQuirk,
                                                      std::unique_ptr<IWaitRoutine>& waiter) noexcept
 {
     try
@@ -709,7 +693,7 @@ NT_CATCH_RETURN()
         auto unlock = wil::scope_exit([&] { UnlockConsole(); });
 
         std::unique_ptr<WriteData> writeDataWaiter;
-        RETURN_IF_FAILED(WriteConsoleWImplHelper(context.GetActiveBuffer(), buffer, read, requiresVtQuirk, writeDataWaiter));
+        RETURN_IF_FAILED(WriteConsoleWImplHelper(context.GetActiveBuffer(), buffer, read, writeDataWaiter));
 
         // Transfer specific waiter pointer into the generic interface wrapper.
         waiter.reset(writeDataWaiter.release());
diff --git a/src/host/_stream.h b/src/host/_stream.h
index 351b9173018..4651deb800e 100644
--- a/src/host/_stream.h
+++ b/src/host/_stream.h
@@ -28,5 +28,4 @@ void WriteClearScreen(SCREEN_INFORMATION& screenInfo);
 [[nodiscard]] NTSTATUS DoWriteConsole(_In_reads_bytes_(pcbBuffer) const wchar_t* pwchBuffer,
                                       _Inout_ size_t* const pcbBuffer,
                                       SCREEN_INFORMATION& screenInfo,
-                                      bool requiresVtQuirk,
                                       std::unique_ptr<WriteData>& waiter);
diff --git a/src/host/screenInfo.cpp b/src/host/screenInfo.cpp
index 0084dc5bced..8d5e9217246 100644
--- a/src/host/screenInfo.cpp
+++ b/src/host/screenInfo.cpp
@@ -41,8 +41,7 @@ SCREEN_INFORMATION::SCREEN_INFORMATION(
     _PopupAttributes{ popupAttributes },
     _virtualBottom{ 0 },
     _currentFont{ fontInfo },
-    _desiredFont{ fontInfo },
-    _ignoreLegacyEquivalentVTAttributes{ false }
+    _desiredFont{ fontInfo }
 {
     // Check if VT mode should be enabled by default. This can be true if
     // VirtualTerminalLevel is set to !=0 in the registry, or when conhost
@@ -2014,13 +2013,6 @@ const TextAttribute& SCREEN_INFORMATION::GetPopupAttributes() const noexcept
 // <none>
 void SCREEN_INFORMATION::SetAttributes(const TextAttribute& attributes)
 {
-    if (_ignoreLegacyEquivalentVTAttributes)
-    {
-        // See the comment on StripErroneousVT16VersionsOfLegacyDefaults for more info.
-        _textBuffer->SetCurrentAttributes(TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults(attributes));
-        return;
-    }
-
     _textBuffer->SetCurrentAttributes(attributes);
 
     // If we're an alt buffer, DON'T propagate this setting up to the main buffer.
@@ -2466,17 +2458,3 @@ const FontInfoDesired& SCREEN_INFORMATION::GetDesiredFont() const noexcept
 {
     return _desiredFont;
 }
-
-// Routine Description:
-// - Engages the legacy VT handling quirk; see TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults
-void SCREEN_INFORMATION::SetIgnoreLegacyEquivalentVTAttributes() noexcept
-{
-    _ignoreLegacyEquivalentVTAttributes = true;
-}
-
-// Routine Description:
-// - Disengages the legacy VT handling quirk; see TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults
-void SCREEN_INFORMATION::ResetIgnoreLegacyEquivalentVTAttributes() noexcept
-{
-    _ignoreLegacyEquivalentVTAttributes = false;
-}
diff --git a/src/host/screenInfo.hpp b/src/host/screenInfo.hpp
index 7f0b9357a14..4ecd1a4e3e9 100644
--- a/src/host/screenInfo.hpp
+++ b/src/host/screenInfo.hpp
@@ -213,9 +213,6 @@ class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console
     FontInfoDesired& GetDesiredFont() noexcept;
     const FontInfoDesired& GetDesiredFont() const noexcept;
 
-    void SetIgnoreLegacyEquivalentVTAttributes() noexcept;
-    void ResetIgnoreLegacyEquivalentVTAttributes() noexcept;
-
     [[nodiscard]] NTSTATUS ResizeWithReflow(const til::size coordnewScreenSize);
     [[nodiscard]] NTSTATUS ResizeTraditional(const til::size coordNewScreenSize);
 
@@ -277,8 +274,6 @@ class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console
     //  the viewport to move (SetBufferInfo, WriteConsole, etc)
     til::CoordType _virtualBottom;
 
-    bool _ignoreLegacyEquivalentVTAttributes;
-
     std::optional<til::size> _deferredPtyResize{ std::nullopt };
 
     static void _handleDeferredResize(SCREEN_INFORMATION& siMain);
diff --git a/src/host/ut_host/ApiRoutinesTests.cpp b/src/host/ut_host/ApiRoutinesTests.cpp
index c0edafe11d9..37e6ec62fdc 100644
--- a/src/host/ut_host/ApiRoutinesTests.cpp
+++ b/src/host/ut_host/ApiRoutinesTests.cpp
@@ -385,7 +385,7 @@ class ApiRoutinesTests
             const auto cchWriteLength = std::min(cchIncrement, cchTestText - i);
 
             // Run the test method
-            const auto hr = _pApiRoutines->WriteConsoleAImpl(si, { pszTestText + i, cchWriteLength }, cchRead, false, waiter);
+            const auto hr = _pApiRoutines->WriteConsoleAImpl(si, { pszTestText + i, cchWriteLength }, cchRead, waiter);
 
             VERIFY_ARE_EQUAL(S_OK, hr, L"Successful result code from writing.");
             if (!fInduceWait)
@@ -441,7 +441,7 @@ class ApiRoutinesTests
 
         size_t cchRead = 0;
         std::unique_ptr<IWaitRoutine> waiter;
-        const auto hr = _pApiRoutines->WriteConsoleWImpl(si, testText, cchRead, false, waiter);
+        const auto hr = _pApiRoutines->WriteConsoleWImpl(si, testText, cchRead, waiter);
 
         VERIFY_ARE_EQUAL(S_OK, hr, L"Successful result code from writing.");
         if (!fInduceWait)
diff --git a/src/host/ut_host/ScreenBufferTests.cpp b/src/host/ut_host/ScreenBufferTests.cpp
index a4a57e53f5e..d1fe5a31962 100644
--- a/src/host/ut_host/ScreenBufferTests.cpp
+++ b/src/host/ut_host/ScreenBufferTests.cpp
@@ -248,8 +248,6 @@ class ScreenBufferTests
     TEST_METHOD(DontChangeVirtualBottomWithMakeCursorVisible);
     TEST_METHOD(RetainHorizontalOffsetWhenMovingToBottom);
 
-    TEST_METHOD(TestWriteConsoleVTQuirkMode);
-
     TEST_METHOD(TestReflowEndOfLineColor);
     TEST_METHOD(TestReflowSmallerLongLineWithColor);
     TEST_METHOD(TestReflowBiggerLongLineWithColor);
@@ -2548,7 +2546,7 @@ void ScreenBufferTests::TestAltBufferVtDispatching()
         std::unique_ptr<WriteData> waiter;
         std::wstring seq = L"\x1b[5;6H";
         auto seqCb = 2 * seq.size();
-        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, false, waiter));
+        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, waiter));
 
         VERIFY_ARE_EQUAL(til::point(0, 0), mainCursor.GetPosition());
         // recall: vt coordinates are (row, column), 1-indexed
@@ -2563,14 +2561,14 @@ void ScreenBufferTests::TestAltBufferVtDispatching()
 
         seq = L"\x1b[48;2;255;0;255m";
         seqCb = 2 * seq.size();
-        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, false, waiter));
+        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, waiter));
 
         VERIFY_ARE_EQUAL(expectedDefaults, mainBuffer.GetAttributes());
         VERIFY_ARE_EQUAL(expectedRgb, alternate.GetAttributes());
 
         seq = L"X";
         seqCb = 2 * seq.size();
-        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, false, waiter));
+        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, waiter));
 
         VERIFY_ARE_EQUAL(til::point(0, 0), mainCursor.GetPosition());
         VERIFY_ARE_EQUAL(til::point(6, 4), altCursor.GetPosition());
@@ -7565,127 +7563,6 @@ void ScreenBufferTests::RetainHorizontalOffsetWhenMovingToBottom()
     VERIFY_ARE_EQUAL(initialOrigin.x, si.GetViewport().Left());
 }
 
-void ScreenBufferTests::TestWriteConsoleVTQuirkMode()
-{
-    BEGIN_TEST_METHOD_PROPERTIES()
-        TEST_METHOD_PROPERTY(L"Data:useQuirk", L"{false, true}")
-    END_TEST_METHOD_PROPERTIES()
-
-    bool useQuirk;
-    VERIFY_SUCCEEDED(TestData::TryGetValue(L"useQuirk", useQuirk), L"whether to enable the quirk");
-
-    auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
-    gci.LockConsole(); // Lock must be taken to manipulate buffer.
-    auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
-
-    auto& mainBuffer = gci.GetActiveOutputBuffer();
-    auto& cursor = mainBuffer.GetTextBuffer().GetCursor();
-    // Make sure we're in VT mode
-    WI_SetFlag(mainBuffer.OutputMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING);
-
-    const TextAttribute defaultAttribute{};
-    // Make sure we're using the default attributes at the start of the test,
-    // Otherwise they could be polluted from a previous test.
-    mainBuffer.SetAttributes(defaultAttribute);
-
-    const auto verifyLastAttribute = [&](const TextAttribute& expected) {
-        const auto& row = mainBuffer.GetTextBuffer().GetRowByOffset(cursor.GetPosition().y);
-        auto iter{ row.AttrBegin() };
-        iter += cursor.GetPosition().x - 1;
-        VERIFY_ARE_EQUAL(expected, *iter);
-    };
-
-    std::unique_ptr<WriteData> waiter;
-
-    std::wstring seq{};
-    size_t seqCb{ 0 };
-
-    /* Write red on blue, verify that it comes through */
-    {
-        TextAttribute vtRedOnBlueAttribute{};
-        vtRedOnBlueAttribute.SetForeground(TextColor{ TextColor::DARK_RED, false });
-        vtRedOnBlueAttribute.SetBackground(TextColor{ TextColor::DARK_BLUE, false });
-
-        seq = L"\x1b[31;44m";
-        seqCb = 2 * seq.size();
-        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter));
-
-        VERIFY_ARE_EQUAL(vtRedOnBlueAttribute, mainBuffer.GetAttributes());
-
-        seq = L"X";
-        seqCb = 2 * seq.size();
-        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter));
-
-        verifyLastAttribute(vtRedOnBlueAttribute);
-    }
-
-    /* Write white on black, verify that it acts as expected for the quirk mode */
-    {
-        TextAttribute vtWhiteOnBlackAttribute{};
-        vtWhiteOnBlackAttribute.SetForeground(TextColor{ TextColor::DARK_WHITE, false });
-        vtWhiteOnBlackAttribute.SetBackground(TextColor{ TextColor::DARK_BLACK, false });
-
-        const auto quirkExpectedAttribute{ useQuirk ? defaultAttribute : vtWhiteOnBlackAttribute };
-
-        seq = L"\x1b[37;40m"; // the quirk should suppress this, turning it into "defaults"
-        seqCb = 2 * seq.size();
-        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter));
-
-        VERIFY_ARE_EQUAL(quirkExpectedAttribute, mainBuffer.GetAttributes());
-
-        seq = L"X";
-        seqCb = 2 * seq.size();
-        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter));
-
-        verifyLastAttribute(quirkExpectedAttribute);
-    }
-
-    /* Write bright white on black, verify that it acts as expected for the quirk mode */
-    {
-        TextAttribute vtBrightWhiteOnBlackAttribute{};
-        vtBrightWhiteOnBlackAttribute.SetForeground(TextColor{ TextColor::DARK_WHITE, false });
-        vtBrightWhiteOnBlackAttribute.SetBackground(TextColor{ TextColor::DARK_BLACK, false });
-        vtBrightWhiteOnBlackAttribute.SetIntense(true);
-
-        auto vtBrightWhiteOnDefaultAttribute{ vtBrightWhiteOnBlackAttribute }; // copy the above attribute
-        vtBrightWhiteOnDefaultAttribute.SetDefaultBackground();
-
-        const auto quirkExpectedAttribute{ useQuirk ? vtBrightWhiteOnDefaultAttribute : vtBrightWhiteOnBlackAttribute };
-
-        seq = L"\x1b[1;37;40m"; // the quirk should suppress black only, turning it into "default background"
-        seqCb = 2 * seq.size();
-        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter));
-
-        VERIFY_ARE_EQUAL(quirkExpectedAttribute, mainBuffer.GetAttributes());
-
-        seq = L"X";
-        seqCb = 2 * seq.size();
-        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter));
-
-        verifyLastAttribute(quirkExpectedAttribute);
-    }
-
-    /* Write a 256-color white on a 256-color black, make sure the quirk does not suppress it */
-    {
-        TextAttribute vtWhiteOnBlack256Attribute{};
-        vtWhiteOnBlack256Attribute.SetForeground(TextColor{ TextColor::DARK_WHITE, true });
-        vtWhiteOnBlack256Attribute.SetBackground(TextColor{ TextColor::DARK_BLACK, true });
-
-        // reset (disable intense from the last test) before setting both colors
-        seq = L"\x1b[m\x1b[38;5;7;48;5;0m"; // the quirk should *not* suppress this (!)
-        seqCb = 2 * seq.size();
-        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter));
-
-        VERIFY_ARE_EQUAL(vtWhiteOnBlack256Attribute, mainBuffer.GetAttributes());
-
-        seq = L"X";
-        seqCb = 2 * seq.size();
-        VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter));
-
-        verifyLastAttribute(vtWhiteOnBlack256Attribute);
-    }
-}
-
 void ScreenBufferTests::TestReflowEndOfLineColor()
 {
     BEGIN_TEST_METHOD_PROPERTIES()
diff --git a/src/host/ut_host/TextBufferTests.cpp b/src/host/ut_host/TextBufferTests.cpp
index 1f6a71312b7..2d6c1d1628e 100644
--- a/src/host/ut_host/TextBufferTests.cpp
+++ b/src/host/ut_host/TextBufferTests.cpp
@@ -1396,16 +1396,16 @@ void TextBufferTests::TestBackspaceStringsAPI()
         L"Using WriteCharsLegacy, write \\b \\b as a single string."));
     size_t aCb = 2;
     size_t seqCb = 6;
-    VERIFY_SUCCEEDED(DoWriteConsole(L"a", &aCb, si, false, waiter));
-    VERIFY_SUCCEEDED(DoWriteConsole(L"\b \b", &seqCb, si, false, waiter));
+    VERIFY_SUCCEEDED(DoWriteConsole(L"a", &aCb, si, waiter));
+    VERIFY_SUCCEEDED(DoWriteConsole(L"\b \b", &seqCb, si, waiter));
     VERIFY_ARE_EQUAL(cursor.GetPosition().x, x0);
     VERIFY_ARE_EQUAL(cursor.GetPosition().y, y0);
 
     seqCb = 2;
-    VERIFY_SUCCEEDED(DoWriteConsole(L"a", &seqCb, si, false, waiter));
-    VERIFY_SUCCEEDED(DoWriteConsole(L"\b", &seqCb, si, false, waiter));
-    VERIFY_SUCCEEDED(DoWriteConsole(L" ", &seqCb, si, false, waiter));
-    VERIFY_SUCCEEDED(DoWriteConsole(L"\b", &seqCb, si, false, waiter));
+    VERIFY_SUCCEEDED(DoWriteConsole(L"a", &seqCb, si, waiter));
+    VERIFY_SUCCEEDED(DoWriteConsole(L"\b", &seqCb, si, waiter));
+    VERIFY_SUCCEEDED(DoWriteConsole(L" ", &seqCb, si, waiter));
+    VERIFY_SUCCEEDED(DoWriteConsole(L"\b", &seqCb, si, waiter));
     VERIFY_ARE_EQUAL(cursor.GetPosition().x, x0);
     VERIFY_ARE_EQUAL(cursor.GetPosition().y, y0);
 }
diff --git a/src/host/ut_host/VtIoTests.cpp b/src/host/ut_host/VtIoTests.cpp
index 1a6085b498c..2f2ef1219b9 100644
--- a/src/host/ut_host/VtIoTests.cpp
+++ b/src/host/ut_host/VtIoTests.cpp
@@ -241,19 +241,19 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests
         std::string_view expected;
         std::string_view actual;
 
-        THROW_IF_FAILED(routines.WriteConsoleWImpl(*screenInfo, L"", written, false, waiter));
+        THROW_IF_FAILED(routines.WriteConsoleWImpl(*screenInfo, L"", written, waiter));
         expected = "";
         actual = readOutput();
         VERIFY_ARE_EQUAL(expected, actual);
 
         // Force-wrap because we write up to the last column.
-        THROW_IF_FAILED(routines.WriteConsoleWImpl(*screenInfo, L"aaaaaaaa", written, false, waiter));
+        THROW_IF_FAILED(routines.WriteConsoleWImpl(*screenInfo, L"aaaaaaaa", written, waiter));
         expected = "aaaaaaaa\r\n";
         actual = readOutput();
         VERIFY_ARE_EQUAL(expected, actual);
 
         // Force-wrap because we write up to the last column, but this time with a tab.
-        THROW_IF_FAILED(routines.WriteConsoleWImpl(*screenInfo, L"a\t\r\nb", written, false, waiter));
+        THROW_IF_FAILED(routines.WriteConsoleWImpl(*screenInfo, L"a\t\r\nb", written, waiter));
         expected = "a\t\r\n\r\nb";
         actual = readOutput();
         VERIFY_ARE_EQUAL(expected, actual);
diff --git a/src/host/writeData.cpp b/src/host/writeData.cpp
index 21b1cbee566..dcf49c54c00 100644
--- a/src/host/writeData.cpp
+++ b/src/host/writeData.cpp
@@ -24,14 +24,12 @@
 WriteData::WriteData(SCREEN_INFORMATION& siContext,
                      _In_reads_bytes_(cbContext) PCWCHAR pwchContext,
                      const size_t cbContext,
-                     const UINT uiOutputCodepage,
-                     const bool requiresVtQuirk) :
+                     const UINT uiOutputCodepage) :
     IWaitRoutine(ReplyDataType::Write),
     _siContext(siContext),
     _pwchContext(THROW_IF_NULL_ALLOC(reinterpret_cast<wchar_t*>(new byte[cbContext]))),
     _cbContext(cbContext),
     _uiOutputCodepage(uiOutputCodepage),
-    _requiresVtQuirk(requiresVtQuirk),
     _fLeadByteCaptured(false),
     _fLeadByteConsumed(false),
     _cchUtf8Consumed(0)
@@ -126,7 +124,6 @@ bool WriteData::Notify(const WaitTerminationReason TerminationReason,
     auto Status = DoWriteConsole(_pwchContext,
                                  &cbContext,
                                  _siContext,
-                                 _requiresVtQuirk,
                                  waiter);
 
     if (Status == CONSOLE_STATUS_WAIT)
diff --git a/src/host/writeData.hpp b/src/host/writeData.hpp
index 120689d52ac..4609b98d375 100644
--- a/src/host/writeData.hpp
+++ b/src/host/writeData.hpp
@@ -27,8 +27,7 @@ class WriteData : public IWaitRoutine
     WriteData(SCREEN_INFORMATION& siContext,
               _In_reads_bytes_(cbContext) PCWCHAR pwchContext,
               const size_t cbContext,
-              const UINT uiOutputCodepage,
-              const bool requiresVtQuirk);
+              const UINT uiOutputCodepage);
     ~WriteData();
 
     void SetLeadByteAdjustmentStatus(const bool fLeadByteCaptured,
@@ -49,7 +48,6 @@ class WriteData : public IWaitRoutine
     wchar_t* const _pwchContext;
     const size_t _cbContext;
     UINT const _uiOutputCodepage;
-    bool _requiresVtQuirk;
     bool _fLeadByteCaptured;
     bool _fLeadByteConsumed;
     size_t _cchUtf8Consumed;
diff --git a/src/server/ApiDispatchers.cpp b/src/server/ApiDispatchers.cpp
index 3ae2b735e91..96ddb0b674e 100644
--- a/src/server/ApiDispatchers.cpp
+++ b/src/server/ApiDispatchers.cpp
@@ -374,8 +374,6 @@ constexpr T saturate(auto val)
     std::unique_ptr<IWaitRoutine> waiter;
     size_t cbRead;
 
-    const auto requiresVtQuirk{ m->GetProcessHandle()->GetShimPolicy().IsVtColorQuirkRequired() };
-
     // We have to hold onto the HR from the call and return it.
     // We can't return some other error after the actual API call.
     // This is because the write console function is allowed to write part of the string and then return an error.
@@ -391,7 +389,7 @@ constexpr T saturate(auto val)
             TraceLoggingUInt32(a->NumBytes, "NumBytes"),
             TraceLoggingCountedWideString(buffer.data(), static_cast<ULONG>(buffer.size()), "Buffer"));
 
-        hr = m->_pApiRoutines->WriteConsoleWImpl(*pScreenInfo, buffer, cchInputRead, requiresVtQuirk, waiter);
+        hr = m->_pApiRoutines->WriteConsoleWImpl(*pScreenInfo, buffer, cchInputRead, waiter);
 
         // We must set the reply length in bytes. Convert back from characters.
         LOG_IF_FAILED(SizeTMult(cchInputRead, sizeof(wchar_t), &cbRead));
@@ -406,7 +404,7 @@ constexpr T saturate(auto val)
             TraceLoggingUInt32(a->NumBytes, "NumBytes"),
             TraceLoggingCountedString(buffer.data(), static_cast<ULONG>(buffer.size()), "Buffer"));
 
-        hr = m->_pApiRoutines->WriteConsoleAImpl(*pScreenInfo, buffer, cchInputRead, requiresVtQuirk, waiter);
+        hr = m->_pApiRoutines->WriteConsoleAImpl(*pScreenInfo, buffer, cchInputRead, waiter);
 
         // Reply length is already in bytes (chars), don't need to convert.
         cbRead = cchInputRead;
diff --git a/src/server/ConsoleShimPolicy.cpp b/src/server/ConsoleShimPolicy.cpp
index 7f6cc56d690..5ca506bd9a7 100644
--- a/src/server/ConsoleShimPolicy.cpp
+++ b/src/server/ConsoleShimPolicy.cpp
@@ -27,24 +27,6 @@ ConsoleShimPolicy::ConsoleShimPolicy(const HANDLE hProcess)
         const auto isInboxPowershell = til::equals_insensitive_ascii(clientName, L"powershell.exe");
         const auto isPwsh = til::equals_insensitive_ascii(clientName, L"pwsh.exe");
         _isPowershell = isInboxPowershell || isPwsh;
-
-        // Inside Windows, we are guaranteed that we're building alongside a new (good) inbox Powershell.
-        // Therefore, we can default _requiresVtColorQuirk to false.
-#ifndef __INSIDE_WINDOWS
-        // Outside of Windows, we need to check the OS version: Powershell was fixed in early Iron builds.
-        static auto doesInboxPowershellVersionRequireQuirk = [] {
-            OSVERSIONINFOEXW osver{};
-            osver.dwOSVersionInfoSize = sizeof(osver);
-            osver.dwBuildNumber = 20348; // Windows Server 2022 RTM
-
-            DWORDLONG dwlConditionMask = 0;
-            VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_LESS);
-
-            return VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE;
-        }();
-        _requiresVtColorQuirk = isInboxPowershell && doesInboxPowershellVersionRequireQuirk;
-        // All modern versions of pwsh.exe have been fixed, and we can direct users to update.
-#endif
     }
     CATCH_LOG();
 }
@@ -73,15 +55,3 @@ bool ConsoleShimPolicy::IsPowershellExe() const noexcept
 {
     return _isPowershell;
 }
-
-// Method Description:
-// - Returns true if the connected client application is known to
-//   attempt VT color promotion of legacy colors. See GH#6807 for more.
-// Arguments:
-// - <none>
-// Return Value:
-// - True as laid out above.
-bool ConsoleShimPolicy::IsVtColorQuirkRequired() const noexcept
-{
-    return _requiresVtColorQuirk;
-}
diff --git a/src/server/ConsoleShimPolicy.h b/src/server/ConsoleShimPolicy.h
index 38c42217100..120ed3f8a77 100644
--- a/src/server/ConsoleShimPolicy.h
+++ b/src/server/ConsoleShimPolicy.h
@@ -24,10 +24,8 @@ class ConsoleShimPolicy
     ConsoleShimPolicy(const HANDLE hProcess);
     bool IsCmdExe() const noexcept;
     bool IsPowershellExe() const noexcept;
-    bool IsVtColorQuirkRequired() const noexcept;
 
 private:
     bool _isCmd{ false };
     bool _isPowershell{ false };
-    bool _requiresVtColorQuirk{ false };
 };
diff --git a/src/server/IApiRoutines.h b/src/server/IApiRoutines.h
index 72386c4981e..579cbddb8f0 100644
--- a/src/server/IApiRoutines.h
+++ b/src/server/IApiRoutines.h
@@ -80,13 +80,11 @@ class __declspec(novtable) IApiRoutines
     [[nodiscard]] virtual HRESULT WriteConsoleAImpl(IConsoleOutputObject& context,
                                                     const std::string_view buffer,
                                                     size_t& read,
-                                                    bool requiresVtQuirk,
                                                     std::unique_ptr<IWaitRoutine>& waiter) noexcept = 0;
 
     [[nodiscard]] virtual HRESULT WriteConsoleWImpl(IConsoleOutputObject& context,
                                                     const std::wstring_view buffer,
                                                     size_t& read,
-                                                    bool requiresVtQuirk,
                                                     std::unique_ptr<IWaitRoutine>& waiter) noexcept = 0;
 
 #pragma region Thread Creation Info


Test patch: