Do I need external pullups to operate the I2C peripheral on an STM32L412? I was assuming the internal pullups for the GPIO would be sufficient but the communications look very slow (pictured). It seems like the ACK bit is there (9th clock pulse low), but nothing happens afterward.
Yes you do, as the I2C peripheral uses open-drain pins (or very similar to open-drain) so all they can do is assert the lines low. Also the pull-ups can be different values for different I2C speeds so they have to be external for that flexibility. I usually start with 4k7 (as awjlogan suggested too) and you can adjust from there if needed.
Yes, you need external pull up resistors. The typical pull up value for the STM32 microcontrollers is 40 k\$\Omega\$ (assuming they're even active). You can calculate a correct value, but if you just want to get working, a 4.7 k\$\Omega\$ resistor will get you started.
Actually whether you need external pull-ups depends on how fast you want to communicate.
Based on your scope photo you are using about 200 kHz speed and the waveform is too slow, so yes, in this case, you definitely need external resistors. In fact, under normal use, the pull-ups are usually needed, but under special cases where communicatiom speed is slow you can use only the internal pull-ups.