Your instinct is correct: a full node can lie-by-omission to a light client and deny them proof that a transaction was included in a block. This is a well-documented vulnerability of SPV wallets and the only mitigation really is to connect to more peers (you only need one "honest" peer).
This problem is also somewhat addressed by BIP157 aka "Neutrino". In this protocol, the light client scans entire blocks for its own transactions. It knows which blocks to check based on filters provided by full nodes. Of course, this brings us back to the first issue: what if a full node provides an invalid filter? Eventually we might see a soft fork that requires valid filters to be inserted in some part of the block, secured by proof-of-work.
Currently, BIP157 offers this:
Unless securely connected to a trusted peer that is serving filter
headers, the client SHOULD connect to multiple outbound peers that
support each filter type to mitigate the risk of downloading incorrect
headers. If the client receives conflicting filter headers from
different peers for any block and filter type, it SHOULD interrogate
them to determine which is faulty. The client SHOULD use getcfheaders
and/or getcfcheckpt to first identify the first filter headers that
the peers disagree on. The client then SHOULD download the full block
from any peer and derive the correct filter and filter header. The
client SHOULD ban any peers that sent a filter header that does not
match the computed one.