
Este é um scanner para CVE-2025-29927.
Este é um scanner de nível profissional projetado para detectar a vulnerabilidade de bypass de middleware CVE-2025-29927 em aplicações Next.js.
X-Middleware-Subrequest criados para contornar o middleware do Next.jspip install -r requirements.txt playwright install
### Executar o scanner```bash
python main.py --domain https://example.com --threads 10 --timeout 10 --save
python main.py --help
| Opção | Descrição |
|----------------|--------------------------------------------|
| `--domain` | URL base do site alvo (obrigatório) |
| `--user-agent` | User-agent personalizado (padrão: string do Chrome) |
| `--timeout` | Tempo limite da solicitação (padrão: 10 segundos) |
| `--proxy` | Endereço do proxy (opcional) |
| `--save` | Salvar resultados em `results.txt` |
| `--threads` | Número de threads (padrão: 10) |
| `--wordlist` | Worlist inclui Caminhos Comuns |
---
## 🐳 Uso do Docker
### Construir a Imagem Docker```bash
docker build -t cve-scanner .
docker run -it --rm cve-scanner --domain https://example.com --save
---
## ⚙️ GitHub Actions
Este projeto inclui um workflow do GitHub Actions para testar a configuração no push. Ele:
- Instala dependências
- Instala navegadores Playwright
- Executa uma verificação `--help`
Veja `.github/workflows/python.yml`.
---
## 🧱 Estrutura```
.
├── main.py # Entry point
├── config.py # CLI parser
├── crawler.py # Playwright crawler
├── scanner.py # Multi-threaded vulnerability testing
├── requirements.txt
├── Dockerfile
└── .github/workflows
Visão Geral da Vulnerabilidade CVE-2025-29927
CVE-2025-29927 é uma falha crítica de segurança no Next.js que permite a invasores contornar a autenticação e autorização baseadas em middleware. Ao incluir um cabeçalho interno especial (X-Middleware-Subrequest) nas requisições HTTP, um invasor pode enganar o servidor Next.js para pular a execução do middleware, obtendo assim acesso a rotas protegidas. Na prática, uma requisição que normalmente seria bloqueada pelo middleware de autenticação (por exemplo, retornando 401/403 ou redirecionando para login) é processada normalmente se este cabeçalho estiver presente, efetivamente contornando as verificações de segurança. Esta vulnerabilidade afeta as versões do Next.js 11.1.4 até 15.2.2, e os administradores são instados a aplicar patches ou implementar mitigações (como remover este cabeçalho em proxies) para proteger suas aplicações.
Detectar esta vulnerabilidade em uma aplicação web requer descobrir endpoints internos e testá-los com o cabeçalho malicioso para verificar se o acesso não autorizado é possível. Abaixo está um plano de design para um script Python avançado que irá rastrear um site alvo (com suporte total a JavaScript) e escanear por CVE-2025-29927, atendendo a todos os requisitos especificados.
Para atender ao requisito de crawling profundo incluindo conteúdo renderizado por JavaScript, usaremos Playwright (preferível ao Selenium por sua velocidade e API moderna). Playwright é uma poderosa biblioteca de automação de navegador headless que pode lidar com aplicações web dinâmicas e frameworks JS modernos. Comparado ao Selenium, Playwright oferece uma API mais moderna (construída sobre o Protocolo Chrome DevTools) e suporta operação síncrona e assíncrona, o que pode proporcionar melhor desempenho para nosso caso de uso. As principais bibliotecas e suas instruções de instalação incluem:
pip install playwright e execute playwright install para obter os binários do navegador).requests por simplicidade ou httpx/aiohttp para suporte assíncrono. (Instalação: pip install requests ou pip install httpx).pip install beautifulsoup4).concurrent.futures.ThreadPoolExecutor do Python será usado (sem instalação extra). Se usar uma abordagem assíncrona, o asyncio do Python com httpx pode ser usado para requisições paralelas.Justificativa: Playwright é escolhido por sua capacidade de raspar conteúdo dinâmico sem grandes complexidades. “Usando Playwright podemos automatizar navegadores headless... para navegar na web como um humano, o que o torna ótimo para raspar sites dinâmicos com JavaScript”. Isso garante que nosso crawler possa ver links ou elementos de UI gerados por scripts (que um crawler simples baseado em requests perderia).
O módulo crawler usará Playwright em modo headless para realizar crawling profundo do site alvo. O objetivo é descobrir caminhos internos (endpoints) para testar, incluindo aqueles revelados apenas após a execução de JS. Pontos chave do design do crawler:
Navegação Headless do Navegador: Inicie uma instância do navegador (ex.: Chromium) em modo headless via Playwright. Use um Contexto de Navegador com um User-Agent personalizado se especificado pelo usuário (mais sobre isso na próxima seção). Por exemplo, podemos criar um contexto com browser.new_context(user_agent=<user_agent_string>) para emular o User-Agent escolhido. Se um proxy estiver configurado, aplique-o na inicialização (Playwright permite definir um servidor proxy ao iniciar o navegador ou contexto).
Estratégia de Crawling Recursivo: Comece a partir de uma URL base (seed). Use page.goto(base_url, timeout=<T>) para carregar a página (timeout configurável). Aguarde a rede ficar ociosa ou um pequeno atraso para permitir que o conteúdo dinâmico carregue, se necessário. Em seguida, extraia links. Podemos extrair links de duas formas:
links = page.evaluate("Array.from(document.querySelectorAll('a[href]'), a => a.href)"), ou<a href>.Filtragem de Links: Filtre links que não estejam dentro do domínio alvo (para permanecer interno). Além disso, ignore URLs de arquivos estáticos como imagens, CSS, JS, etc. Por exemplo, pule qualquer URL com extensões de arquivo como .css, .js, .jpg, .png, .gif, .svg, .woff etc. Uma abordagem prática (inspirada no modelo ProjectDiscovery) é ignorar qualquer caminho que contenha um “ponto” após a barra inicial. Eles extraíram endpoints com um padrão regex href=['"](https://github.com/houmanpashaei/cve-2025-29927/blob/main/%5C/%5B%5E.%5C%22%27%5D%2B)['"] – isso captura caminhos internos que não contêm um ponto (pulando assim assets). Implementaremos lógica similar no código para evitar enfileirar recursos estáticos ou links externos.
Controle de Rastreamento e Profundidade: Mantenha um conjunto de URLs visitadas para evitar loops infinitos ou repetições. Use uma fila (FIFO) para travessia BFS do grafo de links do site. Opcionalmente, permita que o usuário especifique um limite de profundidade de crawling ou um número máximo de páginas a visitar para evitar execução infinita em sites grandes.
Conteúdo Renderizado por JavaScript: Como usamos um navegador real, mesmo links adicionados ao DOM por scripts (por exemplo, um aplicativo React que renderiza um menu após buscar dados) serão visíveis para nosso crawler. Devemos considerar clicar ou interagir se necessário (ex.: se certas páginas só carregam após uma ação do usuário). No entanto, para manter a simplicidade e rapidez, o design inicial focará em coletar os hrefs em cada página carregada. Podemos aprimorar depois para lidar com coisas como rolagem infinita ou conteúdo por trás de cliques, se a aplicação alvo exigir.
Eficiência: Playwright suporta executar várias páginas/abas em paralelo usando sua API assíncrona. Poderíamos instanciar várias páginas com asyncio.gather para buscar vários links concorrentemente. Para uma implementação inicial, uma abordagem mais simples é rastrear sequencialmente (mais fácil de implementar) e contar com escaneamento multi-thread para desempenho. Se necessário, uma otimização avançada poderia envolver um crawl assíncrono (usando async with async_playwright() e aguardando várias chamadas page.goto). Mas como a automação de navegador consome mais recursos, uma abordagem cautelosa é manter talvez uma ou algumas páginas do navegador por vez para não sobrecarregar o sistema.
O script apresentará um menu de configuração amigável ao usuário na inicialização, permitindo que o usuário personalize os parâmetros de escaneamento ou aceite os padrões. Isso pode ser feito por meio de um menu interativo no console (usando prompts input()) ou por argumentos de linha de comando (usando argparse para uma sensação de CLI mais profissional). As opções incluem:
User-Agent Personalizado: O usuário pode especificar uma string User-Agent personalizada para o crawler e scanner. Isso será aplicado ao contexto do navegador Playwright e a quaisquer requisições HTTP diretas. Usar um User-Agent não padrão pode ajudar a evitar detecção trivial de bots. (Por padrão, Playwright pode usar algo identificável; podemos substituí-lo facilmente como mostrado acima.) Por exemplo, o usuário pode inserir uma string identificando-se como Chrome no Windows, que passamos na criação do contexto do Playwright.
Timeout de Requisição: O usuário pode definir um timeout (em segundos) para carregamento de páginas e requisições HTTP. Isso evita que o scanner fique pendurado por muito tempo em endpoints sem resposta. Aplicaremos essa configuração em para crawling e nas requisições (ex.: ) para escaneamento.
pip install rich ou pip install colorama).page.goto(timeout=...)requests.get(timeout=...)Configurações de Proxy: Se o usuário desejar rotear o tráfego por um proxy (para anonimato ou para alcançar hosts internos), ele pode inserir a URL do proxy (e credenciais se necessário). O script configurará o navegador Playwright para usar este proxy na inicialização (ex.: browser.launch(proxy={"server": "http://<proxy_host>:<port>", "username": "...", "password": "..."}) como mostrado nos exemplos). Da mesma forma, para requisições, definiremos o parâmetro proxies (ou variáveis de ambiente) de acordo.
Saída para Arquivo: O menu perguntará se o usuário deseja salvar os resultados em um arquivo (ex.: results.txt). Se sim, o script escreverá quaisquer endpoints vulneráveis descobertos e detalhes neste arquivo, além de imprimir na tela. Se não, os resultados serão apenas impressos no stdout. (Ainda podemos registrar todos os caminhos escaneados em um log detalhado, se necessário, mas o arquivo gravaria especificamente os positivos ou relatório completo com base na preferência do usuário.)
Outras Opções: Podemos incluir alternâncias como “Modo Verboso” para logging de depuração, ou “Profundidade máxima de crawl/páginas” se necessário. Isso pode ajudar o usuário a ajustar o escaneamento. Para o escopo inicial, as quatro opções principais acima são suficientes.
O sistema de menu será implementado em um módulo de configuração/setup dedicado. Pode ser simplesmente uma função que imprime prompts e coleta entrada, com padrões sensatos se o usuário pressionar Enter (ex.: user-agent padrão para um padrão, timeout padrão = 10 segundos, sem proxy, sem saída de arquivo). Isso mantém a interação clara e permite que o script também seja executado de forma não interativa (se posteriormente adicionarmos argumentos de linha de comando, podemos ignorar os prompts interativos fornecendo toda a configuração necessária via args).
O desempenho é crucial para um scanner, especialmente se muitos endpoints forem encontrados. O script empregará concorrência para velocidade, seja por multi-threading ou asyncio (ou uma combinação):
Escaneamento Multi-thread: Como o escaneamento dos caminhos descobertos (enviar requisições HTTP com cabeçalhos) é uma tarefa limitada por I/O, podemos usar threads do Python para paralelizá-lo com segurança. Operações de I/O liberam o Global Interpreter Lock, permitindo que múltiplas threads progridam em requisições de rede concorrentemente. Usando concurrent.futures.ThreadPoolExecutor, podemos ter um pool de threads trabalhadoras, cada uma lidando com um subconjunto das tarefas de escaneamento. Isso pode acelerar drasticamente o processo: por exemplo, executar 5 threads em paralelo pode reduzir o tempo de escaneamento aproximadamente por um fator de 5, como mostrado em outros contextos de web scraping. Permitiremos que o número de threads seja configurável ou escolheremos um padrão sensato (como 10 threads) equilibrando velocidade e carga no servidor. Cada thread pegará URLs de uma fila compartilhada de endpoints a testar.
Alternativa Asyncio: Alternativamente, uma abordagem assíncrona pode ser usada, especialmente se usando Playwright em modo async ou httpx para requisições HTTP. Poderíamos await múltiplas requisições simultaneamente. Por exemplo, httpx.AsyncClient pode enviar muitas requisições concorrentemente e coletar resultados. Essa abordagem evita overhead de threads e pode ser muito eficiente para um grande número de endpoints. No entanto, misturar asyncio com Playwright (que também pode ser usado assincronamente) pode complicar as coisas. Uma solução pragmática é usar threading para a fase de escaneamento HTTP (já que o crawling com Playwright pode ser mais fácil de gerenciar em modo síncrono).
Crawling Concorrente: Devemos também considerar paralelizar o crawl se o site for grande. Playwright pode abrir várias páginas de uma vez usando um contexto assíncrono. Podemos implementar uma concorrência limitada (ex.: 2-3 páginas por vez) para crawling. Por exemplo, à medida que extraímos novas URLs, poderíamos lançar uma nova Page para cada uma se usando asyncio. Isso pode ser uma otimização avançada, se necessário. Inicialmente, um crawl single-thread é mais simples e adequado para tamanhos de site moderados, mas o design pode notar isso como um ponto de melhoria.
Thread-Safety: Garantiremos o tratamento thread-safe de dados compartilhados. A lista de URLs para escanear pode ser processada com ThreadPoolExecutor.map por simplicidade, ou podemos usar uma fila thread-safe (queue.Queue do Python) e fazer com que as threads retirem dela até esvaziar. O conjunto visited para crawling é acessado apenas pelo crawler (single-thread, a menos que façamos crawling concorrente). As threads do scanner apenas lerão sua lista de URLs (sem modificar estruturas compartilhadas, exceto talvez registrar resultados, o que podemos proteger com um lock ou apenas coletar em uma lista thread-safe).
Limitação de Taxa e Cortesia: Como esta é uma ferramenta de teste de segurança, a velocidade é uma prioridade, mas ainda podemos querer evitar sobrecarregar o alvo. O usuário pode ser aconselhado a definir um número razoável de threads. Podemos também implementar um pequeno atraso ou usar semáforos para limitar a concorrência, se necessário. Por exemplo, podemos não lançar todas as threads de uma vez se a rede do usuário ou o servidor puderem sufocar. Em um cenário avançado, uma abordagem assíncrona poderia usar um semáforo para permitir, digamos, 5 requisições concorrentes por vez. Esses detalhes podem ser ajustados com base no teste de desempenho do script.
Em resumo, a concorrência será aplicada principalmente na fase de escaneamento para testar múltiplos endpoints em paralelo. Isso torna o scanner muito mais rápido sem sacrificar muita precisão (já que cada requisição é independente). Como uma referência observa, “Multithreading com concurrent.futures pode dar um impulso significativo aqui. Podemos executar tarefas de I/O concorrentemente em múltiplas threads e ver uma grande aceleração”. Multi-threading é adequado aqui porque tarefas limitadas por rede se beneficiam disso mesmo em Python.
O coração do script é o módulo de escaneamento, que pega a lista de endpoints descobertos (caminhos) e verifica cada um em busca de sinais da vulnerabilidade CVE-2025-29927. O processo para cada endpoint será:
x-middleware-rewrite, x-middleware-next, ou x-middleware-redirect, isso sugere que esta rota está protegida por middleware. Verificamos também se o status não é 200 (significando que o acesso foi negado ou redirecionado), já que esses são os que provavelmente serão contornados. (Se o status já for 200 e o conteúdo carregar normalmente, é uma página pública ou a vulnerabilidade não se aplica; podemos ainda testá-la, mas o interesse real está nas páginas protegidas.)X-Middleware-Subrequest. Tentaremos uma variedade de valores de cabeçalho para garantir a detecção em todas as versões do Next.js:Um valor genérico como "1" ou "true" (algumas fontes sugerem que simplesmente definir o cabeçalho para qualquer valor aciona o pulo).
O payload específico usado em exploits públicos, ex.: "middleware:middleware:middleware:middleware:middleware" (cinco repetições de "middleware"). Sabe-se que isso induz o bypass nas últimas versões (13+). Incluiremos exatamente este valor.
O payload alternativo para projetos que usam o diretório /src, ex.: "src/middleware:src/middleware:src/middleware:src/middleware:src/middleware"
Opcionalmente, valores de segmento único como "middleware" ou "src/middleware" para completude (versões mais antigas do Next.js podem usar um arquivo _middleware no diretório pages, com um payload ligeiramente diferente necessário, mas os payloads multissegmento acima cobrem amplamente os casos conhecidos).
Cada uma dessas requisições será feita com o cabeçalho personalizado definido. Também garantimos usar o mesmo método (GET) e incluir quaisquer cabeçalhos da base que possam ser necessários (como cookies ou tokens de autenticação se o usuário os forneceu para um escaneamento autenticado, embora normalmente escaneemos como não autenticado).
Se a base foi um erro ou redirecionamento (ex.: 401 Não Autorizado, 403 Proibido, ou um redirecionamento para login) e uma das respostas com cabeçalho injetado é 200 OK com um corpo significativamente maior (ou que de outra forma indica que a página carregou), isso é um forte indicador de vulnerabilidade. Por exemplo, se /admin retornou 403 normalmente, mas com o cabeçalho retorna 200 e contém o HTML do painel de administração, sinalizamos.
Em alguns casos, a diferença pode ser um 302 vs um 200, ou um 404 vs 200. Consideraremos uma mudança de código de status de não-200 para 200 como um sinal provável. Além disso, se o status permanecer 200, mas o comprimento do conteúdo mudar drasticamente, isso pode indicar que o cabeçalho alterou o comportamento (menos comum para este bug específico, mas uma possibilidade se a página normalmente entregava uma coisa e com o cabeçalho entregou outra).
Implementaremos verificações como: if base_status_code != 200 and test_status_code == 200: (e talvez também garantir test_body_length > base_body_length ou conter alguma palavra-chave autenticada) então sinalizar como vulnerável. Se a base foi um redirecionamento (ex.: 307 para /login), e o teste produz 200, também sinalizar. Essencialmente, “o acesso foi antes negado, mas agora permitido?”.
Se o status da resposta com o cabeçalho for 404 ou 500 onde a base era um redirecionamento, isso pode ser o cenário de envenenamento de cache (bypass do redirecionamento do middleware causando um 404 na origem). Esse cenário é um pouco mais difícil de detectar com apenas uma requisição, mas a presença de um 404 com cabeçalho quando a base era um redirecionamento também pode ser notada (embora não seja um bypass de autenticação, ainda é um efeito da vuln). No entanto, nosso foco é detectar um bypass de autenticação (acesso 200 OK).
results.txt se o usuário optou por salvar resultados. Devemos formatar isso claramente, ex.:[*] /admin -> base 403, com X-Middleware-Subrequest (payload X) obteve 200 [VULNERÁVEL]
Também podemos imprimir algo como o comprimento da resposta ou um trecho da resposta para confirmar (talvez apenas o comprimento por brevidade, ex.: “len: 0 -> 10240 bytes”). Se múltiplos payloads foram tentados, poderíamos listar quais tiveram sucesso.
Se o site parecer não ser uma aplicação Next.js (ex.: não encontramos nenhum /_next/static/ na página inicial, que é um sinal revelador), podemos gerar uma nota: “Nenhum indicador de Next.js encontrado, o alvo pode não estar usando Next.js – provavelmente não vulnerável.” Mas ainda podemos prosseguir genericamente, já que uma verificação de Next.js é uma otimização, não uma necessidade.This logic will be encapsulated cleanly. For instance, we might have a function scan_endpoint(url, session, header_payloads) that returns a result object or dict with whether it’s vulnerable and details. We will incorporate robust checks to avoid false positives. Specifically, requiring a status code change to 200 (or other clear evidence) helps ensure we only flag actual bypasses. As noted in ProjectDiscovery’s analysis, the scanner checks for response status 200 when the special header is included to confirm the vulnerability.
The script’s output should be easy to read and interpret, as well as optionally saved to a file. We will format the console output with clear headings and indentation where appropriate. Some considerations:
After the scan, print a summary of findings. For example: “Scan Complete: 3 vulnerable endpoints found (out of 45 tested).” Then list the vulnerable endpoints with details.
Use a consistent format for each result line, as shown above, possibly with [VULNERABLE] tags to draw attention. If using a library like rich, we could even color-code “VULNERABLE” in red or yellow. Even without extra libraries, we can use ANSI codes via colorama to highlight, or just uppercase text.
If no vulnerabilities are found, say so explicitly: “No vulnerabilities detected for CVE-2025-29927.”
If the results are to be saved, ensure they are written in a similar format to the file. Possibly in a slightly more verbose way or CSV for programmatic use, but since the user specifically mentioned a text file, we will likely just write the same lines into results.txt.
Also, any critical errors or exceptions encountered (like unable to load a certain page) can be reported in the output in a graceful manner (instead of a stack trace). We can catch exceptions and print a one-line warning per failed URL: e.g., “Timeout loading /blog (skipped)”. This way, the user knows if some paths weren’t tested.
Throughout the execution, we might show a spinner or progress (for long runs) or at least print which page is being crawled or which endpoint is being tested, if verbose mode is on. For a cleaner output, we might only show discovered vulnerable cases at the end, but a running log (perhaps writing to a separate log file) can help with transparency.
Given the emphasis on a clear format, using bullet points or table layout could help when printing multiple results:
We could tabulate as: Endpoint | Base Status | Base Length | Bypass Status | Bypass Length | HeaderValueUsed | Result
However, a simple sentence form might be more readable for a wide range of users. We will ensure each result is on a new line and labeled clearly.
By providing both screen output and an optional file save, the tool is useful for both interactive use and automated scanning (where the user can later review the file or integrate it into reports).
To make the script maintainable and professional-grade, we will organize the code into modules, each handling a distinct aspect of the functionality. A possible project structure:
crawler.py: Contains the crawling logic using Playwright. It will have functions like crawl_site(start_url, config) -> List[str] that returns a list of discovered internal paths. This module will handle launching the browser, retrieving pages, extracting links, and enforcing filters (domain, static file exclusion). It could also house helper logic to normalize URLs (e.g., remove URL fragments, handle relative paths via urllib.parse.urljoin).
scanner.py: Contains the scanning logic for the vulnerability. It will include functions such as scan_paths(url_list, config) -> List[ScanResult]. This will manage creating HTTP requests (using requests.Session or an httpx client), applying headers, comparing responses, and collecting results. If using multithreading, this module would create the ThreadPool and manage tasks. It might define a small ScanResult data class to hold info about each path (path, vulnerable: bool, details).
config.py (or settings.py): Contains code for the user menu and configuration. For instance, a function get_user_config() that interacts with the user and returns a config object/dictionary with all the chosen settings (user_agent, timeout, proxy, output_file flag, etc.). If using CLI args, this module could alternatively parse argparse.ArgumentParser. Essentially, this part isolates all user input and configuration handling.
utils.py: Utility functions, e.g., for printing banners, formatting output strings, handling color output, or common helper like is_static_resource(url) (to check if a URL likely points to a static file). Also, could include a function for graceful shutdown (to be called on SIGINT).
main.py: The entry-point script that ties everything together. It will:
config.py).main could just be at the bottom of one file, but for cleanliness, separating is better.Each module will be designed to be modular and reusable. For instance, one could reuse crawler.py to get site links for other purposes, or reuse scanner.py to test this vulnerability on a given list of URLs (even without crawling).
Exception Handling and Graceful Shutdown: We will implement robust exception handling:
Surround network operations with try/except (catch timeouts, connection errors, etc.). If a crawl of a page fails, log it and continue with others. If a scan request fails (e.g., proxy error), mark that endpoint as error but continue scanning the rest.
Use finally blocks or context managers to ensure resources are cleaned up. For example, use async_playwright() context or ensure browser.close() is called at the end of crawling. Similarly, ensure file handles are closed after writing.
Handle KeyboardInterrupt (Ctrl+C): We can trap the KeyboardInterrupt in the main loop and initiate a graceful shutdown – e.g., print “Stopping, cleaning up…”, shut down threads (perhaps by using ThreadPoolExecutor.shutdown(wait=False) to stop launching new tasks), and close the browser. This prevents orphan processes or locked files if the user aborts.
Use logging for debug messages (perhaps via Python’s logging library). In a professional tool, you’d have logging levels; e.g., debug logs could include each request made, while info level only shows high-level progress. The user could set a verbose flag to toggle this. By default, we might log minimal info to not overwhelm the output.
Code Quality: We will adhere to best coding practices:
Follow PEP8 style guidelines for readability.
Use meaningful function and variable names.
Add docstrings to functions explaining their purpose and usage.
Use type hints for function signatures (Python 3 type annotations) to make the code easier to understand and to catch type issues early.
Modularize constants (like the list of header payloads, lists of static file extensions to ignore, etc.) at the top or in a config, so they can be easily updated. For example, HEADER_PAYLOADS = ["middleware:middleware:...","src/middleware:..."] etc., defined in one place.
Possibly include unit tests for some helper functions (if this were a larger project, though for a single-script tool this might be skipped; still, designing with testability in mind is beneficial).
Professional-Grade Enhancements: To make the script more robust and production-ready, we can further consider:
Authentication support: Allow user to provide cookies or credentials if they want to scan an authenticated section of the site (even though the vulnerability is about bypassing auth, there may be scenarios where you need to log in first to reach certain links to then test bypass on them – albeit the bypass presumably works without valid auth, but this could help in crawling deep links that aren’t public).
Configuration file: Instead of (or in addition to) interactive input, allow reading options from a config file or environment variables, which is useful for automated deployments of the scanner.
Output formats: Provide output in multiple formats such as JSON or CSV for integration with other tools. For example, a --json flag could dump the results as machine-readable JSON.
Integrate with existing frameworks: The logic could be integrated into a larger scanning framework (for instance, turning it into a module for OWASP ZAP or integrating with ProjectDiscovery’s Nuclei by outputting a compatible report). At minimum, ensure the script’s output clearly identifies the vulnerability and affected URLs so it can be used in reports.
Parallel browser sessions: If targeting very large apps, consider launching multiple browser contexts in parallel for crawling different sections concurrently. Playwright can handle multiple contexts (each context is isolated, akin to separate browser profiles). This could speed up crawling significantly at the cost of higher resource usage.
Graceful degradation: If Playwright fails (say the environment lacks a display or proper installation), the script could fall back to a simpler requests-based crawl (which might miss some links but is better than nothing). This makes the tool more robust in various environments. Similarly, if concurrency is set too high and causes issues, catch those and suggest the user to lower thread count.
By following a clean structure and these best practices, the script will be easier to maintain and extend. Each component can be worked on independently – for instance, improving the crawler’s ability to parse JavaScript-heavy navigation, or updating the scanner with new header payload variations if future research finds additional exploitation patterns.
In conclusion, this design outlines a comprehensive approach to detect CVE-2025-29927 in web applications. It leverages a headless browser for deep crawling, multi-threading for efficient scanning, and robust coding practices for reliability. By comparing responses with and without the special header, it can reliably identify vulnerable endpoints where Next.js middleware is being bypassed. The result is a professional-grade tool that helps security engineers and developers quickly find and address this critical vulnerability in their applications.