Pessoal, eu ia colar o Juice Shop na tabela do post das três portas.
Tinha 13 findings com requisito ASVS e arquivo:linha. SQL concatenado, eval no username, CORS *, cesto de outro usuário. O modelo tinha trabalhado. A tabela ia ficar “mais completa”.
Aí li o package.json: probably the most modern and sophisticated insecure web application. Não é gap. É o produto.
O que você leva daqui: lab de propósito inseguro calibra o procedimento. Não entra nas três portas. Silêncio aqui não é “invariante manteve”. É não abrir issue no scoreboard dos outros.
1. A tabela errada
O post pai é sobre OSS que alguém usa de verdade. Formbricks, Dub, Cal.com, Magnitude. Issue de hardening, e-mail quando for exploitable, nada quando o denominador fecha.
Juice Shop e WebGoat não são essa classe. O README do WebGoat avisa: a máquina fica vulnerável de propósito; o default escuta em localhost. O SECURITY.md do Juice Shop pede contato só para o que não faz parte de nenhum hacking challenge. O resto já está no placar.
Somar 13 linhas naquela tabela seria o mesmo reflexo dos 23 findings que eu quase mandei. Volume. A pergunta de segurança some: disto aqui, o que vira issue?
Nada. Porque o sink já tem nome de challenge.
2. Round 1: o que a varredura achou
Estático. Sem PoC. Sem tráfego. Fatia estreita, não o monorepo. YAML de challenges depois, só pra recall. Issue: nenhuma.
Juice Shop v20.2.0. 13 findings (10 L1, 3 L2). 10 chaves do catálogo bateram depois, de 116.
| # | Problema | ASVS | Onde |
|---|---|---|---|
| 1 | Busca concatena q em SQL |
V1.2.4 |
routes/search.ts |
| 2 | Login concatena email em SQL | V1.2.4 |
routes/login.ts |
| 3 | Username via eval
|
V1.3.2 |
routes/userProfile.ts |
| 4 | Search query com bypassSecurityTrustHtml
|
V3.2.2 |
search-result.component.ts |
| 5 | Description HTML sem encoding | V3.2.2 |
search-result.component.ts |
| 6 | CORS default *
|
V3.4.2 |
server.ts |
| 7 | Cesto por id sem dono | V8.2.2 |
routes/basket.ts |
| 8 | Senha em MD5 | V11.4.1 |
lib/insecurity.ts |
| 9 | Admin seed admin123
|
V6.3.2 |
data/static/users.yml |
| 10 | FTP: allowlist de extensão depois null-byte | V5.3.2 |
routes/fileServer.ts |
| 11 |
fetch(imageUrl) sem allowlist |
V1.3.6 |
routes/profileImageUrlUpload.ts |
| 12 | Redirect com url.includes
|
V3.7.2 |
lib/insecurity.ts |
| 13 | Chave RSA do JWT no source | V13.3.1 |
lib/insecurity.ts |
WebGoat. 11 findings. Uma lição de SSRF não abre URL: não entrei como SSRF.
| # | Problema | ASVS | Onde |
|---|---|---|---|
| 1 | SQL concatena params | V1.2.4 |
SqlInjectionLesson5a.java |
| 2 | XML parser com entidade externa | V1.5.1 |
CommentsCache.java |
| 3 | Upload usa fullName no path |
V5.3.2 |
ProfileUploadBase.java |
| 4 | XSS refletido em HTML | V1.2.1 |
CrossSiteScriptingLesson5a.java |
| 5 | Comment stored sem encoding | V3.2.2 |
StoredXssComments.java |
| 6 | Profile por userId sem dono |
V8.2.2 |
IDORViewOtherProfile.java |
| 7 | JWT jku busca chave na URL do token |
V9.1.3 |
JWTHeaderJKUEndpoint.java |
| 8 | Default admin / admin
|
V6.3.2 |
DefaultCredentialsTask.java |
| 9 | Lista de users sem role (Needs-runtime) | V8.2.1 |
MissingFunctionACUsers.java |
| 10 |
redirect: sem allowlist |
V3.7.2 |
OpenRedirectRealRedirect.java |
| 11 | HMAC JWT com palavra do source | V13.3.1 |
JWTSecretKeyEndpoint.java |
Round 1 responde se inventa ID, inventa finding ou vaza PoC. Não responde se cobriu o placar.
3. A academia não é o jogo
Essa tabela não é troféu. É o Juice Shop fazendo o trabalho que a OWASP se propôs: um lugar onde a gente pode errar de propósito, ver o sink com nome, e voltar pro código que paga boleto com o olho mais treinado.
Quem mantém isso (e o WebGoat no mesmo espírito) está doando academia pra uma indústria que, no dia a dia, mistura pressão de entrega com risco de verdade. Sem esse tipo de lab, o atalho vira “rodei o scanner, achei 23 coisas, mandei pro tracker”. Com ele, dá pra ensaiar o reflexo certo: isto aqui é aula. Aquilo ali é produto. A porta não é a mesma.
Ferramenta ajuda. Prompt ajuda. Modelo de raciocínio alto ajuda. Nada disso substitui a pessoa no time que já viu o suficiente de segurança pra não confundir volume com cuidado.
O profissional avançado em AppSec não é o que gera a lista mais longa. É o que segura a mão do time quando a lista pede 13 issues num CTF. É o que olha um eval no username e pergunta: isso é challenge ou é o checkout de amanhã? É o que sabe que silêncio também é ofício. Não o silêncio de quem não olhou. O de quem olhou e escolheu não fazer barulho no lugar errado.
Time sem essa voz vira fábrica de card. Time com essa voz usa o Juice Shop como aquecimento e reserva o tracker pra quem realmente vai ler a issue no sábado.
O checklist de lab vs produto, se você quiser copiar: está no gist. O post das três portas continua sendo o mapa quando o alvo é OSS de verdade.
Takeaway: 13 sinks, zero issues, porque academia não se reporta como incidente. O que se leva pro time é o julgamento.
No seu time, quem é a pessoa que olha uma tabela dessas e pergunta a porta, em vez de abrir treze cards?
Top comments (0)