WASViking Docs
⌘K
Primeiros passos

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

  1. O contêiner de build baixa e instala o agente Sentinel usando a chave de API.
  2. O agente provisiona um bundle mTLS efêmero (válido por 60 minutos, não reutilizável) a partir da API da WASViking.
  3. O agente abre um túnel gRPC sobre mTLS até o servidor de túnel da WASViking.
  4. 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.
  5. 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.
  6. O agente grava wasviking-scan.sarif e wasviking-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ão Bearer. Se você já executa o pipeline de SCA / SBOM / Secrets, a chave dele já inclui ci:scan, então você pode reutilizar a mesma variável em vez de emitir uma segunda chave.

System Settings, aba API Keys, com a lista de chaves Settings → System Settings → API Keys.

Seletor de escopos da chave de API com ci:scan selecionado 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.

Lista de Scan Templates com a coluna CI/CD Slug 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 em localhost, na porta em que o serviço escuta. É por isso que o agente, que executa localmente as sondas do motor, consegue analisar http://localhost:3000. Algumas aplicações precisam de memória; memory: 2048 dá folga ao Juice Shop, e para uma aplicação mais pesada você pode precisar de size: 2x no step para ampliar o pool. Se preferir subir a aplicação por conta própria, adicione - docker a services e suba a aplicação com docker 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 para pull-requests ou branches: main (com uma âncora YAML, como mostra o guia de SCA) depois que ele estiver validado.
  • --fail-on none no 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 para high ou critical quando você já entender a baseline.
  • artifacts. O Bitbucket mantém wasviking-reports/** anexado ao build, de modo que wasviking-scan.sarif e wasviking-scan.json possam 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 authentication do 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