Practical guide

OWASP Top 10 (2025): how apps break and what to do about it.

The ten most common web application risks according to OWASP, each with a short example of the flaw, the fix that matters and a checklist you can apply to your own app this week.

O que é o Top 10What the Top 10 is

O OWASP Top 10 é um documento de conscientização da Open Worldwide Application Security Project: as dez categorias de risco mais críticas em aplicações web, montadas a partir de dados de testes de segurança reais e de uma pesquisa com a comunidade. A edição mais recente é a de 2025. Ele não é uma lista de tudo que pode dar errado nem um padrão de conformidade; é um ponto de partida para decidir o que corrigir primeiro.The OWASP Top 10 is an awareness document from the Open Worldwide Application Security Project: the ten most critical risk categories for web applications, built from real security-testing data and a community survey. The latest edition is 2025. It is not a list of everything that can go wrong nor a compliance standard; it is a starting point for deciding what to fix first.

Como usar: uma categoria é um grupo de falhas (CWEs), não uma falha só. Leia cada seção como “o que procurar no meu código” e “qual controle impede”. Para cabeçalhos HTTP, SQL injection e XSS em detalhe, veja as notas de segurança já publicadas aqui.How to use it: a category is a group of flaws (CWEs), not a single flaw. Read each section as “what to look for in my code” and “which control stops it”. For HTTP headers, SQL injection and XSS in depth, see the other security notes published here.

A lista de 2025 de relanceThe 2025 list at a glance

IDCategoriaCategoryDefesa principalMain defence
A01Broken Access ControlChecar permissão no servidor, em toda requisição, negando por padrãoCheck permission on the server, on every request, deny by default
A02Security MisconfigurationConfiguração segura repetível, sem padrões nem debug em produçãoRepeatable secure configuration, no defaults or debug in production
A03Software Supply Chain FailuresLockfile, SBOM, varredura de dependências, CI com permissões mínimasLockfile, SBOM, dependency scanning, least-privilege CI
A04Cryptographic FailuresTLS em tudo, algoritmos modernos, hash de senha lento, chaves fora do códigoTLS everywhere, modern algorithms, slow password hashing, keys outside code
A05InjectionConsultas parametrizadas e codificação de saídaParameterised queries and output encoding
A06Insecure DesignModelagem de ameaças e limites de abuso desde o projetoThreat modelling and abuse limits from the design stage
A07Authentication FailuresMFA, proteção contra força bruta, sessões segurasMFA, brute-force protection, secure sessions
A08Software or Data Integrity FailuresVerificar assinatura e origem de código e dados; evitar desserialização inseguraVerify signature and origin of code and data; avoid unsafe deserialisation
A09Security Logging and Alerting FailuresRegistrar eventos de segurança e alertar de verdadeLog security events and actually alert on them
A10Mishandling of Exceptional ConditionsFalhar de forma fechada, tratar todos os erros, não vazar detalhesFail closed, handle every error, leak no details

Em relação à edição de 2021, a de 2025 mantém o controle de acesso quebrado em primeiro lugar (a SSRF, antes categoria própria, foi incorporada a ele), sobe a configuração incorreta para o segundo lugar, amplia “componentes vulneráveis” para falhas na cadeia de suprimentos e acrescenta o tratamento de condições excepcionais. Confira a lista oficial para os detalhes de cada mudança.Compared with 2021, the 2025 edition keeps broken access control first (SSRF, previously its own category, was folded into it), moves misconfiguration up to second, widens “vulnerable components” into supply chain failures and adds the mishandling of exceptional conditions. Check the official list for the details of each change.

A01: Controle de acesso quebradoA01: Broken access control

A falha: o usuário consegue fazer ou ver o que não deveria. Exemplo clássico: GET /api/faturas/1042 devolve a fatura de outra pessoa quando você troca o número (IDOR). Também entram aqui acesso a rotas de admin sem checar o papel, CORS aberto demais e SSRF, quando o servidor busca uma URL escolhida pelo atacante (por exemplo o endereço de metadados da nuvem).The flaw: the user can do or see what they should not. Classic example: GET /api/invoices/1042 returns someone else’s invoice when you change the number (IDOR). Also here: admin routes without a role check, overly open CORS and SSRF, when the server fetches a URL chosen by the attacker (for example the cloud metadata address).

// ruim: confia no id da URL
app.get('/api/invoices/:id', auth, async (req, res) => {
  res.json(await db.invoice.findById(req.params.id));
});

// bom: o dono vem da sessão, não do cliente
app.get('/api/invoices/:id', auth, async (req, res) => {
  const inv = await db.invoice.findOne({ id: req.params.id, ownerId: req.user.id });
  if (!inv) return res.sendStatus(404);
  res.json(inv);
});
  • Negar por padrão; liberar por papel e por dono do recurso, no servidor. Esconder o botão no front não é controle.Deny by default; allow by role and by resource owner, on the server. Hiding the button in the front end is not a control.
  • Centralizar a checagem (middleware ou política) em vez de repetir if em cada rota.Centralise the check (middleware or policy) instead of repeating if in every route.
  • Contra SSRF: lista de destinos permitidos, bloquear IPs internos e de metadados, não seguir redirecionamentos às cegas.Against SSRF: allow-list of destinations, block internal and metadata IPs, do not follow redirects blindly.
  • Testes automáticos: “o usuário A não lê o recurso do usuário B” para cada endpoint.Automated tests: “user A cannot read user B’s resource” for each endpoint.

A02: Configuração incorreta de segurançaA02: Security misconfiguration

A falha: o software é seguro, a configuração não. Senhas padrão, bucket público, modo debug ligado, listagem de diretório, mensagens de erro com stack trace, cabeçalhos de segurança ausentes, portas abertas à toa, permissões amplas demais na nuvem.The flaw: the software is secure, the configuration is not. Default passwords, public buckets, debug mode on, directory listing, error messages with stack traces, missing security headers, needlessly open ports, overly broad cloud permissions.

  • Definir a configuração como código (Terraform, Docker, Nginx versionados) e revisar em PR; o mesmo molde para dev, teste e produção, mudando só os segredos.Define configuration as code (Terraform, Docker, Nginx under version control) and review it in PRs; the same template for dev, test and production, changing only the secrets.
  • Remover o que não é usado: contas, rotas de exemplo, portas, recursos e funcionalidades.Remove what is unused: accounts, sample routes, ports, features.
  • Cabeçalhos HTTP e CSP: veja a nota de segurança de apps web. Parsers de XML sem entidades externas (XXE) também ficam aqui.HTTP headers and CSP: see the web app security note. XML parsers with external entities disabled (XXE) also belong here.
  • Varrer a infraestrutura com regularidade (por exemplo, um scanner de IaC no CI) e alertar em desvio de configuração.Scan infrastructure regularly (for example an IaC scanner in CI) and alert on configuration drift.

A03: Falhas na cadeia de suprimentosA03: Software supply chain failures

A falha: o problema vem de código que você não escreveu: dependências vulneráveis ou desatualizadas, pacote malicioso com nome parecido (typosquatting), mantenedor comprometido, imagem de contêiner adulterada, pipeline de CI que roda código não confiável com acesso a segredos.The flaw: the problem comes from code you did not write: vulnerable or outdated dependencies, a malicious package with a look-alike name (typosquatting), a compromised maintainer, a tampered container image, a CI pipeline running untrusted code with access to secrets.

npm ci                 # instala exatamente o lockfile
npm audit --omit=dev   # vulnerabilidades conhecidas
pip-audit              # equivalente em Python
trivy fs .             # dependências e IaC no repositório
  • Versionar o lockfile e instalar com npm ci/equivalente; fixar imagens por digest.Commit the lockfile and install with npm ci/equivalent; pin images by digest.
  • Automatizar atualizações (Dependabot ou Renovate) e varredura no CI; ter um prazo para corrigir vulnerabilidades críticas.Automate updates (Dependabot or Renovate) and scan in CI; set a deadline for fixing critical vulnerabilities.
  • Gerar um SBOM (lista de componentes) e saber o que está em produção.Generate an SBOM (component list) and know what runs in production.
  • No CI: permissões mínimas no token, ações de terceiros fixadas por commit, segredos nunca expostos a PRs de forks, credenciais de nuvem por OIDC em vez de chaves longas.In CI: minimal token permissions, third-party actions pinned by commit, secrets never exposed to fork PRs, cloud credentials via OIDC instead of long-lived keys.
  • Antes de adicionar uma dependência, pergunte se precisa dela; menos pacotes, menos superfície.Before adding a dependency, ask whether you need it; fewer packages, less surface.

A04: Falhas criptográficasA04: Cryptographic failures

A falha: dado sensível sem proteção ou com cripto fraca: tráfego em HTTP, senha com MD5/SHA-1 sem sal, algoritmos antigos, chaves no repositório, números aleatórios previsíveis (Math.random() para tokens), certificados sem validação.The flaw: sensitive data unprotected or protected by weak crypto: HTTP traffic, passwords hashed with MD5/SHA-1 without salt, old algorithms, keys in the repository, predictable random numbers (Math.random() for tokens), unvalidated certificates.

  • Classificar os dados e guardar só o necessário; o que não existe não vaza.Classify data and keep only what is needed; what does not exist cannot leak.
  • TLS 1.2+ em tudo, com HSTS; cifrar em repouso os dados sensíveis (disco, banco, backup).TLS 1.2+ everywhere, with HSTS; encrypt sensitive data at rest (disk, database, backup).
  • Senhas: Argon2id, scrypt ou bcrypt (nunca SHA simples). Tokens: gerador criptográfico (crypto.randomBytes, secrets.token_urlsafe).Passwords: Argon2id, scrypt or bcrypt (never plain SHA). Tokens: a cryptographic generator (crypto.randomBytes, secrets.token_urlsafe).
  • Chaves em um gerenciador de segredos (KMS, Vault, Secrets Manager), com rotação; nunca no Git. Não inventar algoritmo próprio.Keys in a secrets manager (KMS, Vault, Secrets Manager), with rotation; never in Git. Never invent your own algorithm.

A05: InjeçãoA05: Injection

A falha: dado do usuário é interpretado como comando: SQL, NoSQL, comandos do sistema, LDAP, templates e também XSS (injeção no navegador). A causa é sempre a mesma: concatenar texto não confiável numa linguagem interpretada.The flaw: user data is interpreted as a command: SQL, NoSQL, OS commands, LDAP, templates and also XSS (injection in the browser). The cause is always the same: concatenating untrusted text into an interpreted language.

// ruim
db.query("SELECT * FROM users WHERE email = '" + email + "'");

// bom: parâmetro separado do comando
db.query("SELECT * FROM users WHERE email = $1", [email]);
  • Consultas parametrizadas ou ORM bem usado; nunca montar SQL por concatenação, nem em ORDER BY (use lista permitida de colunas).Parameterised queries or a well-used ORM; never build SQL by concatenation, not even in ORDER BY (use an allow-list of columns).
  • Comandos do sistema: evitar o shell; chamar o programa com lista de argumentos (subprocess.run([...]), sem shell=True).OS commands: avoid the shell; call the program with an argument list (subprocess.run([...]), without shell=True).
  • XSS: codificar a saída conforme o contexto (HTML, atributo, JS), usar o auto-escape do framework, evitar innerHTML/dangerouslySetInnerHTML e adicionar CSP.XSS: encode output for its context (HTML, attribute, JS), use the framework’s auto-escaping, avoid innerHTML/dangerouslySetInnerHTML and add CSP.
  • Validar a entrada (tipo, tamanho, formato) como defesa em camadas, mas sem confiar só nela. O usuário do banco da aplicação deve ter o mínimo de privilégio.Validate input (type, length, format) as defence in depth, but do not rely on it alone. The application’s database user should have minimum privilege.

A06: Design inseguroA06: Insecure design

A falha: o erro está no projeto, e código perfeito não o conserta. Exemplos: recuperação de senha por “pergunta secreta”, cupom que pode ser reusado em paralelo, fluxo de compra sem limite por usuário, API que devolve o objeto inteiro e confia que o front esconda os campos.The flaw: the mistake is in the design, and perfect code cannot fix it. Examples: password recovery by “secret question”, a coupon that can be reused in parallel, a purchase flow with no per-user limit, an API that returns the whole object and trusts the front end to hide fields.

  • Modelar ameaças antes de codar (STRIDE: falsificação, adulteração, repúdio, vazamento, negação de serviço, elevação de privilégio) e escrever “casos de abuso” junto com as histórias de usuário.Threat-model before coding (STRIDE: spoofing, tampering, repudiation, information disclosure, denial of service, elevation of privilege) and write “abuse cases” next to user stories.
  • Limites de uso (rate limit, cotas, tamanho de upload), separação de ambientes e de privilégios, menor privilégio por padrão.Usage limits (rate limit, quotas, upload size), separation of environments and privileges, least privilege by default.
  • Regras de negócio críticas com transações e checagens atômicas (condição de corrida); nunca confiar em preço ou desconto vindo do cliente.Critical business rules with transactions and atomic checks (race conditions); never trust a price or discount coming from the client.
  • Revisão de segurança de cada recurso novo grande; testes que tentam abusar, não só usar.Security review for each large new feature; tests that try to abuse, not only use.

A07: Falhas de autenticaçãoA07: Authentication failures

A falha: o app aceita força bruta e credential stuffing (senhas vazadas de outros sites), permite senhas fracas, expõe o ID de sessão na URL, não invalida a sessão no logout, tem recuperação de conta fraca.The flaw: the app accepts brute force and credential stuffing (passwords leaked from other sites), allows weak passwords, exposes the session ID in the URL, does not invalidate the session on logout, has weak account recovery.

  • MFA, de preferência passkeys/WebAuthn; ou delegar a um provedor (OIDC) em vez de reinventar o login (veja a nota de SSO).MFA, preferably passkeys/WebAuthn; or delegate to a provider (OIDC) instead of reinventing login (see the SSO note).
  • Senhas: tamanho mínimo longo (12+), sem regras de composição absurdas, checar contra listas de senhas vazadas, permitir gerenciadores de senha.Passwords: long minimum length (12+), no absurd composition rules, check against breached-password lists, allow password managers.
  • Limitar tentativas por conta e por IP, com atraso crescente; mensagem de erro igual para “usuário não existe” e “senha errada”.Limit attempts per account and per IP, with increasing delay; the same error message for “user does not exist” and “wrong password”.
  • Sessão: ID aleatório novo após o login, cookie HttpOnly; Secure; SameSite=Lax, expiração e invalidação no servidor ao sair.Session: new random ID after login, cookie HttpOnly; Secure; SameSite=Lax, expiry and server-side invalidation on logout.

A08: Integridade de software e dadosA08: Software or data integrity failures

A falha: o app confia em código ou dados sem verificar a origem: atualização automática sem assinatura, script de CDN sem verificação, objeto serializado vindo do cliente (pickle, desserialização Java), artefato de build que ninguém comprova de onde veio.The flaw: the app trusts code or data without verifying origin: auto-update without signature, a CDN script without verification, a serialised object coming from the client (pickle, Java deserialisation), a build artefact nobody can prove the origin of.

  • Nunca desserializar dado não confiável com formatos que executam código; usar JSON com validação de esquema.Never deserialise untrusted data with formats that execute code; use JSON with schema validation.
  • Scripts de terceiros com Subresource Integrity: <script src="…" integrity="sha384-…" crossorigin="anonymous">.Third-party scripts with Subresource Integrity: <script src="…" integrity="sha384-…" crossorigin="anonymous">.
  • Assinar e verificar artefatos e imagens (por exemplo com Sigstore/cosign); revisão obrigatória de código e proteção da branch principal.Sign and verify artefacts and images (for example with Sigstore/cosign); mandatory code review and a protected main branch.
  • Proteger a integridade de dados importantes com assinatura ou HMAC (cookies, links de e-mail, webhooks verificados pela assinatura do remetente).Protect the integrity of important data with a signature or HMAC (cookies, email links, webhooks verified by the sender’s signature).

A09: Falhas de log e alertaA09: Logging and alerting failures

A falha: um ataque acontece e ninguém vê. Logins falhos não são registrados, os logs ficam só na máquina atacada, ninguém recebe alerta, ou o log guarda senhas e tokens. Sem isso, o tempo entre invasão e descoberta é de meses.The flaw: an attack happens and nobody sees it. Failed logins are not recorded, logs stay only on the attacked machine, nobody gets an alert, or the log stores passwords and tokens. Without this, the time between breach and discovery is months.

  • Registrar eventos de segurança: logins (sucesso e falha), mudança de senha e de permissão, acesso negado, falhas de validação, ações administrativas. Incluir quem, o quê, quando e de onde.Log security events: logins (success and failure), password and permission changes, access denied, validation failures, admin actions. Include who, what, when and from where.
  • Logs estruturados (JSON), enviados para fora do servidor e com retenção definida; nunca registrar senha, token ou dado pessoal desnecessário.Structured logs (JSON), shipped off the server with a defined retention; never log passwords, tokens or unneeded personal data.
  • Alertas acionáveis (picos de 401/403, muitos logins falhos, uso de conta de admin fora do horário) com responsável e um plano de resposta a incidentes testado. Veja a nota de observabilidade.Actionable alerts (spikes of 401/403, many failed logins, admin account use out of hours) with an owner and a tested incident-response plan. See the observability note.
  • Cuidado com injeção em logs: remover quebras de linha do dado do usuário antes de registrar.Beware of log injection: strip newlines from user data before logging.

A10: Tratamento de condições excepcionaisA10: Mishandling of exceptional conditions

A falha: o app reage mal ao inesperado: erro não tratado que derruba o serviço, exceção que “abre” em vez de “fechar” (a checagem de permissão falha e o acesso é liberado), mensagem de erro que revela o banco ou o caminho de arquivos, recurso não liberado após falha, estado inconsistente no meio de uma transação.The flaw: the app reacts badly to the unexpected: an unhandled error that takes the service down, an exception that “fails open” (the permission check fails and access is granted), an error message revealing the database or file paths, a resource not released after failure, inconsistent state in the middle of a transaction.

// ruim: se a checagem lançar erro, o acesso passa
try { allowed = await can(user, 'delete', doc); } catch (e) { log(e); }
if (allowed !== false) remove(doc);

// bom: falha fechada
let allowed = false;
try { allowed = await can(user, 'delete', doc); } catch (e) { log.error(e); }
if (!allowed) return res.sendStatus(403);
  • Falhar de forma fechada: na dúvida, negar. Definir um tratador de erros global que devolve mensagem genérica ao cliente e registra o detalhe no servidor.Fail closed: when in doubt, deny. Define a global error handler that returns a generic message to the client and logs the detail on the server.
  • Tratar explicitamente entradas ausentes, nulas, grandes demais e timeouts de dependências; usar transações com rollback e liberar recursos em finally.Explicitly handle missing, null and oversized input and dependency timeouts; use transactions with rollback and release resources in finally.
  • Limites de recurso (tamanho, tempo, memória, taxa) para que um erro ou abuso não vire negação de serviço.Resource limits (size, time, memory, rate) so an error or abuse does not become denial of service.
  • Testar o caminho de erro: testes de falha, fuzzing e injeção de falhas das dependências.Test the error path: failure tests, fuzzing and fault injection of dependencies.

Plano de ação para o seu appAction plan for your app

Tudo de uma vez é impossível; ordene por risco e esforço. Uma ordem que costuma funcionar:Everything at once is impossible; order by risk and effort. An order that usually works:

QuandoWhenAçãoActionCategoriasCategories
Hoje (1 hora)Today (1 hour)Ligar HTTPS e HSTS; desligar debug; tirar segredos do Git e rotacionar os vazados; ligar MFA nas contas de admin e da nuvemEnable HTTPS and HSTS; turn off debug; remove secrets from Git and rotate leaked ones; enable MFA on admin and cloud accountsA02, A04, A07
Esta semanaThis weekDependabot/Renovate e audit no CI; lockfile; consultas parametrizadas em todo lugar; checagem de dono em cada endpoint; cabeçalhos e CSPDependabot/Renovate and audit in CI; lockfile; parameterised queries everywhere; owner check on every endpoint; headers and CSPA01, A02, A03, A05
Este mêsThis monthRate limit e bloqueio de login; tratador de erros global; logs de segurança centralizados com alertas; SBOM; CI com permissões mínimasRate limit and login lockout; global error handler; centralised security logs with alerts; SBOM; least-privilege CIA03, A07, A09, A10
ContínuoOngoingModelagem de ameaças a cada recurso grande; testes de autorização e de abuso; revisão de código com foco em segurança; teste de invasão periódicoThreat modelling for each large feature; authorisation and abuse tests; security-focused code review; periodic penetration testA01, A06, A08
Ferramentas ajudam, não substituem: SAST (Semgrep, CodeQL), DAST (OWASP ZAP), varredura de dependências e de segredos (gitleaks, Trivy) encontram a parte repetitiva. Falhas de autorização e de lógica de negócio (A01, A06) quase sempre exigem teste e revisão humana. Teste apenas sistemas que você é dono ou tem autorização escrita para testar.Tools help, they do not replace: SAST (Semgrep, CodeQL), DAST (OWASP ZAP), dependency and secret scanning (gitleaks, Trivy) find the repetitive part. Authorisation and business-logic flaws (A01, A06) almost always need human testing and review. Only test systems you own or have written authorisation to test.

Atividade: auditar um endpoint (45 minutos)Activity: audit one endpoint (45 minutes)

O que fazer: escolha um endpoint do seu app que leia ou altere dados de um usuário. Com duas contas de teste, tente: (1) acessar o recurso de A estando logado como B; (2) enviar aspas simples e <script> em cada campo; (3) repetir o login errado 20 vezes; (4) mandar um corpo vazio, enorme e com tipos errados; (5) conferir se cada tentativa apareceu nos logs. Anote o que passou e corrija na ordem A01, A05, A07, A10, A09.What to do: pick one endpoint of your app that reads or changes a user’s data. With two test accounts, try: (1) accessing A’s resource while logged in as B; (2) sending a single quote and <script> in every field; (3) failing the login 20 times; (4) sending an empty, huge and wrongly typed body; (5) checking that each attempt showed up in the logs. Note what got through and fix in the order A01, A05, A07, A10, A09.

Resultado esperado: é comum achar pelo menos uma falha de autorização ou de log na primeira rodada; o valor está em transformar cada achado em um teste automático para que não volte.Expected result: finding at least one authorisation or logging gap in the first round is common; the value is in turning each finding into an automated test so it does not come back.

Cola e revisãoCheat sheet and review

ColaCheat sheet

PerguntaQuestionRegra curtaShort rule
Quem pode?Who can?Servidor decide, negar por padrão (A01)Server decides, deny by default (A01)
O que é meu código?What is my code?Dependências são código seu: travar, varrer, atualizar (A03, A08)Dependencies are your code: lock, scan, update (A03, A08)
O que entra?What comes in?Dado é dado, nunca comando: parametrizar e codificar (A05)Data is data, never a command: parameterise and encode (A05)
O que fica?What is stored?Cifrar, guardar pouco, chaves fora do código (A04)Encrypt, store little, keys outside code (A04)
E se falhar?What if it fails?Falhar fechado, mensagem genérica, log detalhado (A09, A10)Fail closed, generic message, detailed log (A09, A10)

Perguntas de revisãoReview questions

  • Por que esconder um botão no front-end não é controle de acesso, e onde a checagem deve ficar?Why is hiding a button in the front end not access control, and where should the check live?
  • Qual a diferença entre a causa de uma injeção SQL e a de um XSS, e o que as duas defesas têm em comum?What is the difference between the cause of SQL injection and XSS, and what do the two defences have in common?
  • Dê um exemplo de falha de design (A06) que nenhuma correção de código resolve.Give an example of a design flaw (A06) that no code fix resolves.
  • O que significa “falhar de forma fechada” e como você testaria isso?What does “fail closed” mean and how would you test it?
FontesSources