O tipo embutido no dado
Quando o dado carrega o próprio tipo e o servidor usa esse tipo para escolher código, o cliente escolhe o código.
Alguns formatos deixam o dado dizer o que ele é: um campo _type, __class__, $type. O servidor lê esse campo e escolhe um handler ou uma classe a partir dele. Enquanto o dado vem de dentro, parece organizado. Quando o dado vem do cliente, o cliente passa a escolher qual código roda.
Um exemplo de brinquedo: um registro handlers = { preference: ..., admin_report: ... } e a linha handlers[blob._type](blob). O app só manda _type igual a preference, mas basta o blob trazer "_type":"admin_report" para o servidor rodar o handler interno. O dado virou um seletor de código.
Esse é o degrau que, em desserializadores poderosos, leva ao pior caso: se o _type nomeia uma CLASSE qualquer e o desserializador a reconstrói, o atacante decide qual objeto nasce (veja cadeia de gadgets). O conserto é tratar o dado como dado: nada de tipo embutido; variantes só por uma lista de permissão fixa no servidor.