Documentation
Getting Started
Daily Operations
Networks & Mail
Look & Feel
Doors & Games
Web Features
Development
Reference
Other

ANetBBS Changelog

Current release: v1.1.53 (October 2026). This file covers v1.0.0
onward, which follows standard semantic versioning — patch releases are
v1.0.1, v1.0.2, and so on. The full internal beta build-number
history (v1.0a1.1 through v1.0b2.239) that got the project to this
release is preserved in
CHANGELOG-beta.md.

v1.0.78 — SSH key login, translations, achievements, door-dev tooling, TUI accessibility (September 2026)

A feature round following up the ninth audit's competitive gap
analysis, plus two live accessibility bugs reported and fixed during
the same window.

  • SSH public-key login. Register a public key at Profile →
    Security → SSH Keys and log in over SSH with no password prompt at
    all. Purely additive — password login is completely unchanged for
    every account that doesn't register a key.
  • Web UI translations. The terminal menu system's existing
    translation mechanism now also covers the web UI (a new t()
    template helper), with an admin page (and a matching anetbbs-cfg
    section) to manage overrides. Spanish, German, and Portuguese are
    seeded by default for the navigation bar and a few other high-
    traffic labels; more template coverage can be added incrementally.
  • Achievements documented and expanded. The existing badge system
    (previously undocumented) now has a README section, and grew from
    10 to 18 rules — new ones tied to Game Center high scores, wiki
    edits, file uploads, and door-game variety.
  • anetbbs-export-users — the export-direction counterpart to
    anetbbs-import-users, for getting user account data (never
    passwords) out to a portable CSV/JSON file.
  • Windows install guide (docs/INSTALL-WINDOWS.md) covering the
    WSL2 and Docker Desktop paths.
  • builtin_python door-writing tutorial and a new scaffolding
    script (anetbbs-scaffold-door) that generates a starter door
    module plus a draft (inactive-until-reviewed) catalog entry.
  • anetbbs-cfg accessibility fixes, both from a live report by a
    screen-reader user: long help text in edit forms was being silently
    cut off at the terminal width instead of wrapping (affected several
    sections, not just the one reported); and every edit form now has
    explicit on-screen [ Save ]/[ Cancel ] rows navigable with the
    same arrow keys as everything else, alongside the existing F2/Esc
    shortcuts, since a function-key sequence not matching what a given
    terminal actually sends could silently discard unsaved edits with no
    warning.
  • Fixed a stale "(beta)" label and an outdated log-path reference in
    the GitHub bug-report issue template.
  • Closed a real correctness gap in the terminal/SSH login layer's
    database-connection handling, in the same class as a similar fix
    earlier this release cycle — dormant in normal production use (a
    deployed process only ever opens one database connection at
    startup), surfaced while testing the SSH key-login feature above.

v1.0.77 — Ninth audit pass: every script, full docs sweep, cfg/monitor hardening review (September 2026)

A ninth audit pass, widening scope to ground not systematically covered
by the eight prior rounds: every standalone maintenance script in
tools/, the shell/Docker deployment layer, a complete accuracy sweep
of every file in docs/, and a closing vulnerability-class review of
the two standalone in-package tools (the terminal config editor and
node monitor) that had seen comparatively less direct attention than
the web blueprints. Same severity-tiered approach as the eight prior
rounds; this entry again omits vulnerability specifics in the interest
of responsible disclosure. Every code fix has a dedicated regression
test.

  • Added integrity verification (checksum compare against known-good
    values, with automatic deletion on mismatch) to the DOS-game-support
    asset downloader, which previously wrote whatever a remote host
    served with no verification at all.
  • Extended the automated code-scan gate (bandit + pyflakes) to cover
    tools/, which had been silently out of scope since the scanning
    step was first added — closing a real, previously unnoticed coverage
    gap rather than just fixing what the wider scan happened to find.
  • Hardened a credential-rotation maintenance script to prompt for its
    password interactively instead of accepting it as a command-line
    argument, and removed a real credential that had been sitting in the
    script's own usage example.
  • Corrected numerous stale references across docs/ and deploy/ to
    the project's pre-v1.0a2.67 process-management approach, which was
    deliberately replaced for Python 3.12 compatibility; a standalone
    entry-point file left over from that era is now clearly marked
    deprecated rather than silently unreferenced.
  • Closed a real correctness bug in a database-configuration class
    affecting any process that constructs more than one app instance
    with a different database in sequence — the second and later
    instances silently reused the first instance's database. Dormant in
    normal production use (a deployed process only ever constructs one
    app instance), but real, and the direct cause of a diagnostic script
    failing outright.
  • Reviewed the terminal config-editor and node-monitor tools against
    the established recurring-vulnerability checklist (privilege
    escalation via a shared launch chokepoint, credential handling, path
    safety, injection) — confirmed already correctly hardened from a
    prior round's fix, no new issues found.
  • Corrected a documentation/code mismatch in a rate-limit docstring, a
    stale feature-count in the themes documentation, and a broken
    version-pinned download URL in the Raspberry Pi install guide, among
    numerous smaller documentation accuracy fixes found in the full
    docs/ sweep.

v1.0.76 — Eighth audit pass: security infrastructure, performance, docs (September 2026)

An eighth audit pass, this time focused less on finding one-off code
bugs (the last several rounds already covered a lot of that ground) and
more on infrastructure-level questions: were there whole categories of
security or performance hardening genuinely missing, not just individual
bugs in the code that's there. Same severity-tiered approach as the
seven prior rounds; this entry again omits vulnerability specifics in
the interest of responsible disclosure. Every finding has a dedicated
regression test.

  • Added site-wide security response headers (Content-Security-Policy,
    X-Frame-Options, X-Content-Type-Options, Referrer-Policy,
    Permissions-Policy) — previously absent entirely. The public embed
    page is deliberately exempted from the framing restriction, and HSTS
    is only sent over an actual HTTPS connection so it can never lock out
    an install that hasn't set up TLS yet.
  • Reviewed session cookie hardening, rate-limiting, and auto-ban
    coverage end to end — confirmed already correctly configured, no
    changes needed.
  • Closed a couple more real database/query gaps found in a systematic
    audit of every foreign-key column in the schema: one more missing
    index on a routinely-queried per-user column, and an eager-loading
    fix for a file listing that was issuing one extra query per row.
  • Added response compression and static-asset cache headers where they
    were missing, at both the reference reverse-proxy layer and as an
    application-level fallback.
  • Reviewed the deliberate choice to auto-apply schema changes on every
    app start rather than use a manual migration-command workflow, and
    confirmed it's the right fit for this project's self-hosted-sysop
    deployment model; documented the pattern more completely for future
    contributors.
  • Reviewed whether to add persistent (Redis/DB-backed) rate limiting or
    two-factor authentication — decided against both for now, for
    documented reasons, with the existing limitations already accurately
    described in docs/SECURITY.md.
  • Fixed a real, live bug on the Release Downloads page: clicking the
    checksum button on an already-generated checksum sidecar file hashed
    the sidecar itself instead of refusing, letting repeated clicks pile
    up an unbounded chain of nested checksum files. Checksum/signature
    sidecars no longer appear as their own downloadable entry, and the
    checksum endpoint now refuses to checksum a checksum file outright.

v1.0.75 — Seventh audit pass: templates, models, deploy hardening, CI coverage (September 2026)

A seventh audit pass, broader in scope than the two prior rounds:
Jinja templates across the whole app, the core data model and app
factory, the reference systemd deployment units, and CI's dependency
vulnerability scanning coverage. Same severity-tiered approach as the
six prior rounds (v1.0.38, v1.0.39, v1.0.48, v1.0.66, v1.0.71, v1.0.72);
this entry again omits vulnerability specifics in the interest of
responsible disclosure. Every finding has a dedicated regression test.

  • Hardened several sysop- or peer-suppliable URL fields rendered as
    clickable links across the profile, RSS, peer-directory,
    ANSI/postcard editor, and IRC web-client pages against
    javascript:-URI and script-injection payloads — one of these was
    reachable by any registered user against a reviewing sysop's own
    browser session.
  • Capped the size of an inbound message the MRC web chat client will
    parse, matching the same cap already applied server-side to the
    BinkP network listener.
  • Closed a gap where a revoked account's already-open web session kept
    access until its next login, instead of losing access immediately —
    matching the existing behavior already in place for a banned or
    locked account.
  • Fixed a missing foreign-key constraint on a message-tracking column,
    and added missing database indexes on two columns queried on every
    leaderboard view and door-game launch attempt, with an automatic
    backfill for existing installs.
  • Extended CI's dependency vulnerability scanning to cover every
    requirements file this project ships, not just the runtime one —
    closing a gap where the Docker-image and developer-tooling
    dependency sets were unaudited.
  • Brought the reference deploy/*.service systemd unit files (used as
    install documentation; the real install/update scripts always
    generate the actual units directly) back in sync with the
    sandboxing directives those scripts actually apply, and added the
    one previously undocumented unit that was missing entirely.

v1.0.74 — CI-only fix: Node-dependent test didn't skip without Node (September 2026)

Fixed a genuine Docker build CI failure on v1.0.73: a new regression
test added during the sixth audit pass (verifying a generated
Synchronet-compat script is syntactically valid JavaScript) shelled
out to node --check unconditionally, unlike every other Node-
dependent test in the same file, which already skip gracefully when a
real Node.js binary isn't present. The CI Docker image doesn't (and
shouldn't need to) have Node.js installed, so the test failed there
with a plain "no such file" error rather than skipping. Brought into
line with the existing convention; the test's other half (a byte-level
check that needs no external tool at all) already fully verifies the
real fix and is unaffected. No runtime behavior change, no functional
bug.

v1.0.73 — CI-only fix: unused import (September 2026)

Fixed a genuine code-scan CI failure on v1.0.72: dead-code removal in
anetbbs/games/dos_bridge.py during the sixth audit pass deleted the
code that used its os import but left the import itself behind.
Caught by pyflakes in CI, not by the local test suite (pyflakes/bandit
aren't part of the local pytest-based verification loop) — no runtime
behavior change, no functional bug.

v1.0.72 — Sixth security/performance audit pass, network daemons and tooling (September 2026)

A sixth audit pass covered ground the fifth round (web + terminal)
didn't reach: the FidoNet-style echomail network daemons, the door-game
session/process-management layer, the MRC chat bridge, MSP, FTP, the
wiki, the sysop configuration tool, maintenance scripts, and the
install/update/build scripts. Same severity-tiered approach as the five
prior rounds (v1.0.38, v1.0.39, v1.0.48, v1.0.66, v1.0.71); this entry
again omits vulnerability specifics in the interest of responsible
disclosure. Around 17 real, independently-verified findings, every one
with a dedicated regression test. In summary, this pass:

  • Closed a resource-exhaustion gap reachable by a fully anonymous,
    unauthenticated network peer, where inbound file receiving over one
    protocol had no overall cap across a whole session (only a per-file
    one), plus a related gap where an outbound network-polling download
    had no size cap at all.
  • Fixed a rate-limiter that was keyed on a self-reported, spoofable
    field instead of the real connection source, and an unbounded
    parsing loop in the same subsystem.
  • Fixed a case where disconnecting a caller's in-progress session could
    silently fail to actually terminate the underlying process while
    still reporting success and freeing its resources for immediate
    reuse — an internal process-management gap, not a user-facing
    feature change.
  • Closed a path-traversal gap in a per-session working-directory
    template, and a socket/resource leak in an optional external-program
    bridge when the external program never actually connects.
  • Fixed two real gaps in background daemon threads: one missing the
    same start/stop safeguard every sibling thread in its package already
    had, another that could turn into a tight busy-loop under a
    misconfigured setting.
  • Fixed an N+1 database query pattern in an unauthenticated,
    peer-reachable status responder.
  • Closed two credential-handling gaps in maintenance tooling: a
    diagnostic script printing a live secret to its own output, and a
    migration report (which intentionally contains one-time plaintext
    credentials, by design, for the sysop to relay) being created
    world-readable instead of locked down at birth — plus a matching
    fix in the install/update scripts, where a generated system
    configuration fragment briefly sat world-readable before its final
    permission lockdown.
  • Corrected several stale documentation pages and added two missing
    ones (a maintenance-tools section, and a dedicated wiki-feature page
    that never existed despite the feature being referenced elsewhere),
    and completed a real-name sweep of the historical beta changelog that
    a prior pass had deliberately deferred.

New regression tests were added throughout — every fix in this pass
has one, verified against the pre-fix code before being counted as
done.

v1.0.71 — Fifth security/performance audit pass, web and terminal (September 2026)

A fifth audit pass was carried out, focused specifically on the web
interface and the terminal (telnet/SSH/rlogin) client this time, using
the same severity-tiered approach as the four prior rounds (v1.0.38,
v1.0.39, v1.0.48, v1.0.66). As with those rounds, this entry
intentionally omits vulnerability specifics in the interest of
responsible disclosure; sysops running an older release should update
at their earliest convenience. This was the broadest single pass yet —
around 27 real, independently-verified findings, every one with a
dedicated regression test, including a second independent verification
pass over the highest-stakes fixes after the main sweep. In summary,
this pass:

  • Closed several real access-control gaps, including a case where one
    user's live, in-progress door-game session could be manipulated by
    another logged-in user, a case where private mail was reachable
    through an unauthenticated public export path, and a case where a
    downstream network node could receive content scoped to a different
    hub identity than its own.
  • Closed a recurring class of gap, found and fixed independently
    across roughly eight different subsystems (terminal chat, message
    composition and display, an internal network bridge, file/game-data
    import, and more), where remotely- or peer-supplied text could
    manipulate a caller's own terminal display in ways it shouldn't be
    able to.
  • Closed a stored cross-site-scripting gap in a self-published content
    feature, and hardened file-upload integrity checking against a
    resource-exhaustion technique.
  • Fixed two unauthenticated-connection resource-exhaustion gaps in the
    terminal server layer.
  • Extended an existing self-protection guard (an admin action that
    already refused to let a sysop lock themselves out via the web
    panel) to the equivalent terminal-side admin screen, which was
    missing it.
  • Fixed several real correctness bugs found along the way: a broken
    constructor call that silently killed a welcome-message feature and
    a bulk-messaging feature, a command-parsing bug in the sysop
    console, a menu dispatch path that could end a caller's whole
    session on one bad navigation, a resource-cleanup gap that left
    files accumulating on disk indefinitely in two unrelated features,
    and a separate gap where a hung external process spawned by a
    configurable feature wasn't being fully terminated on timeout.
  • Removed a small amount of confirmed-dead code and corrected several
    stale documentation pages (outdated version references, missing
    coverage of recently-added features, and a couple of long-standing
    example/placeholder values that named a real person rather than a
    generic example).

New regression tests were added throughout — every fix in this pass
has one, verified against the pre-fix code before being counted as
done. A few lower-priority items were deliberately left as open
questions for a sysop's own judgment call rather than unilaterally
changed; see docs/SECURITY.md for the categories covered.

v1.0.70 — MRC ghost-session fix, web session monitor (September 2026)

Fixed a bug where an MRC chat session could keep showing as connected
indefinitely after the MRC bridge process restarted, even though nobody
was actually there — the bridge persists its session state to disk and
was reloading it unconditionally on every startup, including sessions
left over from a previous process life with no live connection behind
them anymore. The bridge now discards any leftover session state right
after starting, and every place that reports "who's here" to the
upstream hub (the keepalive loop, periodic userlist/stat refreshes,
room-membership checks) now cross-checks against actually-live
connections rather than trusting the persisted list alone.

Added a new admin monitor for web sessions, alongside the existing
terminal node monitor: the "Web + terminal users" panel on Admin →
Control now includes a Kick action for web sessions. Unlike a terminal
session, a web session has no live server-side connection to close
immediately — the kick takes effect on that session's next page
request, with a message explaining that they were disconnected by the
sysop. A "Live Monitor" shortcut was also added to Admin → Users for
quick access to this panel.

v1.0.69 — Classic "scan for new messages?" login preference (September 2026)

Added the classic BBS login-time new-message scan to the terminal (telnet/SSH/rlogin) client, as a new per-user preference:

  • New profile setting, "Scan for new messages at login" (terminal: Edit Profile; web: Profile → Terminal Capabilities), with three modes:
  • Ask each login (the stock default) — prompts Scan for new messages? [Y/n]: right after logon-module screens, before the main menu. Pressing Enter (or Y) proceeds; N skips it silently for that session.
  • Always scan automatically — shows the summary every login with no prompt.
  • Never scan — skips it entirely, restoring the exact behavior of every version before this one.
  • What gets scanned is unread items addressed to you: private messages, inter-BBS instant messages, and notifications (board replies/mentions, echomail replies, netmail, achievements) — the same summary the terminal already showed unconditionally on every login as of a recent release, now gated behind this preference instead of always appearing. It does not scan for general new activity in boards/echomail areas you haven't been replied to in — the web UI already covers that separately via its own always-on unread badges.
  • New: when something is actually found (whether via "ask" + yes, or "auto"), the terminal now offers a one-key shortcut straight into the relevant reader — [P]rivate Messages, [B]oards, and/or [E]chomail, only listing whichever of those actually has something new — instead of just showing the list and dropping the caller back at the main menu with no way to act on it.
  • ANSI/ASCII terminal sessions only. PETSCII sessions still see the notification summary itself, but not the new jump-in shortcut menu, since PETSCII's own dedicated menu system doesn't share the ANSI-native reader screens this reuses.
  • The preference only affects the terminal — the web UI has no equivalent prompt, since its own always-visible nav-bar badges (PM/IM/notification bell) already serve the same purpose there without needing a login-time interruption.

v1.0.68 — Door Games menu fixes (September 2026)

Fixed a cosmetic bug in the terminal Door Games menu where category section lines (e.g. "Puzzle / Casino") showed a literal ? in place of a small arrow separator before the door count — a non-CP437-safe character that got mangled on the way to the terminal. Replaced with a plain ASCII arrow that renders correctly everywhere. Also added a screen clear before each Door Games menu/submenu redraw, so a menu shorter than a full screen no longer leaves the previous menu's leftover content stacked above it.

v1.0.67 — Follow-up from the fourth audit pass, plus a CI-only test fix (September 2026)

Follows up on three items from the v1.0.66 audit pass that were deliberately left open pending a product decision rather than being fixed on the spot:

  • The web IRC client's SASL EXTERNAL (TLS client-certificate) support was already fully implemented at the connection layer but had no way to actually reach it — no UI, no way to supply a certificate. It's now wired up end-to-end: a sysop-facing toggle in the web IRC client lets a user paste in certificate/key PEM text, which the server writes to a fresh, server-named, permission-locked temporary location for the duration of that one connection and removes on every disconnect path. The client never supplies a server-side file path — only the certificate content itself — so this can't be used to reference or probe any file already on the server.
  • Closed a low-severity anonymous resource-exhaustion gap in inbound FidoNet file-request (FREQ) handling: a fully unauthenticated connection could queue an unbounded number of file-request entries with no realistic way for them to ever be delivered, since outbound delivery only ever happens to a real, already-configured node. Now rate-limited per source address and globally, matching the same bounding approach already used for other unauthenticated network responders in this codebase.
  • A small number of historical changelog and documentation entries referenced the sysop by name; these have been reworded to be name-neutral, matching the rest of the project's documentation.

Also fixed a CI-only test failure (caught in an actual GitHub Actions run, not reproducible locally): a regression test added in v1.0.66 relied on a module-level constant in the ANetCraft door game that was computed once at import time, so redirecting it for the test didn't fully redirect where multiplayer save data actually got written — it silently succeeded locally (against a directory that happened to already exist) and failed outright against a fresh CI checkout. Fixed by removing the constant in favor of a small function that always re-derives the save path, closing the whole bug class rather than just working around it in the test.

v1.0.66 — Fourth security/performance audit pass, plus correctness fixes and documentation cleanup (September 2026)

A fourth broad audit pass was carried out across the entire codebase — every service, every protocol handler, and the documentation/wiki — using the same severity-tiered approach as the three prior rounds (v1.0.38, v1.0.39, v1.0.58). As with those rounds, this entry intentionally omits vulnerability specifics in the interest of responsible disclosure; sysops running an older release should update at their earliest convenience. In summary, this pass:

  • Closed several real gaps where a user-facing feature had no meaningful boundary check at all, including an outbound dial-out feature that could be pointed at internal infrastructure, and a case where banning or locking a user account had no effect on that user's already-connected terminal session.
  • Fixed a case where a bulk network-fetch feature validated a destination once but then reconnected to it independently, reopening a timing gap the validation was meant to close.
  • Closed a handful of smaller gaps in inbound network-protocol handling (FidoNet file distribution, echomail/netmail composition) where untrusted peer-supplied data wasn't fully constrained before being trusted or relayed further.
  • Fixed several real correctness bugs found along the way: a broken menu link that could end a user's entire session instead of just failing that one navigation; a sysop-configurable setting that had no effect despite the admin UI showing it as active; a background task that could lose in-flight output under load; and a background delivery mechanism that was silently failing to record its own results.
  • Removed a small amount of confirmed-dead code (superseded implementations with zero remaining callers) and closed several minor consistency/hardening gaps that weren't proven exploitable today but were worth tightening anyway.
  • Corrected several inaccuracies in the documentation (an out-of-date architecture diagram, a stale claim about a security default, a couple of file-path references) and filled in a few real, previously-undocumented gaps (a user-migration tool, several configuration options, and the wiki feature itself never having its own entry in the doc index).

New regression tests were added throughout — every fix in this pass has one, verified against the pre-fix code before being counted as done.

v1.0.65 — Fixed a CI-flaky output-truncation race (September 2026)

Fixed a timing race (caught via an intermittent CI failure on a busier build server, not a live report) that could truncate or drop the last bit of output from a custom menu item's "run an external program" action: the moment the child process exited, its output-forwarding task was cancelled immediately, with no guarantee the last already-buffered chunk had actually been read and sent to the caller yet. Now that task gets a short window to finish draining normally before being cancelled.

v1.0.64 — rlogin direct-door goodbye-screen fix (September 2026)

Fixed a live-reported cosmetic bug: a caller who reached a door directly through the rlogin game-server target feature (xtrn=<slug>, added in v1.0.60) saw the sysop's goodbye screen and the plain "Goodbye!" text right before the connection hung up on exit. A game-server-style connection like this is expected to just hang up silently the moment the door exits — the same behavior a real Synchronet rlogin game-server target has — so the goodbye screen is now skipped for this specific connection type only; every other logoff path (normal menu logoff, idle timeout, dropped carrier) is unaffected.