Skip to content

[3.0] Answer an activation link that names nobody - #9482

Merged
live627 merged 1 commit into
SimpleMachines:release-3.0from
albertlast:3.0/activate-unknown-member
Aug 11, 2026
Merged

[3.0] Answer an activation link that names nobody#9482
live627 merged 1 commit into
SimpleMachines:release-3.0from
albertlast:3.0/activate-unknown-member

Conversation

@albertlast

Copy link
Copy Markdown
Collaborator

Description

An activation link whose u names nobody is a 500.

$ curl -s -o /dev/null -w '%{http_code}\n' 'index.php?action=activate;u=999;code=x'
500
$ mysql -e "SELECT message, file, line FROM smf_log_errors ORDER BY id_error DESC LIMIT 1"
Typed property SMF\Actions\Activate::$member must not be accessed before initialization
/var/www/html/Sources/Actions/Activate.php   255

Activate::loadMember() assigns $this->member only when it finds someone. The
line after the call reads $this->member->is_activated unconditionally.

The handling for this already exists and cannot be reached.
Activate::execute() opens with

if (!isset($this->member)) {
    if (empty($_REQUEST['u']) && empty($_POST['user'])) {
        $this->showResendRequest();
    } else {
        $this->showRetryInvalidUser();
    }

    return;
}

which is 2.1's behaviour — the form asking for a username and an activation code.
The constructor throws first, so execute() never runs.

This is reachable in ordinary use: a member deleted while their activation mail
is in flight, an id that got mangled in a mail client, or a link followed after
the account was pruned.

What changes

The constructor returns when loadMember() found nothing, and leaves the answer
to the guard execute() already has.

Testing

?action=activate;u=999;code=x and ?action=activate;u=999 both give a 200 with
"User does not exist" and the retry form, and log nothing. A real activation link
still activates; ?action=activate with no u still shows the resend form.

Issues References (Fixes|Related|Closes)

Related to #7933

loadMember() assigns $this->member only when it finds someone, and the line
after it reads $this->member->is_activated regardless, so an activation link
for a member id that no longer exists is a 500 rather than a page.

execute() already handles this: if the member is not set it shows the form that
asks for a username and an activation code, which is what 2.1 did. It never
gets the chance, because the constructor has already thrown.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
@jdarwood007 jdarwood007 added this to the 3.0 Alpha 6 milestone Aug 10, 2026
@live627
live627 merged commit fb81ff9 into SimpleMachines:release-3.0 Aug 11, 2026
4 checks passed
@jdarwood007 jdarwood007 modified the milestones: 3.0 Alpha 6, 3.0 Alpha 5 Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants