Skip to content

backlog: file #1245 -- an admin password reset re-arms bootstrap retirement and disables the account - #365

Merged
wshallwshall merged 1 commit into
mainfrom
claude/asvs-1245-bootstrap-retirement
Aug 13, 2026
Merged

backlog: file #1245 -- an admin password reset re-arms bootstrap retirement and disables the account#365
wshallwshall merged 1 commit into
mainfrom
claude/asvs-1245-bootstrap-retirement

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

Files one backlog item. Docs-only: docs/BACKLOG.md, +29 lines, 0 deletions, pure append.

#1245 -- an administrator password reset re-arms bootstrap retirement and disables the account.

The defect

admin_reset_password sets must_change_password=True. That is the same flag
_retire_superseded_bootstrap reads as "the bootstrap is still unclaimed".

So: reset the password of a local account named admin, on a system that has any other enabled
administrator, and the next login attempt disables the account ahead of the credential check. The
temporary credential just issued can never be used. Re-enabling re-triggers it. No route clears the
flag except the self-service change -- which needs the session the reset just revoked.

The recovery route is the destruction route.

Why it survived review

The docstring at auth/service.py:580-581 asserts this cannot happen, and it is right about a
self-service change
, which CLEARS the flag. It is wrong about an administrator reset, which SETS
it. The item says so explicitly, because the fix has to correct that sentence and not just the code --
a fix that leaves the docstring standing re-teaches the same wrong model to the next reader.

Scope bound -- please do not lose this if you summarise the item

This is a strong STATIC finding, not a demonstrated one. The chain was read at origin/main with
every line confirmed individually. It has not been reproduced by executing a login sequence, and
the confirming test does not exist. That bound is written into the item body deliberately and should
survive into whatever closes it.

Verification

  • exactly one commit e7c16805, matching the filing session's report
  • base 2d11dacc is current origin/main -- fresh branch, not stacked on the #1243 head
  • carries zero commits belonging to #1243, which is on its own branch and its own PR (backlog: file #1243 -- close ASVS 1.2.2 on the merits, both limbs in one item #364);
    the filing session split them deliberately rather than adding a second unrelated item to an armed PR
  • docs-only, +29 -0
  • ledger gate passed (1245 allocated via alloc.ps1), leak guard passed
  • parse_items: #1245 present, OPEN, exactly one status banner

Severity is written in the conditional per CLAUDE.md section 0.

…rement and disables the account

Found while adjudicating the ASVS 6.1.1 re-score, not by looking for it: the
recovery route docs/SECURITY.md now prescribes is the route that destroys the
account, on a system with more than one administrator.

admin_reset_password sets must_change_password=True, which is the same flag
_retire_superseded_bootstrap reads as "still unclaimed". The retirement runs at
the head of _login_local for the bootstrap username, ahead of the credential
check, so the next login attempt disables the account and the temporary
credential the administrator just issued can never be used. Re-enabling does not
help: the flag is still set and another administrator still exists, so the next
attempt retires it again. No route clears the flag except the self-service
password change, which needs the session the reset revoked.

The docstring immediately above the gate asserts this cannot happen. That claim
holds for a self-service password change, which clears the flag, and fails for an
administrator reset, which sets it. Recording that explicitly because it is why
the defect survived review, and the fix has to correct the sentence too.

Both ends of the failure are silent: the administrator sees a successful reset,
the holder sees a generic invalid-credentials refusal that is deliberately
indistinguishable from a wrong password. The retirement is audited, but nothing
surfaces it where either party would look.

The item bounds itself: the chain was read statically and each line confirmed
individually, not reproduced by executing a login sequence, and the confirming
test does not exist yet.
@wshallwshall
wshallwshall enabled auto-merge (squash) August 13, 2026 13:54
@wshallwshall
wshallwshall merged commit 950b0cd into main Aug 13, 2026
33 of 34 checks passed
@wshallwshall
wshallwshall deleted the claude/asvs-1245-bootstrap-retirement branch August 13, 2026 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant