Solução

Nome Valor
Vulnerabilidade Broken Object Level Authorization (BOLA)
CWE CWE-639
OWASP Top Ten A01_2021-Broken_Access_Control

Métodos mágicos1 e suas mágicas… Em uma instância da classe Request no Laravel, você pode ler o input do usuário simplesmente tentando ler um atributo do objeto. Com isso, ele irá ler o input da query string, body ou o parâmetro da URL, caso algum deles exista com esse nome. Do contrário retorna null.

Vejamos a implementação disso no Laravel 11:

/**
 * Get an input element from the request.
 *
 * @param  string  $key
 * @return mixed
 */
public function __get($key)
{
    return Arr::get(
        $this->all(),
        $key,
        fn () => $this->route($key)
    );
}

Sem entrar em detalhes de como $this->all() funciona, basicamente ele busca pelo campo com aquele nome em todos os inputs do usuário.

Exemplo: Se você ler o campo $request->name você não sabe como esse name foi enviado pelo usuário. Pode ser um query parameter, pode ser um JSON no body, pode ser um form parameter no body ou pode ser o nome de um parâmetro da URL. O Laravel vai buscar por um input chamado name em qualquer um desses lugares.

Ou seja, a validação feita em UpdatePostRequest está verificando se o usuário tem permissão para editar o post de ID $request->id. Mas o controller PostController está editando o post de ID $postId, que é um parâmetro de URL… Mas e $request->id, é um parâmetro de URL também? Ninguém sabe.

Tendo isso em mente, se a gente enviar na URL o ID do post de outro usuário mas enviar o ID de um post do nosso usuário em outro input (ex.: no body), potencialmente o ID validado em UpdatePostRequest será diferente do ID atualizado em PostController.

Exemplo de requisição PUT /posts/2:

{
    "id": 1,
    "title": "What is BOLA vulnerability?",
    "content": "I dunno..."
}

Ou seja, efetivamente o post que será alterado será o de ID 2 (na URL), mas a validação está sendo feita com o ID 1 (no body).


  1. Se você não sabe o que são métodos mágicos, sugiro que leia a documentação: https://www.php.net/manual/pt_BR/language.oop5.magic.php↩︎