A Virada do Apex no Summer ’26
Desde que o Apex existe — e isso já faz quase duas décadas — o comportamento padrão do código era simples de resumir: se você não dizia nada, ele rodava com acesso total. SOQL via tudo. DML atualizava qualquer campo. O desenvolvedor precisava ativamente restringir o acesso. Adicionar WITH SECURITY_ENFORCED, declarar with sharing, verificar FLS manualmente. Tudo opcional. Tudo sob responsabilidade de quem escrevia o código.
O Summer ’26 vira essa lógica de cabeça para baixo. A partir da API versão 67, o Apex passa a ser seguro por padrão. Não é um ajuste cosmético. São três mudanças que chegam juntas e que, combinadas, representam a maior alteração no modelo de segurança do Apex desde que a linguagem foi criada.
Se você mantém código Apex em produção, este artigo é sobre o que quebra, o que não quebra, e o que você precisa fazer antes que sua próxima deployment quebre sozinha.
As três mudanças — e por que elas são uma coisa só
A Salesforce poderia ter entregue cada uma dessas mudanças em releases separados. Não fez isso. As três chegam juntas na API v67 porque juntas elas formam uma mudança de paradigma:
- Database operations agora rodam em user mode por padrão. SOQL, SOSL, DML e métodos Database — tudo que antes corria em system mode sem você pedir — agora respeita as permissões do usuário que está rodando o código.
- Classes sem declaração explícita de sharing viram
with sharingpor padrão. Omissão de sharing não é mais inofensiva. Ela muda o comportamento. WITH SECURITY_ENFORCEDfoi removido. Qualquer classe em v67 que use essa claúsula não compila. O substituto éWITH USER_MODE.
Não são três funcionalidades separadas. São três manifestações do mesmo princípio: o Apex não presume mais acesso elevado. O acesso elevado agora precisa ser explícito.
Paul Battiston, MVP Hall of Famer e CEO da Groundwork Apps, resumiu bem no Salesforce Ben: “Essas mudanças são um passo na direção certa para melhorar a segurança da plataforma por padrão. Só certifique-se de testar seu código ao subir versões de API.”
Na prátia, o que muda no seu código
O impacto depende de como você escreve Apex. Se você sempre declarou with sharing e sempre usou WITH USER_MODE ou Security.stripInaccessible(), talvez você não sinta nada. Mas se você herdou código legado — e quem não herdou? — prepare-se.
Cenário 1: Controller de LWC que expõe dados
Imagine um controller simples que alimenta um componente Lightning:
public class AccountController {
@AuraEnabled(cacheable=true)
public static List<Account> getAccounts() {
return [
SELECT Id, Name, AnnualRevenue
FROM Account
ORDER BY Name
LIMIT 50
];
}
}No API v66 ou anterior, esse código retornava AnnualRevenue mesmo que o usuário não tivesse acesso de leitura ao campo. O Apex simplismente ignorava o FLS. No v67, a mesma query pode falhar — ou retornar menos campos — porque agora ela respeita o que o usuário de fato pode ver.
A versão correta e explícita:
public with sharing class AccountController {
@AuraEnabled(cacheable=true)
public static List<Account> getAccounts() {
return [
SELECT Id, Name, AnnualRevenue
FROM Account
WITH USER_MODE
ORDER BY Name
LIMIT 50
];
}
}O WITH USER_MODE pode parecer redundante no v67, já que user mode é o padrão. Mas eu ainda recomendo usá-lo. O objetivo não é satisfazer o compilador. É deixar o contrato de segurança legível para o próximo desenvolvedor que mexer nesse código. Ele não deveria precisar saber a versão de API da classe para entender se a query respeita o usuário.
Cenário 2: Automação de backend que precisa de sistema mode
Nem todo código Apex deve rodar com as permissões do usuário. Uma ação invocável que avança um pedido no fluxo de aprovação, um batch de reconciliação noturna, uma integração que atualiza campos internos — esses processos são do sistema, não do usuário.
O problema é que muito código legado simplesmente não dizia isso. Ele se apojava no comportamento implícito. Agora o código precisa ser explícito:
public inherited sharing class OrderAdvancementService {
public static void markReadyToInvoice(Set<Id> orderIds) {
List<Order> orders = [
SELECT Id, Status
FROM Order
WHERE Id IN :orderIds
WITH SYSTEM_MODE
];
for (Order ord : orders) {
ord.Status = 'Ready To Invoice';
}
update as system orders;
}
}A linha update as system é a novidade aqui. Ela diz: essa atualização é intencionalmente elevada. O desenvolvedor tomou a decisão de que o processo de negócio — não o usuário — é o dono dessa transição.
Isso não significa ignorar segurança. Significa mover a decisão de segurança para a camada certa. O usuário ainda precisa estar autorizado a iniciar o processo. Os registros ainda passam por validações. Mas o campo interno de status não precisa fingir que é uma edição direta do usuário.
Cenário 3: Database methods com AccessLevel
O mesmo princípio se aplica aos métodos Database.update, Database.insert e similares. Antes:
Database.SaveResult[] results = Database.update(records, false);Depois, se a operação deve respeitar o usuário:
Database.SaveResult[] results = Database.update(
records,
false,
AccessLevel.USER_MODE
);Code language: JavaScript (javascript)
Se for automação confiável:
Database.SaveResult[] results = Database.update(
records,
false,
AccessLevel.SYSTEM_MODE
);O que NÃO mudou
System mode ainda existe. Triggers continuam rodando em system mode e vão continuar assim. Esse é um ponto importante porque a reação erada a essa mudança é tratar toda falha de v67 como bug de permissão. Às vezes a falha está te dizendo que o código acessava dados que não devia. Outras vezes está te dizendo que o código é automação legítima de backend e deveria ser explícito sobre isso.
Saber distingüir um caso do outro é exatamente o trabalho de arquitetura que o v67 nos obriga a fazer.
Sharing não é FLS — e isso impora mais agora
Um erro comum de segurança em Apex é tratar with sharing como se resolvesse tudo. Não resolve.
with sharing controla acesso a registros. Determina se o código respeita as regras de compartilhamento de quais registros o usuário pode ver.
Não controla permissões de objeto nem field-level security. A documentação da Salesforce é clara sobre isso: with sharing e without sharing afetam segurança em nível de registo, não segurança em nível de objeto ou campo.
Essa distinção impora mais no v67 porque há dois defaults mudando no mesmo release:
public class MyService {
// No v67, sharing omitido = with sharing
}
List<Account> accounts = [
SELECT Id, Name
FROM Account
// No v67, database operation = USER_MODE
];São preocupações separadas. Uma controla visibilidade de registros. A outra controla como as operações de banco reforçam o acessso mais amplo do usuário. Um codebase limpo no v67 deve tornar as duas decisões visíveis.
O que você precisa fazer agora
Se você tem código Apex em produção, essa não é uma mudança que dá para adiar. O Summer ’26 já chegou nas instâncias de produção entre 15 de maio e 13 de junho de 2026. Seu org já pode estar rodando na nova versão.
- Audite seu código existente. Busque por
WITH SECURITY_ENFORCED— ele não compila mais no v67. Substitua porWITH USER_MODE. - Revise classes sem declaração de sharing. A partir do v67, omitir sharing significa
with sharing. Se o código dependia do comportamento antigo, adicionewithout sharingexplícito. - Recompile e teste. Testes que passavam no v66 não garantem comportamento correto no v67. Adicione cenários de teste que rodam como usuários restritos e verificam a visibilidade correta dos dados.
- Para managed packages, a revisão é inegociável. O novo comportamento afeta todos os assinantes quando o pacote é atualizado.
A recomendação de Mohith Shrivastava, Principal Developer Advocate da Salesforce, no blog oficial de desenvolvedores: “Planeje agora. O SOAP login() está sendo aposentado, e o Apex está mudando. Teste em sandbox antes de subir qualquer classe para v67.”
Estratégia de teste: o que seus testes atuais não cobrem
Seus testes de Apex foram escritos contra os defaults antigos. Eles passavam porque o código, rodando em system mode, via tudo — e os asserts foram escritos esperando esse comportamento. O problema é que testes que passam no v66 não provam que o código funciona corretamente no v67.
O caminho seguro é adicionar testes que executam como usuários com permissões restritas. Crie um perfil de teste com acesso limitado a campos e objetos, execute os métodos como esse usuário usando System.runAs(), e verifique se o código retorna apenas o que o usuário deveria ver. Se um método de backend precisa de system mode, o teste deve documentar essa decisão com um comentário e o código deve ser explícito com WITH SYSTEM_MODE ou AccessLevel.SYSTEM_MODE.
Para quem mantém managed packages, o risco é maior. O comportamento do seu pacote muda para todos os assinantes quando você sobe a versão de API. A Salesforce recomenda fazer essa auditoria em sandbox com dados realistas antes de qualquer deployment.
O que torna essa mudança diferente
A Salesforce já fez mudanças de segurança antes. Mas essa é diferente porque inverte a lógica fundamental da plataforma. Durante quase 20 anos, o Apex presumiu acesso total. O desenvolvedor adicionava restrições. Agora o Apex presume acesso restrito. O desenvolvedor adiciona elevações.
Isso muda o custo cognitivo de escrever Apex seguro. Antes, você precisava lembrar de restringir. Agora, você precisa lembrar de quando — e por que — está elevando. É uma inversão completa de responsabilidade.
E é uma melhoria genuína. O velho padrão era uma fonte comum de exposição acidental de dados. Classes que retornavam todos os registros porque ninguém lembrou de adicionar with sharing. Queries que expunham campos que o usuário não devia ver. O v67 reduz drasticamente a quantidade de elevação acidental na plataforma.
Como o time da Asyncronaut colocou: “API v67 não remove o system mode do Apex. Ela remove o conforto de não pensar nele.”
E isso é uma coisa boa.
