Tendermint consensus requires $\gt\frac{2}{3}$ of validators to sign a block for it to be included in the blockchain. Tendermint light clients are initialized with all the validators on their blockchain. To update a light client, a relayer submits a block. If enough known validators have signed the submitted block, the light client updates its validator set and merkle root to be the same as the submitted block's.
Because Tendermint only includes blocks if $\gt\frac{2}{3}$ of validators agree, $\frac{1}{3}$ of validators being honest will stop a malicious block from being included. Thus, Tendermint light clients can accept new blocks that $\geq \frac{1}{3}$ of validators they know have signed.
Accepting blocks that $\geq \frac{1}{3}$ of validators have signed creates the lightest possible light client, but comes with the tradeoff that the light client is unsafe if more than a third of a blockchain's validators are malicious. One can increase the trust threshold to $\geq\frac{2}{3}$ if they'd like the same safety level as Tendermint consensus. As of January 2023, the Hermes relayer uses a $\frac{2}{3}$ trust threshold by default1.
Thank you to Susannah Evans for reviewing and correcting my many errors as I learned about light clients.
I understand this in less detail, but because Bao asked, here's a sketch of how IBC is built on top of a light client like this:
hash(connection|channel|packet_sequence|packet_data)
to the sending chain's merkle KV store.connection|channel|packet_sequence|packet_data
that hashes to a value which is in the light client's merkle root.You can imagine ACKs working the same way, and timeouts being a matter of submiting an update client on the sending chain that contains a block header that is after the specified timeout.