Um composer install que vira pesadelo
Imagine a cena: você roda composer install no seu projeto Laravel, como faz todo dia. O terminal mostra os pacotes sendo baixados, tudo normal. Você toma seu café, abre o VS Code e começa a codar. O que você não sabe é que, nos últimos 30 segundos, um script PHP de quase 6.000 linhas varreu seu computador inteiro — chaves SSH, credenciais AWS, tokens do GitHub, carteiras de criptomoedas, senhas salvas no Chrome, vaults do 1Password e até seus cookies do Discord. Tudo criptografado com AES-256 e enviado para um servidor na internet.
Paranoia? Não. Isso aconteceu de verdade, em 22 de maio de 2026, com pelo menos 233 versões de pacotes do ecossistema Laravel-Lang.
O que é o Laravel-Lang e por que isso importa
O Laravel-Lang é um conjunto de pacotes de tradução e localização mantidos pela comunidade. Se você já usou laravel-lang/lang (7.800 stars no GitHub), laravel-lang/attributes, laravel-lang/http-statuses ou laravel-lang/actions, seus projetos dependem desse ecossistema.
São pacotes “inofensivos” — arquivos de tradução, basicamente. Ninguém audita pacote de tradução com o mesmo cuidado que audita uma lib de autenticação. E é exatamente por isso que o atacante escolheu esse alvo.
“A supply chain attack doesn’t need to compromise the most critical package. It just needs to compromise the most trusted one.”
— Pesquisadores da Aikido Security
Como o ataque funcionou (passo a passo)
O vetor de ataque é engenhoso e explora uma feature pouco conhecida do GitHub: tags de versão podem apontar para commits de forks. O atacante não precisou invadir o repositório oficial. Ele fez um fork, adicionou código malicioso, e criou tags no repositório original apontando para commits do fork.
Passo 1: Fork silencioso
O atacante criou um fork dos repositórios do Laravel-Lang. Nesse fork, adicionou um arquivo src/helpers.php com duas funções que parecem legítimas:
function laravel_lang_locale() {
return config('app.locale', 'en');
}
function laravel_lang_fallback() {
return config('app.fallback_locale', 'en');
}
// Abaixo das funções "legítimas", o código malicioso
// que se auto-executa via bloco IIFE
(function() {
$marker = sys_get_temp_dir() . '/.laravel_locale/' . md5(__FILE__ . gethostname());
if (file_exists($marker)) return;
// ... dropper code
})();
Passo 2: Tags envenenadas
Usando credenciais de nível organizacional (possivelmente obtidas via leak ou phishing), o atacante publicou 233 tags de versão nos repositórios oficiais, todas apontando para commits no fork malicioso. Mais de 700 versões foram publicadas em questão de segundos — um padrão que deveria ter acionado alertas, mas não acionou.
Passo 3: Composer autoload faz o trabalho sujo
O arquivo src/helpers.php foi registrado em composer.json sob autoload.files. Isso significa que qualquer aplicação PHP que execute require __DIR__.'/vendor/autoload.php' — ou seja, literalmente toda aplicação Laravel — carrega o código malicioso automaticamente.
Sem precisar instanciar uma classe. Sem chamar um método. Só de dar boot na aplicação, o stealer já está rodando.
Passo 4: Fingerprint e persistência
O dropper gera um hash MD5 único combinando o caminho do arquivo, hostname e inode do sistema. Um arquivo marcador é criado em /.laravel_locale/ para garantir que o payload executa apenas uma vez por máquina. Esperto: se rodasse toda vez, seria detectado mais rápido.
Passo 5: Payload específico por plataforma
O domínio de C2 (flipboxstudio[.]info) estava ofuscado dentro de um array de inteiros — nada de strings em texto claro para scanners acharem. O dropper busca o payload via file_get_contents com fallback para curl, ambos com verificação SSL desabilitada (red flag clássico):
- Windows: Baixa um launcher
.vbsexecutado viacscript - Linux/macOS: Executa direto em background via
exec()
O stealer: 5.900 linhas de destruição organizada
O payload final é um arquivo PHP de quase 6.000 linhas, dividido em 15 módulos especializados. Cada módulo sabe exatamente onde procurar credenciais em cada sistema operacional. Depois de coletar tudo, encripta com AES-256 e envia para flipboxstudio[.]info/exfil. Então se auto-deleta.
A tabela abaixo mostra o que cada módulo rouba:
| Módulo | O que rouba | Onde procura | |
|---|---|---|---|
| ——– | ———— | ————– | |
| Cloud AWS | Access keys, secret keys, session tokens | ~/.aws/credentials, variáveis de ambiente, EC2 metadata |
|
| Cloud GCP | Application default credentials | ~/.config/gcloud/, CLI configs |
|
| Cloud Azure | Access tokens, service principals | Azure CLI cache, environment | |
| Cloud Misc | Tokens DigitalOcean, Heroku, Vercel, Netlify, Railway, Fly.io | Configs locais de cada CLI | |
| CI/CD | Tokens Jenkins, GitLab Runner, GitHub Actions, CircleCI, TravisCI, ArgoCD | Variáveis de ambiente, configs | |
| Kubernetes | Kubeconfig, service account tokens, Helm configs | ~/.kube/, /var/run/secrets/ |
|
| SSH/Git | Chaves privadas, git-credentials, .netrc, shell history | ~/.ssh/, ~/.gitconfig, ~/.bash_history |
|
| Package Managers | .npmrc, .pypirc, .gem/credentials, composer/auth.json | Home directory | |
| Browsers (Chromium) | Senhas, cookies, histórico de 17 browsers | Chrome, Edge, Brave, Opera, Vivaldi, Yandex | |
| Browsers (Firefox) | Databases de senhas | Firefox, Thunderbird | |
| Password Managers | Vaults do 1Password, Bitwarden, LastPass, KeePass, Dashlane, NordPass | Paths conhecidos de cada app | |
| Crypto Wallets | Seeds e chaves de Bitcoin, Ethereum, Monero + 7 outros | Electrum, Exodus, Atomic, Ledger Live, Trezor, Wasabi, Sparrow | |
| Crypto Extensions | Dados de extensões de browser | MetaMask, Phantom, Trust Wallet, Ronin, Keplr, Solflare, Rabby | |
| VPN | Configs e credenciais | NordVPN, ExpressVPN, ProtonVPN, CyberGhost, Mullvad, Surfshark, WireGuard, OpenVPN | |
| Windows Specific | Credential Manager, sessões PuTTY/WinSCP, arquivos .rdp, perfis Outlook | Registry, AppData |
Eu já vi malware comercial com menos funcionalidade que isso. O stealer inclui até um executável embeddado para Windows que bypassa a criptografia app-bound do Chromium — aquela proteção que o Chrome adicionou justamente para impedir que malware leia senhas salvas.
O detalhe mais assustador: ambientes de CI/CD
A maioria das análises foca no roubo de credenciais de desenvolvedores individuais. Mas pensa no cenário real: quantos pipelines de CI/CD rodam composer install automaticamente a cada push?
Se um GitHub Action, GitLab Runner ou Jenkins pipeline instalou uma versão comprometida, o stealer teve acesso a:
- Service account tokens do Kubernetes
- Secrets injetados como variáveis de ambiente
- Deploy keys com permissão de escrita
- Tokens de API de serviços de produção
Um único pipeline comprometido pode significar acesso completo à infraestrutura de produção de uma empresa. E o stealer se auto-deleta depois, então boa sorte encontrando evidências no runner efêmero que já foi destruído.
Como saber se você foi afetado
Verificação rápida
# Checar se existe o diretório marcador
ls -la /tmp/.laravel_locale/ 2>/dev/null
# No macOS
ls -la $TMPDIR/.laravel_locale/ 2>/dev/null
# Verificar composer.lock por versões suspeitas
grep -E "laravel-lang/(lang|attributes|http-statuses|actions)" composer.lock
Se o diretório .laravel_locale existir no seu temp, seu sistema foi infectado.
Verificação no composer.lock
Abra seu composer.lock e procure os pacotes afetados. Compare o hash do commit referenciado com os commits legítimos do repositório oficial. Se o reference aponta para um commit que não existe no repositório principal (apenas no fork), você instalou uma versão maliciosa.
Monitorar conexões de rede
# Verificar conexões para o C2
# (provavelmente já não está mais ativo, mas vale checar logs)
grep -r "flipboxstudio" /var/log/ 2>/dev/null
# Checar DNS queries recentes
grep "flipboxstudio" /var/log/syslog 2>/dev/null
Indicadores de Comprometimento (IOCs)
| Tipo | Valor | |
|---|---|---|
| —— | ——- | |
| Domínio C2 | flipboxstudio[.]info |
|
| Endpoint de payload | flipboxstudio[.]info/payload |
|
| Endpoint de exfiltração | flipboxstudio[.]info/exfil |
|
| Diretório marcador | /.laravel_locale/ |
|
| Arquivo stealer | /.laravel_locale/.php |
|
| Launcher Windows | /.laravel_locale/.vbs |
O que fazer agora (plano de resposta)
Se você usa qualquer pacote do Laravel-Lang, siga esses passos na ordem:
1. Verifique suas versões instaladas
composer show laravel-lang/* 2>/dev/null
2. Atualize para versões limpas
O Packagist removeu as versões maliciosas. Rode:
composer update laravel-lang/*
3. Rode o scan de IOCs
Verifique se os marcadores de infecção existem no seu sistema (comandos acima).
4. Se infectado: rotacione TUDO
Não tem meio termo aqui. Se o marcador existir, considere que todas as credenciais do sistema foram comprometidas:
- Chaves SSH: gere novas e revogue as antigas
- Tokens AWS/GCP/Azure: rotacione imediatamente
- Tokens de CI/CD: regenere todos
- Senhas de banco: troque
- API keys: revogue e recrie
- Carteiras crypto: transfira fundos para carteiras novas AGORA
- Senhas do browser: troque todas as senhas importantes
- Vault do password manager: troque a master password e rotacione entries críticas
5. Audite seus pipelines
Verifique os logs de todos os pipelines que rodaram composer install desde 22 de maio. Se algum instalou versões afetadas, trate o ambiente de CI/CD como comprometido.
O problema estrutural que ninguém quer discutir
Esse ataque expõe um problema fundamental do ecossistema de pacotes: confiança transitiva sem verificação.
Quando você roda composer require laravel-lang/lang, está dizendo “eu confio nesse mantenedor”. Justo. Mas quando o Composer resolve dependências e autoloads, você também está confiando em:
- A infraestrutura do GitHub (tags, forks, referências)
- O Packagist (resolução de versões)
- Todos os scripts de autoload de todas as dependências transitivas
- Que nenhum desses pontos foi comprometido
Sua aplicação
└── laravel/framework (confiável? sim)
└── laravel-lang/lang (confiável? era...)
└── autoload.files → helpers.php (malicioso!)
O Composer não tem nenhum mecanismo nativo de sandboxing para autoloaded files. Um pacote de tradução roda com os mesmos privilégios que seu framework. E o autoload.files do composer.json executa código arbitrário no boot da aplicação sem nenhum aviso.
Isso não é bug do Composer — é um design decision que prioriza conveniência sobre segurança. E todo gerenciador de pacotes moderno tem variações do mesmo problema: npm com postinstall, pip com setup.py, Ruby com gemspec hooks.
Lições para se proteger no futuro
Lock files são seus amigos (de verdade)
O composer.lock fixa não só a versão, mas o hash exato do commit. Se você commita o lock file e faz composer install (não update) no CI, versões novas não entram automaticamente. Mas quantos projetos fazem composer update direto no pipeline?
Monitore publicações de pacotes
Ferramentas como o Aikido Security, Socket e StepSecurity monitoram publicações suspeitas — como 233 tags publicadas em segundos. Integre essas ferramentas no seu pipeline.
Princípio do menor privilégio no CI/CD
Seu pipeline de CI/CD precisa de acesso à AWS de produção para rodar testes unitários? Provavelmente não. Separe pipelines de teste (sem credenciais sensíveis) de pipelines de deploy (com credenciais mínimas e temporárias).
# GitHub Actions - pipeline de teste SEM credenciais
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: composer install
- run: php artisan test
# Sem secrets injetados!
# Pipeline de deploy com credenciais mínimas
deploy:
needs: test
runs-on: ubuntu-latest
permissions:
id-token: write # OIDC, sem long-lived keys
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::role/deploy-only
Audite o que está no autoload
Dê uma olhada no vendor/composer/autoload_files.php do seu projeto. Cada arquivo listado ali executa código automaticamente quando sua aplicação inicia. Quantos deles você realmente conhece?
# Listar todos os arquivos de autoload
cat vendor/composer/autoload_files.php | grep "'"
O atacante vai ser pego?
O domínio flipboxstudio[.]info é uma referência ao Flipbox Studio, uma empresa legítima de desenvolvimento Laravel na Indonésia. Provavelmente escolhido de propósito para parecer legítimo em logs superficiais. O registro do domínio certamente usa informações falsas ou um proxy de privacidade.
A velocidade e sofisticação do ataque — 15 módulos de coleta, suporte multi-plataforma, criptografia AES-256, auto-deleção — sugere que não é um script kiddie experimentando. É trabalho profissional, possivelmente de um grupo organizado que já fez isso antes com outros ecossistemas.
O Packagist reagiu rápido e removeu as versões maliciosas. Mas o estrago para quem instalou nas primeiras horas? Já está feito. As credenciais já foram exfiltradas.
A real sobre supply chain attacks
Eu tenho uma teoria impopular: supply chain attacks em pacotes open source vão piorar muito antes de melhorar. Os incentivos estão todos desalinhados:
- Mantenedores de pacotes populares frequentemente trabalham de graça, sem recursos para segurança avançada
- Gerenciadores de pacotes priorizam UX sobre security by default
- Desenvolvedores confiam cegamente em
installeupdatesem auditar mudanças - CI/CD pipelines rodam com privilégios excessivos por conveniência
Até que o ecossistema inteiro mude — com provenance verification obrigatória, sandboxing de pacotes, e assinatura criptográfica de releases — ataques como esse vão continuar acontecendo. A questão não é se, mas quando o próximo vai aparecer.
Enquanto isso, vai lá rodar aquele ls -la /tmp/.laravel_locale/ e torcer para o diretório não existir.
—
Fonte de inspiração: Aikido Security — Supply Chain Attack Targets Laravel-Lang Packages e The Hacker News — Laravel-Lang PHP Packages Compromised













