Voltar para o Blog

GitHub Releases Imutáveis: A Nova Arma Contra Ataques à Supply Chain

Olá HaWkers! Ataques à supply chain de software estão cada vez mais sofisticados. Você pode confiar que aquele pacote que baixou ontem é exatamente o mesmo hoje? E se alguém modificou os arquivos da release sem você saber?

O GitHub acaba de lançar uma feature poderosa para combater esse problema: Releases Imutáveis. Desde 28 de outubro de 2025, você pode publicar releases que simplesmente não podem ser modificadas depois de criadas. Vamos entender como isso funciona e por que é um divisor de águas para segurança.

O Problema: Supply Chain Attacks São Reais

Antes de mergulhar na solução, precisamos entender o problema. Ataques à supply chain acontecem quando alguém compromete uma dependência que seu projeto usa.

Cenário Real de Ataque

Imagine este cenário:

  1. Você usa a biblioteca awesome-lib versão 2.3.0
  2. Baixa a release do GitHub, tudo OK
  3. 2 meses depois, um atacante consegue acesso à conta do mantenedor
  4. O atacante substitui os arquivos da release 2.3.0 com código malicioso
  5. Novos usuários baixando "2.3.0" recebem código comprometido
  6. Seu CI/CD baixa novamente a mesma versão (cache expirou) e agora está comprometido

Até agora, isso era perfeitamente possível no GitHub. Releases podiam ser editadas, arquivos substituídos, tags movidas.

A Solução: Releases Imutáveis

GitHub Releases Imutáveis introduzem três camadas de proteção:

1. Assets Imutáveis

Uma vez que você publica uma release como imutável, seus assets (arquivos) não podem ser:

  • Adicionados
  • Modificados
  • Deletados
# Publicando uma release imutável via gh CLI
gh release create v1.0.0 \
  --title "Release 1.0.0" \
  --notes "Initial release" \
  --immutable \
  dist/app.tar.gz \
  dist/app.zip

# ✅ Release criada como imutável
# 🔒 Assets agora estão permanentemente protegidos

Depois disso, é impossível modificar os arquivos, mesmo se você for o dono do repositório. A única opção é criar uma nova release.

2. Proteção de Tags

Tags associadas a releases imutáveis são automaticamente protegidas e não podem ser:

  • Deletadas
  • Movidas para outro commit
# Tentando deletar tag de release imutável
git push origin :refs/tags/v1.0.0

# ❌ Erro: Cannot delete protected tag 'v1.0.0'
# ❌ This tag is associated with an immutable release

Isso previne ataques onde o atacante moveria a tag para apontar para código malicioso.

3. Release Attestations

A parte mais poderosa: releases imutáveis recebem attestations assinadas usando o formato Sigstore. Isso permite verificar autenticidade e integridade dos arquivos.

# Verificando uma release com gh CLI
gh attestation verify dist/app.tar.gz --repo owner/repo

# ✅ Verified: dist/app.tar.gz
# ✅ Attestation signed by: GitHub Actions
# ✅ Workflow: .github/workflows/release.yml
# ✅ Commit SHA: abc123def456
# ✅ Timestamp: 2025-10-28T14:30:00Z

As attestations provam:

  • Quem criou a release (qual workflow do GitHub Actions)
  • Quando foi criada
  • De qual commit veio
  • Que os arquivos não foram alterados desde a criação

Como Implementar no Seu Projeto

Ativar releases imutáveis é simples. Você pode fazer a nível de repositório ou organização.

Configuração no Repositório

# .github/workflows/release.yml
name: Create Release

on:
  push:
    tags:
      - 'v*'

permissions:
  contents: write
  attestations: write
  id-token: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build artifacts
        run: |
          npm run build
          tar -czf dist.tar.gz dist/

      - name: Create Immutable Release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref_name }}
          release_name: Release ${{ github.ref_name }}
          immutable: true

      - name: Upload Release Asset
        uses: actions/upload-release-asset@v1
        with:
          asset_path: ./dist.tar.gz
          asset_name: dist.tar.gz

Configuração na Organização

Para aplicar a todas as releases de todos os repositórios:

# Via GitHub CLI
gh api \
  --method PATCH \
  -H "Accept: application/vnd.github+json" \
  /orgs/YOUR_ORG/settings \
  -f immutable_releases_enabled=true

# ✅ Todas as novas releases na organização serão imutáveis

Verificando Releases Externamente

O melhor: você pode verificar releases mesmo fora do GitHub usando ferramentas Sigstore:

# Instalando cosign (ferramenta Sigstore)
brew install sigstore/tap/cosign

# Baixando release
wget https://github.com/owner/repo/releases/download/v1.0.0/app.tar.gz

# Baixando attestation
wget https://github.com/owner/repo/releases/download/v1.0.0/app.tar.gz.attestation

# Verificando
cosign verify-attestation \
  --certificate-identity-regexp="^https://github.com/owner/repo" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
  --type https://slsa.dev/provenance/v1 \
  app.tar.gz.attestation

# ✅ Verification successful!

Isso é extremamente poderoso para ambientes corporativos e governamentais que precisam garantir integridade de software.

Casos de Uso Reais

1. Distribuição de Binários Críticos

# Empresa distribuindo CLI tool
gh release create v2.1.0 \
  --immutable \
  --notes "Security release - CVE-2025-12345 fixed" \
  bin/cli-linux-amd64 \
  bin/cli-darwin-amd64 \
  bin/cli-windows-amd64.exe

# Clientes podem verificar que o binário não foi adulterado
gh attestation verify bin/cli-linux-amd64 --repo company/cli-tool

2. Compliance e Auditoria

// Script de auditoria automatizada
const { execSync } = require('child_process');

function auditDependencies() {
  const dependencies = getDependenciesFromPackageJson();

  dependencies.forEach((dep) => {
    try {
      const result = execSync(
        `gh attestation verify node_modules/${dep.name} --repo ${dep.repo}`,
        { encoding: 'utf-8' }
      );

      console.log(`✅ ${dep.name}: Verified`);
    } catch (error) {
      console.error(`❌ ${dep.name}: VERIFICATION FAILED!`);
      throw new Error(`Dependency ${dep.name} failed verification`);
    }
  });
}

// Rode isso no CI/CD antes de deploy
auditDependencies();

3. Open Source com Garantias

Projetos open source podem agora oferecer garantias mais fortes:

## Downloading MyProject

All releases are **immutable** and signed with Sigstore attestations.

### Verify your download:

# Download

wget https://github.com/myproject/myproject/releases/download/v1.0.0/myproject.tar.gz

# Verify

gh attestation verify myproject.tar.gz --repo myproject/myproject

You should see ✅ verification successful before using the software.

Limitações e Considerações

Releases Antigas Não Mudam

Releases existentes permanecem mutáveis a menos que você as republique:

# Releases antigas ainda podem ser modificadas
# Para torná-las imutáveis, você precisa republicá-las

# ⚠️ Isso cria uma NOVA release com novo timestamp
gh release create v1.0.0 --immutable # republica como imutável

Não Há Volta

Uma vez imutável, sempre imutável. Se você cometeu um erro:

# ❌ Não funciona: tentar editar release imutável
gh release edit v1.0.0 --notes "Updated notes"
# Error: Cannot edit immutable release

# ✅ Solução: criar nova release
gh release create v1.0.1 --immutable --notes "Fixed issue from v1.0.0"

Custo de Armazenamento

Assets imutáveis não podem ser deletados, então ocupam espaço permanentemente. Para projetos com muitas releases grandes, isso pode aumentar uso de storage.

Integrações e Ferramentas

GitHub está construindo um ecossistema em torno de releases imutáveis:

// Verificando releases via API do GitHub
async function verifyRelease(owner: string, repo: string, tag: string) {
  const response = await fetch(
    `https://api.github.com/repos/${owner}/${repo}/releases/tags/${tag}`,
    {
      headers: {
        Accept: 'application/vnd.github.attestation-preview+json',
      },
    }
  );

  const release = await response.json();

  if (!release.immutable) {
    throw new Error('Release is not immutable!');
  }

  // Verificar attestations para cada asset
  for (const asset of release.assets) {
    const attestation = await fetchAttestation(asset.attestation_url);
    const valid = await verifyAttestation(attestation);

    if (!valid) {
      throw new Error(`Asset ${asset.name} failed verification`);
    }
  }

  return true;
}

O Futuro da Supply Chain Security

Releases imutáveis são parte de uma tendência maior de zero trust em desenvolvimento de software. Combinadas com outras features como:

  • Dependency Review do GitHub
  • SBOM (Software Bill of Materials) automático
  • Code Scanning integrado

Estamos construindo um ecossistema onde supply chain attacks ficam cada vez mais difíceis.

Se você está interessado em como IA está ajudando na segurança de código, recomendo ler OpenAI Aardvark: A IA Autônoma que Encontra Vulnerabilidades, onde exploramos ferramentas autônomas de segurança.

Bora pra cima! 🦅

Comentários (0)

Esse artigo ainda não possui comentários 😢. Seja o primeiro! 🚀🦅

Adicionar comentário