Pular para o conteúdo

GitHub Actions Validator: Detecte erros de workflow e brechas de segurança antes de fazer push.

Roda no seu navegador — nada do que você cola sai desta página. Como comprovamos isso

Playground do validador de workflows do GitHub Actions

Example
.github/workflows/ci.yml
name: PR Build (insecure)

# pull_request_target runs with a privileged token AND secrets.
on:
  pull_request_target:
    types: [opened, synchronize]

# write-all grants the token every scope — far more than this job needs.
permissions: write-all

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      # Checking out the PR head under pull_request_target executes
      # attacker-controlled code with your write token: the "pwn request".
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}

      # The PR title is attacker-controlled and is interpolated straight into
      # the shell, so a crafted title can break out and run its own commands.
      - name: Greet the contributor
        run: echo "Thanks for the PR titled ${{ github.event.pull_request.title }}"

      # Third-party action pinned to a mutable tag, not a commit SHA.
      - uses: some-vendor/deploy-action@v2
        with:
          token: ${{ secrets.DEPLOY_TOKEN }}

Results update as you type — press ⌘/Ctrl + Enter to run now. Press Esc to release the editor.

fig. 03 — github-actions-validator · ci/cd 1 error · 3 warnings · 2 info
Results

Errors 1

errorError: pull_request_target checks out untrusted PR code.Line 17

This workflow triggers on `pull_request_target` (privileged token + secrets) and checks out the pull request head. Any fork contributor can run arbitrary code with your repository’s write token — the classic “pwn request” vulnerability.

Fix

Do not check out PR head in pull_request_target. Use pull_request for untrusted code, or split into a privileged job (no checkout of PR code) and an unprivileged build job, and never expose secrets to checked-out PR code.

Warnings 3

warningWarning: Top-level `permissions: write-all` is over-broad.Line 9

`write-all` grants the GITHUB_TOKEN write access to every scope (contents, packages, deployments, …). A single compromised step or action then inherits all of it.

Fix

Declare only the scopes you need, e.g. permissions: { contents: read }, and elevate per-job where a specific write is required.

warningWarning: Untrusted input interpolated into a shell command.Line 24

An attacker-controlled GitHub context (such as a PR title, body, or branch name) is expanded directly inside a `run:` step. Because `${{ … }}` is substituted before the shell executes, a malicious value can inject and run arbitrary commands.

Fix

Pass the value through an environment variable instead of inline interpolation, e.g. set env: { TITLE: ${{ github.event.pull_request.title }} } and reference "$TITLE" in the script (quoted).

warningWarning: Third-party action “some-vendor/deploy-action@v2” is not pinned to a commit SHA.Line 27

This action is referenced by a mutable tag or branch (e.g. `@v4` or `@main`). The maintainer — or anyone who compromises the action — can repoint it to malicious code that runs with your workflow’s token and secrets.

Fix

Pin to a full 40-character commit SHA, e.g. uses: some-vendor/…@<sha>, and add a comment with the human-readable version. Tools like Dependabot can keep the SHA up to date.

Info 2

infoInfo: First-party action “actions/checkout@v4” is pinned to a tag, not a SHA.Line 17

This action is maintained by GitHub, so the risk is lower, but tags and branches are still mutable. Pinning to a full commit SHA guarantees the exact code you reviewed runs every time.

Fix

Pin to a full 40-character commit SHA, e.g. uses: actions/…@<sha>, and add a comment with the human-readable version. Tools like Dependabot can keep the SHA up to date.

infoInfo: Secrets referenced in a pull_request-triggered workflow.Line 29

Workflows triggered by `pull_request` from a fork do not receive repository secrets by default. If this runs as `pull_request_target`, the secrets ARE available to untrusted PR code — make sure that is intended.

Fix

Confirm whether forks need these secrets. Prefer running secret-dependent steps on a trusted event (push, workflow_run) rather than untrusted PRs.

Cole um workflow do GitHub Actions e obtenha seus erros de YAML mais as configurações de segurança incorretas que os linters comuns deixam passar — na hora, no seu navegador. Sem instalação, sem cadastro.

A lacuna

A sintaxe é a parte fácil.

actionlint acerta a sintaxe do workflow — tipagem de expressões, dependências de jobs, até shellcheck nos seus blocos run. Continue usando-o. Mas um workflow pode ser YAML perfeitamente válido e ainda assim entregar os seus secrets a um atacante.

Os erros perigosos são os de segurança: rodar código de fork não confiável sob pull_request_target, interpolar texto controlado por um atacante dentro de um shell, puxar uma ação de terceiros por uma tag que o autor pode mover silenciosamente, ou conceder um token write-all a um job que só precisa ler. Esses são os padrões por trás de incidentes reais de cadeia de suprimentos — veja o guia de fortalecimento de segurança do GitHub e a análise do pwn-request.

Este validador verifica as duas coisas — o YAML e as configurações de segurança incorretas — para que você possa validar um workflow do GitHub Actions antes do push, sem nada para instalar e sem nada enviado.

Veja a lista completa nas verificações de segurança, ou experimente o playground ao vivo acima.

O pipeline

Como funciona.

Cinco passos determinísticos rodam de ponta a ponta em cada validação — todos dentro da aba do seu navegador, toda vez.

  1. Analisa o YAML.

    Seu workflow é analisado com um leitor de YAML: os erros de sintaxe, a indentação incorreta e os problemas estruturais são reportados com a linha que falhou.

  2. Mapeia o workflow.

    Os triggers, os jobs, as permissões e cada passo são lidos em um modelo para que o analisador saiba o que roda, quando e com qual token.

  3. Roda as verificações.

    Cada regra de segurança percorre o modelo, procurando combinações arriscadas de trigger + checkout, expressões não confiáveis em blocos run, fixações de ações mutáveis e permissões amplas.

  4. Ordena por severidade.

    Os achados são classificados como altos, médios ou baixos para que os riscos de pwn-request e de injeção subam para o topo, à frente das picuinhas de estilo.

  5. Mostra a solução.

    Cada achado liga a localização exata a uma correção concreta: o trigger seguro, o padrão de variável env, o SHA fixado, a permissão restrita.

Verificações de segurança

As 4 verificações que importam.

Além da validade do YAML, o analisador busca as configurações incorretas que levam a secrets vazados e pipelines comprometidos. Cada uma abaixo mostra o padrão arriscado e a solução.

pull_request_target + checkout (pwn request)

Severidade High

Um workflow com pull_request_target roda com os secrets do repo base e um token de leitura/escrita, mas pode ser disparado a partir de qualquer fork. Fazer checkout e rodar o head do PR executa código não confiável com os seus secrets.

Arriscado

.github/workflows/ci.yml
# DANGEROUS — runs fork code with base-repo secrets
on: pull_request_target
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}
      - run: npm ci && npm run build   # attacker's code, your token

Corrigido

.github/workflows/ci.yml
# SAFE — untrusted code runs with no secrets
on: pull_request          # not pull_request_target
permissions:
  contents: read
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4   # checks out the PR safely
      - run: npm ci && npm run build

Script injection via ${{ github.* }}

Severidade High

Interpolar um valor controlável por um atacante — um título de PR, um nome de branch ou o corpo de uma issue — diretamente em um bloco run permite que esse valor escape da string e seja executado como comandos de shell.

Arriscado

step
# DANGEROUS — title is substituted into the shell verbatim
- run: echo "Title: ${{ github.event.pull_request.title }}"
  # a title of  a"; rm -rf ~ #  runs as a command

Corrigido

step
# SAFE — pass through env, quote, treat as data
- env:
    TITLE: ${{ github.event.pull_request.title }}
  run: echo "Title: $TITLE"

Unpinned third-party actions

Severidade Medium

Uma referência de tag ou branch (@v4, @main) é mutável: o mantenedor da ação, ou qualquer um que comprometa a conta dele, pode movê-la para um código novo que então roda no seu pipeline com o seu token.

Arriscado

step
# RISKY — mutable references can change under you
- uses: some-org/deploy-action@v2
- uses: another-org/setup@main

Corrigido

step
# SAFE — pin to an immutable full commit SHA
- uses: some-org/deploy-action@a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0  # v2.3.1
- uses: another-org/setup@0f1e2d3c4b5a69788796a5b4c3d2e1f00112233  # main @ 2024-05

Over-broad GITHUB_TOKEN permissions

Severidade Medium

permissions: write-all (ou um bloco permissions omitido sobre um valor padrão permissivo) entrega a cada passo um token que pode fazer push de código, publicar pacotes e editar issues — muito mais do que a maioria dos jobs precisa.

Arriscado

.github/workflows/ci.yml
# RISKY — every job gets a fully privileged token
permissions: write-all
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: ./run-tests.sh

Corrigido

.github/workflows/ci.yml
# SAFE — least privilege, scoped to what's needed
permissions:
  contents: read
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: ./run-tests.sh

As permissões podem ser restritas por job ou para todo o workflow — veja a referência de permissões do GitHub. A detecção de pipe-to-shell e de secrets em pull requests também funciona hoje, com mais por vir em breve.

Análise estática

Uma nota sobre o escopo: isto é um analisador estático — ele lê o seu workflow sem executá-lo, então detecta os padrões de configuração incorreta de alto sinal acima e os erros de YAML, mas não executa jobs nem resolve o conteúdo ao vivo das ações referenciadas. Trate um resultado limpo como uma sólida confiança antes do push, e ainda assim combine-o com actionlint, proteções de branch e padrões de menor privilégio no nível da organização.

FAQ

Suas perguntas, respondidas.

Toque em uma pergunta para expandir a resposta.

Duas coisas ao mesmo tempo. Primeiro, ele analisa o YAML do seu workflow e reporta erros de sintaxe, indentação incorreta e falhas estruturais — as coisas que fazem uma execução falhar antes que um único passo seja executado. Segundo, e mais importante, ele roda um conjunto de verificações de configurações de segurança incorretas que os linters comuns deixam passar: o padrão "pwn request" de pull_request_target + checkout, a injeção de scripts por meio de expressões ${{ github.* }} não confiáveis, ações de terceiros fixadas em uma tag mutável em vez de em um SHA de commit, e permissões amplas demais como write-all. Você recebe erros e padrões perigosos em uma única passada.

Não. O validador roda 100% no lado do cliente. O YAML do seu workflow é analisado dentro da aba do seu navegador: nada é enviado para um servidor, e não há conta nem cadastro. Você pode colar com segurança workflows internos ou proprietários, inclusive os que têm nomes de secrets e labels de runners privados.

O actionlint é excelente em sintaxe, tipagem de expressões e integração com o shellcheck — e você deve continuar usando-o. Mas os erros que de fato acabam comprometendo repositórios são os de segurança: rodar código não confiável com um token privilegiado, interpolar texto controlado por um atacante diretamente em um shell, ou puxar uma ação de terceiros por uma tag que o autor pode mover silenciosamente. Esta ferramenta foca nessas configurações de segurança incorretas, valida também o YAML e não precisa instalar nada.

Um workflow disparado por pull_request_target roda no contexto do repositório base — com acesso aos seus secrets e a um GITHUB_TOKEN de leitura/escrita — mas pode ser disparado por um pull request de qualquer fork. Se esse workflow também fizer checkout do head do PR (actions/checkout com a ref do PR) e então compilar, testar ou rodar scripts a partir dele, o código do fork de um atacante é executado com os seus secrets. Esse é o clássico "pwn request". O validador sinaliza pull_request_target sempre que ele for combinado com um checkout de código não confiável do PR.

Quando você embute uma expressão como ${{ github.event.issue.title }} ou ${{ github.head_ref }} diretamente dentro de um bloco run:, o GitHub substitui o valor bruto, controlável por um atacante, dentro do seu script antes que o shell o analise. Um título como a"; rm -rf / # se torna executável. A solução é passar os valores não confiáveis por uma variável env: e referenciá-los como "$TITLE" para que o shell os trate como dados, nunca como código. O validador sinaliza as expressões do contexto github não confiáveis usadas dentro de passos run.

Uma referência como actions/checkout@v4 ou some-org/action@main aponta para uma tag ou branch que o mantenedor da ação — ou um atacante que comprometa a conta dele — pode mover para um código novo a qualquer momento, e esse código roda no seu pipeline com o seu token. Fixar em um SHA de commit completo de 40 caracteres (uses: actions/checkout@<sha>) torna a versão imutável. O validador sinaliza as ações de terceiros fixadas em uma tag ou branch mutável.

Não. Este validador é uma ferramenta independente e comunitária, e não é afiliada, endossada nem patrocinada pela GitHub, Inc. "GitHub" e "GitHub Actions" são usados aqui apenas de forma descritiva, para identificar o formato de workflow que a ferramenta verifica.

Cole o YAML do workflow em um validador baseado em navegador para detectar erros antes de fazer commit — sem instalar nada e sem precisar de push. Esta ferramenta roda o conjunto completo de verificações (estrutura YAML mais configurações de segurança incorretas) inteiramente no seu navegador, então você recebe feedback instantâneo sobre erros de sintaxe, runs-on faltando, nomes de trigger incorretos e padrões perigosos como ações não fixadas ou injeção de scripts antes que o workflow chegue ao GitHub.

Os problemas frequentes incluem um runs-on faltando em um job, um passo que especifica ao mesmo tempo uses e run, uma referência needs que aponta para um job que não existe, um nome de evento de trigger inválido e uma indentação YAML incorreta. O validador detecta cada um desses como erros estruturais com o número da linha onde o problema ocorre, para que você possa corrigi-los antes que a execução falhe no GitHub.

A maioria dos verificadores estáticos — actionlint, zizmor, action-validator — exige uma CLI ou uma toolchain de Rust/Go. Este validador é gratuito, não precisa de instalação nem cadastro, e roda inteiramente no seu navegador. Ele verifica tanto a validade do YAML quanto as configurações de segurança incorretas (ações não fixadas, injeção de templates, triggers perigosos, permissões de token amplas demais) que as ferramentas de CLI cobrem, sem nenhuma configuração local.

More free, private DevOps tools.

O validador do GitHub Actions é uma ferramenta dentro do OpsCanopy — uma copa crescente de validadores, conversores e testadores baseados em navegador que nunca tocam um servidor.

Começando com Docker?  Leia o guia de Docker →

42 ferramentas gratuitas, todas capazes de funcionar offline — o opscanopy.com não exige cadastro e não envia nada.

Ferramentas relacionadas: o conversor de ignores de CVE e AlertLint, o testador de regras do Loki. Explore o diretório completo de ferramentas.

Não é afiliado, endossado nem patrocinado pela GitHub, Inc. GitHub e GitHub Actions são marcas comerciais da GitHub, Inc., usadas aqui apenas de forma descritiva para identificar o formato de workflow que esta ferramenta verifica.