0Pricing
Linux Command Line & Bash Scripting Mastery · Aula

Análise estática e auditoria com ShellCheck

Integre o ShellCheck a uma barreira de segurança e interprete suas descobertas para reforçar cada script.

Análise estática e auditoria com ShellCheck é uma aula grátis de Linux Command Line & Bash Scripting Mastery no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Linux Command Line & Bash Scripting Mastery, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Linux Command Line & Bash Scripting Mastery inclui 4 aulas no total.

O que é ShellCheck e por que ele importa

ShellCheck é uma ferramenta de análise estática de código aberto para scripts de shell. Ela analisa seu código-fonte Bash (e POSIX sh, dash, ksh) sem executá-lo e relata bugs, construções inseguras, problemas de portabilidade e problemas de estilo — cada um identificado por um código de regra exclusivo, como SC2086.

Em um pipeline reforçado por segurança, o ShellCheck atua como um gate obrigatório: nenhum script é entregue até ser aprovado. Isso é importante porque:

  • Muitas vulnerabilidades de shell (separação de palavras, injeção e expansão sem aspas) ficam invisíveis durante os testes do caminho esperado, mas são acionadas quando a entrada é controlada por um invasor.
  • O ShellCheck detecta essas classes de bugs antes da execução, sem custo.
  • Ele documenta por que cada padrão é perigoso, tornando sua equipe mais consciente com o tempo.

Instale-o em qualquer sistema:

# Debian / Ubuntu
sudo apt-get install shellcheck

# macOS (Homebrew)
brew install shellcheck

# From source via Cabal (any platform)
cabal update && cabal install ShellCheck

# Verify
shellcheck --version

Executando o ShellCheck pela Primeira Vez

A chamada mais simples é shellcheck <script>. O ShellCheck lê a linha shebang para determinar o dialeto do shell e, em seguida, emite as descobertas na saída padrão.

Cada descoberta inclui:

  • Arquivo e número da linha — localização exata
  • Gravidade — error, warning, info ou style
  • Código SC — identificador estável da regra, que você pode consultar ou suprimir
  • Explicação em linguagem clara — informa o que está errado e, muitas vezes, como corrigir

Execute o script abaixo e observe a saída que o ShellCheck produziria:

#!/usr/bin/env bash
# demo_bad.sh — intentionally flawed for ShellCheck demonstration

FILE=$1

if [ $FILE == '' ]; then
  echo "No file given"
fi

cat $FILE | grep 'error' | wc -l

Interpretando a Saída do ShellCheck e os Códigos SC

Para o script da cena anterior, o ShellCheck emitiria descobertas como:

  • SC2086 (aviso) — Use aspas duplas para evitar expansão de curingas e separação de palavras — em $FILE dentro de [ $FILE == '' ] e em cat $FILE.
  • SC2039 / SC3010 (informação) — == em [ ] é uma particularidade do bash; use = para POSIX.
  • SC2002 (estilo) — cat inútil. Considere cmd < file em vez de cat file | cmd.

Cada código SC corresponde a uma página wiki em https://www.shellcheck.net/wiki/SCxxxx, com justificativa e um exemplo corrigido.

A versão corrigida desse script:

#!/usr/bin/env bash
# demo_fixed.sh — ShellCheck-clean

FILE="$1"

if [ -z "$FILE" ]; then
  echo "No file given" >&2
  exit 1
fi

grep -c 'error' "$FILE"

Níveis de Gravidade e O que Exige Ação

O ShellCheck classifica cada descoberta por gravidade. Em um gate de segurança, você deve tratá-las da seguinte forma:

  • error — Quase certamente um bug ou uma falha de segurança. Bloqueie a compilação. Corrija imediatamente. Exemplo: SC2148, shebang ausente; SC2070, $? sem aspas.
  • warning — Padrão de alto risco, frequentemente explorável. Bloqueie a compilação. Corrija ou justifique explicitamente a supressão. Exemplo: SC2086, variável sem aspas.
  • info — Provavelmente correto hoje, mas frágil ou não portável. Corrija no mesmo PR, a menos que seja considerado fora do escopo.
  • style — Preferência estética ou do POSIX. Recomendado, mas opcional em uma base de código exclusivamente Bash.

Use --severity=warning para sair com código diferente de zero somente em avisos ou níveis superiores — o limite padrão de um gate de segurança:

#!/usr/bin/env bash
# gate.sh — fail CI on errors and warnings only
shellcheck --severity=warning scripts/*.sh
echo "ShellCheck exit code: $?"

Integrando o ShellCheck como Gate de Segurança da CI

Um gate de segurança só é útil quando é obrigatório e automatizado. O padrão abaixo envolve o ShellCheck em uma etapa da CI que:

  • Encontra cada arquivo .sh no repositório.
  • Executa o ShellCheck com --severity=warning e saída JSON legível por máquina.
  • Faz o pipeline falhar (exit 1) se existir qualquer descoberta.
  • Imprime um resumo para que os engenheiros possam agir sobre as descobertas sem sair do registro da CI.

Coloque este arquivo no seu repositório e chame-o do seu pipeline de CI (GitHub Actions, Jenkins, GitLab CI etc.):

#!/usr/bin/env bash
# ci/shellcheck_gate.sh
set -euo pipefail

SCRIPTS=$(find . -name '*.sh' -not -path './.git/*')
FAILED=0

for script in $SCRIPTS; do
  echo "==> Checking: $script"
  if ! shellcheck --severity=warning --format=tty "$script"; then
    FAILED=1
  fi
done

if [ "$FAILED" -eq 1 ]; then
  echo "[GATE] ShellCheck found warnings or errors. Build blocked." >&2
  exit 1
fi

echo "[GATE] All scripts passed ShellCheck."

A Família SC2086: Expansões de Variáveis sem Aspas

SC2086 é a descoberta mais comum do ShellCheck e uma das vulnerabilidades de shell mais exploradas: expansões de variáveis sem aspas.

Quando uma variável não está entre aspas duplas, o shell executa a separação de palavras (divide em IFS) e a expansão de curingas sobre seu valor. Um invasor que controle a variável pode injetar argumentos extras, provocar travessia do sistema de arquivos ou fazer com que os comandos recebam operandos inesperados.

Padrão clássico perigoso:

#!/usr/bin/env bash
# Attacker sets: FILENAME="important.txt /etc/passwd"
FILENAME="$1"

# UNSAFE — word splitting turns this into two args
rm $FILENAME

# SAFE — double quotes prevent splitting
rm "$FILENAME"

# Arrays are the right tool for lists
FILES=("$@")
rm -- "${FILES[@]}"

Detectando o Risco de Injeção de Comandos com SC2046 e SC2035

Duas regras menos conhecidas, mas críticas, tratam da injeção de comandos por meio da saída de subshells:

  • SC2046 — Coloque isto entre aspas para evitar separação de palavras / curingas dentro de $(…). Se a saída de um subshell for usada sem aspas, qualquer espaço em branco ou caractere curinga na saída se tornará um token do shell.
  • SC2035 — Use ./*.sh em vez de *.sh para evitar que nomes de arquivos iniciados por - sejam interpretados como opções (um vetor clássico de injeção de argumentos).

Cenário concreto de exploração e correção:

#!/usr/bin/env bash
# SC2046 example — output of find fed unquoted to chmod
# If a filename contains spaces, extra arguments appear

# UNSAFE
chmod 600 $(find /secrets -name '*.key')

# SAFE — use a while-read loop or xargs with -0
find /secrets -name '*.key' -print0 \
  | xargs -0 chmod 600

# SC2035 example
# UNSAFE — a file named '-rf' would be passed as an option
rm *.sh

# SAFE
rm -- ./*.sh

Usando o Formato de Saída JSON para Automação

O ShellCheck oferece suporte a vários formatos de saída por meio de --format:

  • tty (padrão) — saída de terminal legível por humanos
  • json — legível por máquina; ideal para painéis, bloqueadores personalizados ou envio para plataformas SAST
  • gcc — compatível com ferramentas que analisam o formato de erros do GCC (IDEs, Vim/Emacs)
  • checkstyle — formato XML consumido pelo plug-in Checkstyle do Jenkins

O formato JSON permite escrever políticas automatizadas, por exemplo, bloqueando somente códigos SC específicos ou agregando descobertas de uma grande base de código em um relatório de segurança.

#!/usr/bin/env bash
# Emit JSON and filter for only error-severity findings using jq
shellcheck --format=json scripts/deploy.sh \
  | jq '[.[] | select(.level == "error")]'

# Count distinct SC codes across all scripts
find . -name '*.sh' -print0 \
  | xargs -0 shellcheck --format=json 2>/dev/null \
  | jq '[.[] | .code] | group_by(.) | map({code: .[0], count: length}) | sort_by(-.count)'

Suprimindo Falsos Positivos Corretamente

Desativar o ShellCheck indiscriminadamente anula seu propósito. A abordagem correta é uma supressão direcionada e documentada, que afete somente a linha ou o bloco exato em que a descoberta realmente não se aplica.

Três mecanismos de supressão:

  • Desativação em linha — # shellcheck disable=SC2086 na linha acima do código problemático. Afeta somente essa linha.
  • Desativação/ativação de bloco — envolva uma seção com # shellcheck disable=… e # shellcheck enable=….
  • Diretiva no nível do arquivo — coloque # shellcheck disable=… no início do arquivo (raramente justificável; documente o motivo).

Toda supressão deve incluir um comentário explicando por que a descoberta é um falso positivo:

#!/usr/bin/env bash
# deploy.sh

# Legitimate suppression: $DEPLOY_ARGS is intentionally word-split
# because it is a pre-validated list of flags from a trusted config file.
# shellcheck disable=SC2086
exec deploy-tool $DEPLOY_ARGS

# Block suppression for a section that generates dynamic code
# shellcheck disable=SC2016
VARS='$HOME $PATH $USER'
echo "Unexpanded vars: $VARS"
# shellcheck enable=SC2016

Configurando o ShellCheck por meio de .shellcheckrc

Para configurações que abrangem todo o projeto, o ShellCheck lê .shellcheckrc do diretório do script, subindo até /. Isso permite evitar a repetição de sinalizadores em cada chamada e mantém os scripts do gate simples.

Diretivas úteis em .shellcheckrc:

  • shell=bash — substitui a detecção do dialeto (útil para arquivos sem shebang)
  • enable=all — ativa verificações opcionais (por exemplo, avoid-nullary-conditions, require-variable-braces)
  • disable=SC2059 — supressão para todo o projeto em uma exceção justificada
  • external-sources=true — segue e verifica diretivas source / .
# .shellcheckrc — project root
shell=bash
enable=all
external-sources=true

# SC2312: consider invoking this command separately to avoid masking its
# return value — suppressed project-wide because we use set -e.
# Rationale: errexit already aborts on failure; masking risk is mitigated.
disable=SC2312

Script Reforçado de Ponta a Ponta: Antes e Depois

A maneira mais eficaz de assimilar as descobertas do ShellCheck é refatorar um script realista, passando de um estado reprovado para um estado limpo e reforçado. O script abaixo faz backup de um diretório e foi escrito sem levar a segurança em consideração. Ele falha no ShellCheck em pelo menos cinco regras distintas.

Estude as duas versões. A versão depois passa por shellcheck --severity=warning sem diretivas de supressão e é significativamente mais segura diante de entradas controladas por um invasor:

#!/usr/bin/env bash
# BEFORE — multiple ShellCheck violations
DEST=$1
SRC=$2
DATE=`date +%Y%m%d`

if [ ! -d $DEST ]; then
  mkdir $DEST
fi

cp -r $SRC $DEST/$DATE
echo Done


#!/usr/bin/env bash
# AFTER — ShellCheck-clean and hardened
set -euo pipefail

DEST="${1:?Usage: backup.sh <dest> <src>}"
SRC="${2:?Usage: backup.sh <dest> <src>}"
DATE=$(date +%Y%m%d)

if [ ! -d "$DEST" ]; then
  mkdir -p -- "$DEST"
fi

cp -r -- "$SRC" "$DEST/$DATE"
echo 'Done' >&2

Verificação de Conhecimento: ShellCheck em um Gate de Segurança

Teste sua compreensão sobre o papel do ShellCheck como gate de segurança.

Recapitulação: Análise Estática como Gate de Segurança

Nesta lição, você aprendeu a tornar o ShellCheck um gate de segurança obrigatório no seu fluxo de trabalho Bash:

  • O ShellCheck realiza análise estática sem executar seus scripts, detectando erros de uso de aspas, riscos de injeção e padrões inseguros antes da execução.
  • Cada descoberta contém um código SC (por exemplo, SC2086) vinculado a uma documentação detalhada e orientações para correção.
  • A escala de gravidade — error, warning, info, style — permite ajustar o gate: --severity=warning é o limite de segurança recomendado.
  • Use saída legível por máquina (--format=json) para automatizar relatórios, acompanhar tendências e integrar com SAST.
  • Suprima com moderação: sempre direcione a uma única linha, sempre documente o motivo em um comentário e nunca suprima globalmente, a menos que isso seja justificado por .shellcheckrc.
  • Combine o ShellCheck com set -euo pipefail, uso explícito de aspas, terminadores -- argument e validação de entradas para obter defesa em profundidade.

Um script aprovado pelo ShellCheck não é automaticamente seguro — mas um script reprovado pelo ShellCheck nunca deve chegar à produção.

Perguntas Frequentes

A aula “Análise estática e auditoria com ShellCheck” é grátis?

Sim — o texto completo de “Análise estática e auditoria com ShellCheck” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Linux Command Line & Bash Scripting Mastery, atualize para CoddyKit PRO. O curso de Linux Command Line & Bash Scripting Mastery inclui 4 aulas no total.

O que vou aprender em “Análise estática e auditoria com ShellCheck”?

Integre o ShellCheck a uma barreira de segurança e interprete suas descobertas para reforçar cada script. Você pratica Linux Command Line & Bash Scripting Mastery com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Linux Command Line & Bash Scripting Mastery?

Nenhuma experiência prévia é necessária. Linux Command Line & Bash Scripting Mastery no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Análise estática e auditoria com ShellCheck”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Linux Command Line & Bash Scripting Mastery?

Sim. Cada aula de Linux Command Line & Bash Scripting Mastery inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Prevenção de injeção de comandos e argumentos
  2. Tratamento seguro de segredos e higiene do ambiente
  3. Execução com privilégios mínimos e disciplina no sudo
  4. Análise estática e auditoria com ShellCheck
← Voltar para Linux Command Line & Bash Scripting Mastery