DAST em CI/CD com Bitbucket Pipelines
Execute um scan DAST automatizado do WASViking Sentinel dentro do Bitbucket Pipelines contra a aplicação que você sobe em localhost, por um túnel mTLS efêmero. A aplicação nunca é exposta publicamente, o build falha quando há achados reais, e os resultados chegam ao portal, com SARIF e JSON como artefatos de build.
Este guia executa um scan DAST da WASViking® dentro de um
build do Bitbucket Pipelines, contra a aplicação que você inicia em
localhost no runner, e faz o pipeline falhar quando encontra
vulnerabilidades reais. A aplicação nunca é exposta à internet pública: o
agente Sentinel abre um túnel mTLS efêmero e o motor de DAST envia suas
sondas de volta por ele.
É o mesmo binário, a mesma API e o mesmo subcomando scan de execução
única do
guia de GitHub Actions. O que
muda entre fornecedores de CI é o YAML ao redor, além de dois detalhes
do Bitbucket que esta página destaca explicitamente: você sobe a
aplicação como um serviço, para que ela responda em localhost, e
as credenciais ficam em variáveis de repositório
protegidas (secured repository variables).
A configuração tem duas metades, e a ordem importa: configure
primeiro o portal da WASViking (uma chave de API com escopo ci:scan)
e depois conecte tudo ao Bitbucket.
O que esta integração faz
- Executa um scan DAST sob demanda, em pull requests ou em pushes para
main, contra o build que você sobe no runner. - Faz o build falhar por severidade com
--fail-on, de modo que uma release vulnerável seja bloqueada antes do merge. - Compara com a branch base usando
--baseline, de modo que um pull request só falhe pelo que ele introduz, e não por dívida preexistente. - Executa scans autenticados com um token de curta duração que o seu
pipeline gera em tempo de execução (
--auth-bearer/--auth-header), de modo que as áreas protegidas por login sejam de fato alcançadas, sem credenciais estáticas em uma configuração. - Prioriza os endpoints que você lista com
--path, analisando primeiro as rotas da sua própria API, antes da superfície descoberta automaticamente. Essencial para APIs autenticadas e SPAs sem links HTML rastreáveis. - Emite SARIF 2.1.0 e um relatório JSON completo como artefatos de build.
- Provisiona e remove o agente a cada execução, sem deixar credenciais persistentes no runner.
- Consome a sua cota de scans de CI/CD e registra cada execução no portal.
Como funciona
- O contêiner de build baixa e instala o agente Sentinel usando a chave de API.
- O agente provisiona um bundle mTLS efêmero (válido por 60 minutos, não reutilizável) a partir da API da WASViking.
- O agente abre um túnel gRPC sobre mTLS até o servidor de túnel da WASViking.
- O agente solicita um scan contra o seu alvo em
localhost. A API valida que o alvo é um endereço privado, verifica cota e concorrência, e inicia o motor de DAST. - O motor executa suas verificações (OWASP Top 10, SQLi, XSS, headers de segurança e outras) enviando sondas de volta pelo túnel; o agente as executa localmente contra a sua aplicação.
- O agente grava
wasviking-scan.sarifewasviking-scan.json, e o Bitbucket coleta esse diretório como artefato de build.
Postura de acesso
- O agente só analisa alvos privados:
localhost, RFC1918 e link-local. Endereços públicos são rejeitados pelo validador de alvos da API, que é intencionalmente mais restritivo que o fluxo on-premises persistente. - O bundle mTLS é efêmero (60 minutos) e de uso único.
- Nenhum tráfego de produção é interceptado. Apenas a instância de teste que você inicia no runner é analisada.
- Nenhum código-fonte, nenhuma variável de repositório além da chave que
você informa e nada fora de
.wasviking/é coletado. - Revogue o acesso a qualquer momento revogando a chave de API no portal.
Pré-requisitos
| Requisito | Detalhe |
|---|---|
| Plano WASViking | CI/CD Pipeline Scans habilitado (Pro ou superior). |
| Papel no portal | Admin ou Manager, para emitir chaves de API. |
| Bitbucket | Pipelines ativado no repositório, em Repository settings → Pipelines → Settings. |
| Permissão no Bitbucket | Admin no repositório, para criar variáveis de repositório protegidas e fazer o commit de bitbucket-pipelines.yml. |
| Imagem de build | Qualquer imagem Linux x86_64 com curl. A atlassian/default-image:5 funciona. |
| Aplicação alvo | Capaz de iniciar no runner e responder em localhost:<port>, seja como um serviço do Bitbucket, seja como um contêiner que você sobe no step. |
| Saída de rede | HTTPS para api.wasviking.com e sentinel.wasviking.com na porta 443. Nenhuma conexão de entrada é necessária. |
Usa GitLab CI, Jenkins, CircleCI ou qualquer outra ferramenta capaz de executar um binário Linux? Os comandos são idênticos. Só muda o dialeto de YAML. Comece por wasviking-sentinel em CI/CD.
Passo 1: Crie uma chave de API com escopo ci:scan (portal)
Uma única chave de API cobre o build inteiro: ela autoriza o download do instalador do agente e o próprio scan. Nenhum token de agente Sentinel é envolvido. O fluxo de CI provisiona um agente efêmero na hora a partir dessa chave, então não há agente persistente para registrar.
Vá para Settings → System Settings → API Keys e clique em + New Key.
| Campo | Valor |
|---|---|
| Label | Algo que você reconheça depois, por exemplo Bitbucket DAST, checkout-api. Use uma chave por repositório, para que revogá-la não derrube outros pipelines. |
| Scopes | ci:scan (Trigger scans from a CI/CD pipeline, que também autoriza o download do instalador). Privilégio mínimo: um pipeline de DAST não precisa de mais nada. |
| Expiration | 90 dias é um padrão sensato. Faça a rotação nessa cadência. |
Salve e copie a chave uma única vez. Você vai colá-la no Bitbucket no
Passo 2 como WASV_DAST_API_KEY.
A WASViking autentica com o header
Authorization: ApiKey <key>, e nãoBearer. Se você já executa o pipeline de SCA / SBOM / Secrets, a chave dele já incluici:scan, então você pode reutilizar a mesma variável em vez de emitir uma segunda chave.
Settings → System Settings → API Keys.
Selecione apenas ci:scan para uma chave de pipeline de CI/CD.
Passo 2: Armazene a chave como variável de repositório protegida
Nunca faça commit de uma chave no repositório. No Bitbucket, vá para Repository settings → Pipelines → Repository variables e adicione:
| Nome | Valor | Secured |
|---|---|---|
WASV_DAST_API_KEY |
A chave de API do Passo 1. | Sim |
WASV_TEMPLATE |
Opcional. O CI/CD slug de um Scan Template, por exemplo ci-fast. |
Não |
Marque Secured na chave, para que o valor seja mascarado no log do
build e não possa ser lido de volta pela interface. Deixe WASV_TEMPLATE
sem essa proteção; ela não é um segredo, e vê-la no log ajuda.
Um comportamento do Bitbucket a considerar: builds de pull request disparados a partir de um repositório que é um fork não recebem variáveis protegidas. A primeira linha do step abaixo é uma proteção que faz o build falhar imediatamente nesse caso, em vez de executar o scan sem autenticação.
Como escolher um Scan Template
Um Scan Template é um conjunto nomeado e reutilizável de preferências de
scan (crawl, autenticação, seleção de analisadores, comentários de IA),
para que o pipeline não reconfigure tudo isso a cada execução. Consulte-os
no portal em Scans → Scan Templates; a coluna CI/CD Slug é
exatamente o valor que você coloca em WASV_TEMPLATE.
Para um gate por PR ou por commit, use ci-fast: apenas crawl,
headers de segurança, portas expostas e TLS, pulando os módulos ativos
pesados, de modo que o gate responda em segundos. Combine-o com uma
execução agendada de cobertura completa contra staging. Deixe
WASV_TEMPLATE sem valor para usar os padrões de CI embutidos.
Scans → Scan Templates. A coluna CI/CD Slug é o valor de WASV_TEMPLATE.
Passo 3: Adicione o pipeline
Crie ou estenda o bitbucket-pipelines.yml na raiz do repositório. O
exemplo sobe o OWASP Juice Shop como aplicação sob teste, para que
você possa executá-lo de ponta a ponta hoje mesmo; substitua o serviço
pela forma como a sua própria aplicação inicializa no CI.
image: atlassian/default-image:5
definitions:
services:
# The application under test. Bitbucket makes a service reachable on
# localhost, so the agent scans it at http://localhost:3000. Replace
# this image with your own app; keep it intentionally on a private
# port, never public.
app-under-test:
image: bkimminich/juice-shop:latest
memory: 2048
pipelines:
custom:
wasviking-dast:
- step:
name: WASViking DAST
max-time: 25
services:
- app-under-test
script:
- test -n "$WASV_DAST_API_KEY"
- export WASV_API_BASE="https://api.wasviking.com"
- export TARGET_URL="http://localhost:3000"
# Wait until the app answers before scanning.
- |
up=""
for i in $(seq 1 60); do
if curl -fsS "$TARGET_URL/" >/dev/null 2>&1; then
echo "target is up after ${i} tries"; up=1; break
fi
sleep 3
done
test -n "$up" || { echo "target never answered on $TARGET_URL"; exit 1; }
# Install WASViking Sentinel.
- |
curl -fsSL \
-H "Authorization: ApiKey $WASV_DAST_API_KEY" \
"$WASV_API_BASE/api/v1/sentinel/install.sh" | sh
- mkdir -p wasviking-reports
# Run the DAST scan through the ephemeral mTLS tunnel.
# --fail-on none keeps the first runs green while you review
# the findings; switch to --fail-on high (or critical) to make
# it a merge gate. WASV_TEMPLATE is optional.
- |
TEMPLATE_ARG=""
if [ -n "$WASV_TEMPLATE" ]; then TEMPLATE_ARG="--template $WASV_TEMPLATE"; fi
./.wasviking/wasviking-sentinel scan \
--api "$WASV_API_BASE" \
--api-key "$WASV_DAST_API_KEY" \
--scan-type singlescan \
--fail-on none \
--baseline all \
--out ./wasviking-reports \
$TEMPLATE_ARG \
"$TARGET_URL"
artifacts:
- wasviking-reports/**
Quatro escolhas nesse arquivo merecem ser entendidas antes de você adaptá-lo:
- O serviço em
localhost. O Bitbucket torna um contêiner de serviço acessível a partir do step de build emlocalhost, na porta em que o serviço escuta. É por isso que o agente, que executa localmente as sondas do motor, consegue analisarhttp://localhost:3000. Algumas aplicações precisam de memória;memory: 2048dá folga ao Juice Shop, e para uma aplicação mais pesada você pode precisar desize: 2xno step para ampliar o pool. Se preferir subir a aplicação por conta própria, adicione- dockeraservicese suba a aplicação comdocker compose up -d, e então analise a mesma URL de localhost. - Um pipeline
custom. O scan é executado sob demanda em Pipelines → Run pipeline → Custom → wasviking-dast, que é o formato certo para o primeiro rollout. Mova o step parapull-requestsoubranches: main(com uma âncora YAML, como mostra o guia de SCA) depois que ele estiver validado. --fail-on noneno início. As primeiras execuções ficam verdes, para que você possa ler os achados no portal e nos artefatos sem que um build vermelho mascare a integração. Aumente o rigor parahighoucriticalquando você já entender a baseline.artifacts. O Bitbucket mantémwasviking-reports/**anexado ao build, de modo quewasviking-scan.sarifewasviking-scan.jsonpossam ser baixados na aba Artifacts após a execução.
Faça o commit do arquivo e execute-o em Pipelines → Run pipeline → Custom.
Passo 4: Flags do scan
O comando de scan recebe a URL do alvo como último argumento:
wasviking-sentinel scan [flags] <URL_TARGET>
| Flag | Obrigatório | Descrição |
|---|---|---|
<URL_TARGET> |
Sim | URL do alvo, passada por último. Deve resolver para um endereço privado (localhost, RFC1918, link-local). |
--api-key |
Sim | Chave de API com o escopo ci:scan. Também lê WASV_API_KEY. |
--api |
Não | URL base da API da WASViking. Padrão: https://api.wasviking.com. |
--scan-type |
Não | singlescan (padrão, recomendado para CI) ou fullscan. |
--template |
Não | Slug de um Scan Template, para reutilizar uma configuração de scan padrão. Também lê WV_TEMPLATE. Vazio = padrões de CI embutidos. |
--fail-on |
Não | Limite único: critical, high, medium, low ou none. Lógica de "igual ou acima": high falha em high e critical. Padrão: critical. |
--baseline |
Não | all (todo achado conta, padrão) ou new (apenas achados ausentes do scan mais recente na branch base). |
--auth-bearer |
Não | Bearer token para executar o scan autenticado. Prefira a variável de ambiente WV_AUTH_BEARER, para que ele nunca apareça no argv nem no log. Sobrescreve qualquer autenticação definida em --template. |
--auth-header |
Não | Header de autenticação personalizado no formato Name: value. Prefira WV_AUTH_HEADER. Use --auth-bearer ou --auth-header, não os dois. |
--path |
Não | Endpoint extra a analisar primeiro, antes da superfície descoberta automaticamente. Pode ser repetido, ou informado via WV_SEED_PATHS (separado por vírgulas). Caminhos relativos ou URLs de mesma origem; até 500. |
--out |
Não | Diretório de saída para SARIF e JSON. Padrão: diretório atual. |
--timeout |
Não | Timeout total, em tempo de relógio. Padrão: 45 minutos. |
Dois arquivos são produzidos: wasviking-scan.sarif (SARIF 2.1.0) e
wasviking-scan.json (saída completa com metadados da WASViking).
Exit codes
O Bitbucket faz o step falhar em qualquer exit code diferente de zero, então são esses códigos que transformam um achado em um merge bloqueado.
| Código | Significado |
|---|---|
0 |
Nada no limite de --fail-on ou acima dele. |
1 |
Achados no limite ou acima dele, ou uma falha de execução não mapeada. |
2 |
Valor de --baseline inválido. |
70 |
O slug de --template não foi encontrado para a sua organização. |
71 |
O slug de --template existe, mas a sua chave não pode usá-lo. |
Se você também ativar as pré-verificações locais --sca ou --secrets
no mesmo comando, elas são executadas antes do provisionamento e
adicionam seus próprios exit codes (70/71 para SCA, 73/74 para
secrets), documentados no
guia de SCA.
Scans autenticados
Um scan sem autenticação só vê o que um visitante anônimo vê. Para alcançar a área protegida por login, gere um token de curta duração no pipeline e passe-o para o scan, em vez de armazenar credenciais estáticas em um template.
| Modo | Flag | Variável de ambiente (preferida) | Enviado como |
|---|---|---|---|
| Bearer token | --auth-bearer <token> |
WV_AUTH_BEARER |
Authorization: Bearer <token> |
| Header personalizado | --auth-header 'Name: value' |
WV_AUTH_HEADER |
Name: value (por exemplo, X-Api-Token: …) |
Sempre passe o token pela variável de ambiente, não pela flag. Um valor na linha de comando acaba no argv do processo e no log do build; uma variável de ambiente, não.
Como isso se comporta:
- Sobrescreve o template. Uma credencial informada substitui por
completo o bloco
authenticationdo seu--template; todo o resto do template é preservado. Um único template pode atender pipelines anônimos e autenticados. - Criptografado em repouso, nunca registrado em log. O segredo
trafega pelo mesmo canal TLS da chave de API e é gravado na trilha de
auditoria apenas como um marcador de modo (
bearer/header), nunca com o valor. - Sem downgrade silencioso. Em caso de sucesso, a CLI imprime
Authenticated scan confirmed (mode=bearer). Se o servidor não aplicar a credencial, a CLI faz o step falhar (exit 2) em vez de executar sem autenticação e reportar um falso resultado limpo.
Gere o token contra a instância que você iniciou no runner e exporte-o antes do step de scan:
- |
TOKEN="$(curl -fsS -X POST http://localhost:3000/api/login \
-H 'Content-Type: application/json' \
-d "{\"email\":\"$SCAN_TEST_USER\",\"password\":\"$SCAN_TEST_PASSWORD\"}" \
| python3 -c 'import sys,json;print(json.load(sys.stdin)["authentication"]["token"])')"
test -n "$TOKEN" || { echo "login failed"; exit 1; }
export WV_AUTH_BEARER="$TOKEN"
Use uma conta de teste dedicada e de baixo privilégio para os scans,
nunca um usuário real nem uma credencial de admin. Armazene
SCAN_TEST_USER e SCAN_TEST_PASSWORD como variáveis de repositório
protegidas.
Priorizando endpoints específicos (seed paths)
O motor descobre a sua superfície automaticamente (crawl, robots.txt,
sitemap, OpenAPI/Swagger, introspecção de GraphQL). Mas rotas de API
e views de SPA muitas vezes não têm links HTML rastreáveis, então o
crawler nunca chega a elas. Liste-as explicitamente com --path e elas
são analisadas primeiro:
--path /rest/products/search \
--path /api/v1/orders
Ou, de forma equivalente, pelo ambiente (separado por vírgulas):
export WV_SEED_PATHS=/rest/products/search,/api/v1/orders
Caminhos relativos ou URLs de mesma origem, até 500. Combine com
autenticação: o token libera as rotas protegidas, e --path faz com que
o scanner de fato as visite. Em caso de sucesso, a CLI imprime
Priority seed paths confirmed (N applied).
Política de fail-on
--fail-on define a menor severidade que faz o build falhar, e tudo
acima dela também falha.
| Configuração | Comportamento |
|---|---|
--fail-on none |
Nunca falha. Apenas relatório, útil nas primeiras execuções. |
--fail-on critical |
Falha apenas em critical. |
--fail-on high |
Falha em high e critical. Um bom padrão para pull requests. |
--fail-on medium |
Falha em medium e acima. Mais rígido, mais atrito. |
Um rollout prático: comece em none para ver o volume, passe para
critical e depois aumente o rigor para high quando a sua baseline
estiver limpa (normalmente, alguns sprints).
Diff de baseline
--baseline controla o que conta para a política de fail-on.
| Modo | Comportamento |
|---|---|
all (padrão) |
Todo achado conta. Use em branches de release, scans agendados e auditorias. |
new |
Contam apenas os achados ausentes do scan mais recente na branch base. Use nos pull requests do dia a dia, para evitar atrito com dívida preexistente. |
Como ler os resultados
O portal é o sistema de registro. Cada execução e seus achados ficam em User → CI/CD Pipeline, com a execução marcada como Bitbucket Pipelines, e os achados vinculados à postura da sua organização.
O arquivo SARIF é escrito para ferramentas que consomem o formato. O
Bitbucket não ingere SARIF nativamente, então nesta plataforma ele é um
artefato de build que você baixa na aba Artifacts ou entrega a outra
ferramenta, e não uma camada de anotações no pull request. O log do build
traz o resumo do scan (uma distribuição por severidade e
Result: PASS/FAIL), e o portal traz o histórico completo.
O que é e o que não é coletado
A WASViking não coleta o código-fonte do seu repositório, variáveis
de ambiente do runner além das chaves que você informa, conteúdo do
sistema de arquivos do runner fora do diretório .wasviking/, nem
qualquer tráfego ou dado de produção. Apenas a instância de teste que
você inicia no runner é analisada. Os dados são processados na região dos
Estados Unidos, criptografados em trânsito (TLS 1.2+) e em repouso
(AES-256). Um DPA e a residência de dados na UE estão disponíveis sob
solicitação; consulte o Trust Center
para o mapeamento completo de conformidade (ISO 27001, SOC 2, LGPD, GDPR,
NIST SSDF, OWASP DSOMM).
Problemas comuns
| Problema | Causa provável |
|---|---|
| O step falha na primeira linha, antes de qualquer saída | WASV_DAST_API_KEY não está definida. Em um pull request vindo de um fork, as variáveis protegidas não são entregues ao build. |
target never answered on http://localhost:3000 |
O serviço da aplicação não subiu a tempo. Aumente o loop de espera, dê mais memory ao serviço ou verifique se a imagem do serviço inicia sem erros. |
HTTP 401 Unauthorized |
Chave revogada, expirada ou sem o escopo ci:scan. O header é Authorization: ApiKey <key>, e não Bearer. |
HTTP 400 target must be private |
O alvo resolveu para um endereço público. Analise localhost ou uma faixa privada. |
HTTP 429 quota exceeded |
Cota mensal de scans de CI/CD atingida. Aguarde o próximo ciclo, faça upgrade ou compre um pacote add-on. |
HTTP 429 concurrency limit |
Scans simultâneos demais para o seu plano. |
| Exit 70 | O slug de --template não existe para a sua organização. Corrija o valor de WASV_TEMPLATE ou remova-o para usar os padrões de CI. |
| Scan preso em running | A aplicação alvo não respondeu às sondas. Confirme que o health check passou antes do step de scan. |
| SARIF vazio | A aplicação não estava acessível ou retornou apenas erros 5xx. |
Erro no download de install.sh |
Política de rede bloqueando api.wasviking.com ou o bucket de releases. |
| O step sai com exit 2, "server did not apply any credential" | Você solicitou um scan autenticado, mas o token não foi aplicado. Verifique se o token foi gerado (não está vazio) e exportado para WV_AUTH_BEARER/WV_AUTH_HEADER. |
Onde isto se encaixa na plataforma
- A cota de scans de CI/CD e o histórico de execuções ficam em User → CI/CD Pipeline no portal.
- A versão deste mesmo pipeline para GitHub Actions é DAST em CI/CD com GitHub Actions.
- Os gates de dependências e de secrets também rodam no Bitbucket, com o mesmo binário e o mesmo modelo de chave. Consulte SCA, SBOM e Secrets em CI/CD com Bitbucket Pipelines.
- A referência do subcomando
scannos diferentes sistemas de CI é wasviking-sentinel em CI/CD. - O roteamento de alertas está documentado em Slack e Teams e Webhooks.
