Skip to content

Latest commit

 

History

History
2347 lines (1708 loc) · 93.8 KB

File metadata and controls

2347 lines (1708 loc) · 93.8 KB

Hollo changelog

Version 0.10.0

To be released.

Version 0.9.2

Released on May 25, 2026.

  • Fixed a bug where the media proxy returned 404 Not Found for remote media whose upstream server labeled the payload as application/octet-stream or binary/octet-stream even though the bytes were valid image, video, or audio data. The proxy now sniffs magic bytes to recover the real MIME type in these cases. [#498]

Version 0.9.1

Released on May 21, 2026.

  • Upgraded Fedify to 2.2.3 to fix a security vulnerability in Linked Data Signature verification that could allow certain signed activities to be interpreted differently than intended. [CVE-2026-42462]

Version 0.9.0

Released on May 20, 2026.

  • Upgraded Drizzle ORM to 1.0.0-rc.2 and migrated Hollo's relational query definitions to the new relations API. This has no intended user-facing behavior changes, but the first migration after upgrading may need one extra database permission check. Drizzle 1 upgrades its own migration log table, drizzle.__drizzle_migrations, by adding name and applied_at columns. PostgreSQL only allows that ALTER TABLE when the migration is run by the table owner.

    If pnpm run migrate fails with must be owner of table __drizzle_migrations, first check which role owns Drizzle's migration log table:

    SELECT
      n.nspname AS schema,
      c.relname AS table_name,
      pg_get_userbyid(c.relowner) AS owner
    FROM pg_class c
    JOIN pg_namespace n ON n.oid = c.relnamespace
    WHERE n.nspname = 'drizzle'
      AND c.relname = '__drizzle_migrations';

    If the owner is not the same role Hollo uses in DATABASE_URL, run the following SQL as the current table owner or a database admin, replacing hollo with your Hollo database user:

    ALTER SCHEMA drizzle OWNER TO hollo;
    ALTER TABLE drizzle.__drizzle_migrations OWNER TO hollo;
    ALTER SEQUENCE IF EXISTS drizzle.__drizzle_migrations_id_seq
      OWNER TO hollo;

    Then run pnpm run migrate again with Hollo's normal DATABASE_URL. If your database provider does not allow ownership transfers, run this one migration once with the database role that already owns drizzle.__drizzle_migrations.

  • Cancel running PostgreSQL queries when the corresponding GET or HEAD request is aborted, such as when a client disconnects or quickly switches away from a timeline column. Hollo now tracks the underlying postgres.js query handles used by Drizzle and calls PostgreSQL cancellation for in-flight queries tied to the aborted read-only request. This reduces wasted database work and helps keep the connection pool available under repeated client-side aborts. The existing statement_timeout recommendation remains useful as a backstop for queries that cannot be tied to a safe HTTP request.

  • Added passkey (WebAuthn) authentication. The admin Auth page now has a “Passkeys” section for enrolling and managing passkeys, and the public login page presents a “Sign in with passkey” button (with the email/password form tucked behind a toggle) whenever at least one passkey is enrolled. Both device-bound and synced (multi-device) passkeys are accepted. A passkey on its own counts as multi-factor authentication, so a successful passkey sign-in is accepted in place of the TOTP step — the user is not asked for a one-time code in the same session.

    Hollo uses the @simplewebauthn/server library for verification and ships the matching browser helper as a static asset linked only from the auth and login pages. Registration uses residentKey: required and userVerification: required, so every enrolled passkey is discoverable and tied to a biometric or PIN gesture. Registration challenges are bound to the current login session with a server-enforced 5-minute TTL, and login challenges are stored in a single-use passkey_login_challenges table so a captured cookie + assertion pair can be redeemed at most once. [#487]

  • Added optional split-domain WebFinger support. When the new HANDLE_HOST and WEB_ORIGIN environment variables are set, Hollo uses Fedify's origin configuration so that fediverse handles (e.g. @alice@example.com) and ActivityPub actor URIs (e.g. https://ap.example.com/@alice) can live on different domains. The Mastodon-compatible /api/v1/instance and /api/v2/instance endpoints expose HANDLE_HOST as the instance domain when this is configured, so clients display the correct @user@HANDLE_HOST handle. Both variables must be set together; setting only one is a startup error. They must be configured before the first account is created — changing the handle domain after federation has begun breaks remote follow relationships; on startup Hollo logs a warning when the configured HANDLE_HOST does not match the existing account's stored handle. Operators must also configure their reverse proxy on the handle domain to redirect /.well-known/webfinger to WEB_ORIGIN. See the Split-domain WebFinger guide. [#161, #484]

  • Added a media proxy that re-serves remote avatars, headers, post attachments, custom emojis, and preview-card images from Hollo's own origin. This sidesteps CORS configurations on remote object stores and prevents the visitor's browser from talking directly to the source server. Controlled by a new MEDIA_PROXY environment variable with three levels: [#481, #483, #493]

    • off (default): the Mastodon API and web UI hand the original remote URL to clients, matching the historical behaviour.
    • proxy: every remote media URL is rewritten to a signed /proxy/<sig>/<b64url> path served by Hollo itself. The proxy runs SSRF checks on the upstream URL and on every redirect target, allows only image/video/audio Content-Types (image/svg+xml is explicitly blocked to avoid same-origin XSS), caps the body at 32 MiB, and serves the response with Cache-Control: public, max-age=2592000, immutable and X-Content-Type-Options: nosniff. No on-disk cache.
    • cache: same URL rewriting, but the streamed body is persisted to the configured storage backend as proxy/<sha256>.bin, with a content-type sidecar alongside it at proxy/<sha256>.json. Subsequent requests skip the upstream fetch. Remote actor avatars for accounts with an approved follow relationship to the local account are also prefetched into this same cache when the actor is stored or refreshed, so stale upstream avatar files can keep rendering after Hollo has seen them once. The admin dashboard at /thumbnail_cleanup can purge the cache on demand.

    MEDIA_PROXY also accepts the Boolean synonyms true/on/1 (as aliases for proxy) and false/off/0 (as aliases for off). Disk caching is opt-in only via the explicit cache value.

    Outbound federation is unaffected: Hollo still publishes the original remote URLs in ActivityPub icon, image, attachment, and emoji Tag references.

  • Added a REMOTE_MEDIA_THUMBNAILS environment variable that controls whether Hollo downloads incoming remote attachments to generate a local WebP thumbnail. Set to off to skip the upstream fetch and Sharp pipeline entirely, storing the remote URL itself as the thumbnail URL—useful in combination with MEDIA_PROXY=proxy or cache to free up the disk space the local thumbnails would otherwise occupy. Defaults to on (the historical behavior). [#481, #483]

  • Added FEP-044f quote authorization and policy support on top of the Mastodon-compatible quote APIs. [#457, #459, #460]

    • Added persistent quote states for pending, accepted, rejected, revoked, and unauthorized quotes, plus quote target and authorization IRIs for federation.
    • Hollo now enforces quote policy, quote target visibility, block relationships, follower-only quote permissions, and direct-message mention requirements when creating a quote through POST /api/v1/statuses. Remote public posts without an advertised FEP-044f quote policy are treated as legacy quote targets and can be quoted without waiting for quote authorization.
    • Implemented quote_approval_policy handling on status creation and editing, and added PUT /api/v1/statuses/:id/interaction_policy for updating a status' quote policy after publication.
    • quotes_count now includes only accepted quotes and is updated when quotes are accepted, rejected, revoked, created, deleted, or received through federation.
    • GET /api/v1/statuses/:id/quotes now lists only accepted quotes, and quote revocation keeps quote target metadata while removing the quote from accepted quote lists and counts.
    • Published outbound FEP-044f quote, quoteAuthorization, and interactionPolicy.canQuote properties on ActivityPub objects, while keeping the legacy quoteUrl property for compatibility.
    • Parsed inbound FEP-044f quote targets and quote approval policies from remote objects, including support for the legacy quoteUrl property.
    • Added federation handling for QuoteRequest, Accept(QuoteRequest), Reject(QuoteRequest), and Delete(QuoteAuthorization), allowing Hollo to request quote authorization from remote servers, accept or reject incoming quote requests, and revoke quotes when a remote quote authorization is deleted.
    • Added dereferenceable local QuoteAuthorization ActivityPub objects for accepted quotes.
  • Added custom field editing to the admin account creation and editing forms, allowing up to 10 label–value pairs per profile (beyond Mastodon's limit of 4). Field values support Markdown and mention syntax. The Mastodon-compatible PATCH /api/v1/accounts/ update_credentials endpoint now also accepts up to 10 custom fields via fields_attributes[0] through fields_attributes[9].

  • Added LOG_FILE_FORMAT environment variable to control the format of the log file set by LOG_FILE. Valid values are jsonl (the default, JSON Lines format) and logfmt (logfmt format).

  • Fixed preview card generation for remote posts whose content only links to mentioned accounts. Hollo now excludes ActivityPub Mention targets from remote preview-card link detection even when the source server, such as NodeBB, emits plain profile links in the post HTML instead of links marked with a mention class.

  • Fixed a bug in PATCH /api/v1/accounts/update_credentials where submitting any credential update (e.g. display_name) without fields_attributes would silently wipe all existing custom profile fields from the public profile, API responses, and federation output.

  • Added an ActivityPub quote-inline fallback to the content of explicit quote posts created through the Mastodon API. Software that does not support quote posts can now still show the quoted post permalink, while quote-aware software can hide the fallback paragraph by class name.

  • Hid incoming quote-inline fallback paragraphs from Mastodon API status content and profile pages when Hollo can render the structured quoted post. If the quoted post is unavailable, the fallback link remains visible so the quoted URL is not lost.

  • Posts on the public profile and hashtag pages now render Open Graph link previews—a thumbnail (when og:image is set), the host name, the page title, and a short description—for each post that has a stored preview_card. Posts with attached media or shown as quoted posts hide the preview to avoid visual clutter. [#458]

  • Refreshed the entire server-rendered front-end. Hollo replaces Pico CSS with a new design system documented in DESIGN.md and styled through UnoCSS (Wind4, Icons, Typography, and Web Fonts presets). [#458]

    • The design language is achromatic by default; each account owner's theme color tints the profile, post, hashtag, and owner-specific dashboard pages through --theme-50 through --theme-950 CSS variables injected on <html>.
    • Web Fonts are loaded from bunny.net: Inter for Latin, Noto Sans KR/JP/SC for CJK, and JetBrains Mono for code. Lucide icons replace ad-hoc iconography.
    • Every public and dashboard page was rebuilt: login, setup, OTP, the public home, account profiles, single post permalinks, the hashtag stream, the account list and editor, custom emojis, federation, thumbnail cleanup, the OAuth consent screen, and the dashboard auth (2FA) panel.
    • Posts render their bodies as prose markdown with brand-colored links, attached media as a two-column grid, polls as brand-tinted bars, quoted posts as an inset card, and link previews as a media-object card. The single-post permalink page additionally enlarges the focal post.
    • Forms share a small set of primitives (Field, TextField, TextareaField, SelectField, CheckboxField, FieldSection, and SubmitButton) that the auth, account, emoji, federation, thumbnail cleanup, and migrate forms all use. The theme color picker on the account form is a 20-swatch grid; the username field is bracketed by @ and @host chips so the resulting fediverse handle is obvious.
    • Dark mode follows prefers-color-scheme: dark automatically, with primary buttons stepping from brand-600 to brand-700 so they don't dominate dark surfaces. Text selection adopts the active brand color.
    • Hollo's logos are self-hosted from /public/ instead of being fetched from jsDelivr. The 22 Pico-generated *.min.css files are removed; UnoCSS emits a single src/public/uno.css whose URL is cache-busted by file mtime.
  • Added public Followers and Following pages on profile screens, with pagination (100 entries per page) and a substring search filter over display name and handle. The followers list is always public. The following list is gated by a new per-account setting, Make following list public (off by default); when off, the page returns 404 Not Found, the corresponding ActivityPub following collection is hidden from federation, and the Mastodon-compatible GET /api/v1/accounts/:id/following endpoint returns an empty array. The toggle also round-trips through PATCH update_credentials as hide_collections. [#491]

  • Added public reaction list pages anchored to each local post: /@:handle/:id/likes lists the accounts that liked the post, /@:handle/:id/shares lists the accounts that boosted it, /@:handle/:id/reactions/:emoji lists the accounts that reacted with a specific emoji, and /@:handle/:id/quotes lists the posts that quote it. Each page features the original post above the list. On the profile feed and post permalink page, the per-post like, share, quote, and reaction-emoji indicators now link into these pages for local posts; remote posts continue to display the counts as plain text. [#490]

  • Added avatar and header image upload to the admin account creation and editing forms, with drag-and-drop support and in-page image preview. Files are stored using the same storage backend as the Mastodon-compatible API (PATCH /api/v1/accounts/update_credentials).

  • Search queries on account handles, names, and post content now use PostgreSQL trigram indexes via the pg_trgm extension, improving ILIKE search performance. The pg_trgm extension is enabled automatically when the migration is applied.

  • Fixed a performance bug on the account edit page where saving an account always triggered a network lookup of @hollo@hollo.social regardless of whether the “Receive Hollo news” setting had actually changed. The lookup now only happens when the news-following state genuinely changes.

  • Improved the performance of authenticated API requests by replacing the complex multi-table JOIN query in the tokenRequired middleware with a lightweight single-table lookup. Account owner data is now fetched on demand only by routes that actually need it, and requests that fail scope validation no longer touch the accounts table at all. [#127, #467]

  • Fixed a bug where incoming ActivityPub posts with timestamps more than 12 hours in the future were accepted and stuck to the top of the federated timeline, enabling timeline manipulation via forged timestamps. Such posts are now silently ignored. [#67, #466]

  • Fixed a crash when persisting ActivityPub posts with a published date before the Unix epoch (January 1, 1970), which caused uuidv7() to receive a negative timestamp. [#67, #466]

  • Fixed min_id handling on GET /api/v1/timelines/public, GET /api/v1/timelines/home, GET /api/v1/timelines/list/:list_id, and GET /api/v1/timelines/tag/:hashtag to follow Mastodon's pagination semantics: min_id now returns the posts immediately newer than the cursor (rather than the most recent posts above it), so gap-loading clients such as SubwayTooter can converge on arbitrarily large gaps. since_id is now honoured on these endpoints as well, and min_id takes precedence when both are supplied. Timeline responses also include a rel="prev" entry in the Link header alongside the existing rel="next" entry, and keep rel="next" even when a bounded gap page returns fewer statuses than the requested limit, so clients no longer have to guess which cursor parameter to use or stop walking partial gaps. [#479, #482, #492]

  • Optimized Mastodon-compatible timeline loading after the Drizzle ORM upgrade. Home, list, public, and hashtag timelines now use a smaller relation graph that avoids fetching columns and nested relations that are not needed for timeline status serialization. They also fetch matching post IDs first, then hydrate only those posts with the timeline status projection, so empty cursor checks and heavily filtered timelines avoid running the relation-heavy query at all. The ID selection and hydration run in the same read-only repeatable-read snapshot, preserving timeline eligibility consistency while reducing the size and cost of the SQL generated for large timelines, especially list timelines on instances with many stored posts, without changing the API response format. Timeline limit query parameters are now capped at 1000 to keep these queries bounded even when clients request unusually large pages.

  • Fixed a performance bug that caused profile page queries to take hundreds of seconds on a cold PostgreSQL buffer cache and trigger a thundering herd that exhausted the connection pool. Two root causes: [#489]

    • posts.actor_id had no composite index with published, so timeline queries that ORDER BY published DESC performed a full sort of all matching rows. A B-tree index on (actor_id, published) is now created by migration.
    • Every API response that fetches a list of posts used a lateral join to eagerly load all direct replies for each post, even though only the denormalized replies_count counter is actually used in the Mastodon API serialization. The lateral join is removed from all list-context queries (getPostRelations, timelines, notifications, outbox, etc.). The ActivityPub object serializer now also uses replies_count for the replies collection totalItems instead of reloading every reply. Single-post views (the public post permalink page) still fetch replies but are now capped at 20 per request.
  • Fixed a performance bug where the NodeInfo endpoint performed a sequential scan of the entire posts table on every request because posts.updated had no index. On large instances (e.g. 4 M rows / 13 GB) this took 15–20 seconds per query; since NodeInfo is polled frequently (Caddy health checks, remote servers), the slow queries piled up and could exhaust the connection pool. A B-tree index on posts.updated is now created by migration. [#488]

  • Further optimized the NodeInfo endpoint with three changes that together reduce a previously 42-second query to a handful of milliseconds:

    • Rewrote the activeMonth and activeHalfyear queries from a RIGHT JOIN + countDistinct (full scan of all posts) to an EXISTS semi-join that performs at most one index lookup per local account owner.
    • Added a composite B-tree index on (actor_id, updated) to support the EXISTS subquery without heap fetches.
    • Added a 5-minute in-process TTL cache on the NodeInfo dispatcher so repeated polls by external directories and health checkers no longer hit the database at all.
  • Optimized the GET /api/v2/instance endpoint. The languages field was previously computed by a full scan of the posts table on every request. A new partial composite index posts_actor_id_language_index on (actor_id, language) WHERE language IS NOT NULL turns this into an Index-Only Scan, and a 5-minute in-process response cache absorbs repeated calls so the database is queried at most once per 5 minutes.

  • Improved hashtag timeline and featured tag performance by adding a GIN index on posts.tags. All ? and ?| operator lookups on the tags column (hashtag timeline, featured tag counts, profile hashtag filters, and tag pages) previously caused a full sequential scan of the 4 M+ row posts table, taking several seconds even on a warm cache. The new index cuts these to index lookups.

  • The TIMELINE_INBOXES feature flag, introduced in Hollo 0.4.0, now defaults to true. Set it to false explicitly to opt out. The flag will be removed entirely in Hollo 1.0.0, when timeline inbox mode will be the only supported behavior.

  • Upgraded Fedify to 2.2.2.

  • Added Traditional Chinese (繁體中文; zh-TW) documentation.

Version 0.8.6

Released on May 21, 2026.

  • Upgraded Fedify to 2.1.14 to fix a security vulnerability in Linked Data Signature verification that could allow certain signed activities to be interpreted differently than intended. [CVE-2026-42462]

Version 0.8.5

Released on May 19, 2026.

  • Fixed a security vulnerability where any federated actor could send a Delete activity to remove cached remote posts authored by any other actor, because the inbox handler matched only on the post IRI without verifying the deleter's identity. Delete activities are now ignored unless the actor's origin matches the post author's origin.

  • Fixed a security vulnerability where an Update activity could overwrite or first-materialize a remote post under another instance's authority. The inbox handler now refuses an Update whose actor origin does not match the embedded object's id origin.

  • Fixed a security vulnerability where an Announce activity from a different origin than the announced object could first-materialize a cached post from attacker-controlled embedded content, masquerading as another actor's post. Cross-origin announces of previously unknown objects are now re-fetched from the canonical URL before being persisted, and the embedded body is no longer trusted to overwrite a post that is already known locally.

    As a deliberate trade-off, a cross-origin Announce of a previously unknown post is dropped when the canonical origin is unreachable (down, rate-limiting, or rejecting Hollo's signed fetch). Honoring the embedded body in that case would re-introduce the masquerade vector that this change closes—an attacker can always craft an embedded object whose id and attributedTo agree on a victim origin, so the only safe source for the canonical content is the canonical origin itself. In practice this affects relay-mediated boosts and cross-instance reposts when the source instance is temporarily offline; locally cached posts and same-origin announces are unaffected.

  • The login and OTP session cookies are now set with HttpOnly, SameSite=Lax, and (over HTTPS) Secure. Previously these cookies were set without explicit attributes, so a single reflected XSS could exfiltrate the session and cross-site POSTs could forge admin actions.

  • Hono's CSRF middleware is now applied to every cookie-authenticated web route (/login, /login/otp, /logout, /setup, /auth, /accounts, /emojis, /federation) and to POST /oauth/authorize. Without this, a malicious page could submit a hidden cross-site form to trigger state-changing actions (disable 2FA, delete an account, silently authorize an OAuth app, etc.) on behalf of a logged-in admin. /oauth/token, /oauth/revoke, /oauth/userinfo, and the /api/* namespace continue to authenticate with client credentials or bearer tokens and are intentionally not affected.

  • The application error handler now returns the response carried by HTTPException instead of rethrowing it as a generic 500. Without this, middleware that signals refusal by throwing HTTPException(403, …) (the new CSRF middleware, among others) would have surfaced as opaque 500 responses to clients.

  • Incoming Follow, Like, EmojiReact, and Announce activities from a blocked actor are now silently dropped. Previously a block only flipped auto-approval on incoming follow requests and did nothing for protected accounts, likes, reactions, or announcements—a blocker still saw notifications and timeline entries from the actor they had blocked.

  • Pinned the transitive fast-xml-parser dependency (carried in via the AWS SDK that backs S3 storage) using pnpm.overrides. v4 consumers now resolve to ^4.5.5 (fixing the critical entity- encoding bypass and several high-severity parser issues) and v5 consumers resolve to ^5.7.0. Each AWS SDK is kept on its expected major version to preserve API compatibility; the single remaining “XMLBuilder unescaped delimiter” moderate advisory is only patched on v5.7.0+ and is not addressed here because forcing AWS SDK v4 consumers onto fast-xml-parser v5 would risk runtime regressions on S3 deployments.

  • Hollo now warns at startup whenever LOG_QUERY=true is set. The flag causes drizzle-orm to emit every SQL query together with its bound parameter values, which include OAuth access tokens (stored plain in the database), authorization codes, and other secrets; leaving it enabled in production exposes those secrets to anyone with read access to the application logs (or to a downstream collector such as Sentry or a file sink).

  • The OAuth PKCE code-challenge check and the OAuth multi-credential client-secret consistency check are now compared in constant time using crypto.timingSafeEqual. (The primary client-secret authentication path runs as a Postgres equality predicate and is unchanged.) The PKCE comparison is between two SHA-256 hashes (low practical timing-attack risk) and the multi-credential consistency check only fires when a client presents the same credentials via more than one mechanism, so neither was a confirmed exploitation primitive, but constant-time comparison is the correct defence-in-depth posture for any user-space operation on a secret.

Version 0.8.4

Released on May 14, 2026.

  • Fixed a bug where boosting a quote post would incorrectly copy the quote_id to the outer boost wrapper status, causing clients like SubwayTooter to fail to display the quoted post correctly. The quote_id and quote fields now only appear inside the inner reblog object. [#480]

  • Fixed a bug where no logs were output when running as a worker node (NODE_TYPE=worker). The logging system was only initialized when the web server started, so worker-only processes ran silently regardless of the LOG_LEVEL setting. [#478]

Version 0.8.3

Released on May 10, 2026.

  • Upgraded Fedify to 2.1.12 to fix a critical SSRF (Server-Side Request Forgery) vulnerability where private IPv4 addresses encoded as IPv6 literals could bypass security checks during remote ActivityPub object fetching.

Version 0.8.2

Released on May 5, 2026.

  • Fixed a security vulnerability where the hashtag follow/unfollow API endpoints were missing an ownership filter, allowing a single authenticated request to modify followed tags for all account owners in the database. [#429 by tomaioo]

Version 0.8.1

Released on April 27, 2026.

  • Fixed thumbnail cleanup preview counts over 999 being truncated after the localized count was passed through the redirect URL. The preview now keeps the raw count in the URL and formats it only when rendering. [#451]

Version 0.8.0

Released on April 27, 2026.

  • Added support for separating worker nodes from the web server for better scalability in high-traffic scenarios. This allows running web server and background workers (Fedify message queue and import worker) in separate processes, preventing heavy federation workloads from slowing down web server responsiveness. This is particularly beneficial for instances with thousands of followers where a single post can generate thousands of outbox messages. [#350]

    • Added NODE_TYPE environment variable to control which components run in each process: all (default, current behavior), web (web server only), or worker (workers only).
    • All nodes share the same PostgreSQL database, which acts as the message queue backend using LISTEN/NOTIFY for real-time message delivery.
    • Added comprehensive documentation for Docker Compose, systemd, and manual deployment setups with worker separation.
    • Added pnpm worker script for running worker-only nodes.
  • Reduced idle memory usage by lazy-loading several heavy dependencies and startup-only code paths based on actual memory measurements. This lowers the baseline footprint of NODE_TYPE=all, web, and worker deployments, especially on single-user instances with filesystem storage. [#435]

    • Markdown formatting now loads Shiki only when rich text formatting is actually needed, instead of at server startup.
    • Filesystem deployments no longer pull S3-specific storage code into the initial web server startup path.
    • The web server and worker process now import each other's code paths only when the selected NODE_TYPE needs them.
    • Preview card scraping, media processing, and authentication helpers now load on demand instead of eagerly during route registration.
  • Added a production build step powered by tsdown, and changed pnpm prod and pnpm worker to run the compiled JavaScript output with Node.js instead of running TypeScript through tsx. Docker images now build these JavaScript files in a builder stage and include them in the runtime image. [#357]

  • Moved remote replies scraping from synchronous post ingestion to a rate-limited background worker. Remote posts now enqueue reply collection scraping jobs instead of fetching nested replies inline, which prevents slow or very large remote reply collections from delaying federation processing. [#445, #447]

    • Added per-origin throttling and 429 Too Many Requests backoff for remote replies scraping.
    • Added bounded scraping controls: REMOTE_REPLIES_SCRAPE_DEPTH, REMOTE_REPLIES_SCRAPE_MAX_ITEMS, REMOTE_REPLIES_SCRAPE_INTERVAL_SECONDS, REMOTE_REPLIES_SCRAPE_BACKOFF_SECONDS, and REMOTE_REPLIES_SCRAPE_COOLDOWN_SECONDS.
  • Added automatic refresh of stale remote actor profiles. When receiving activities like Announce or Create(Note), Hollo now checks if the actor's cached data is stale and asynchronously refreshes their profile in the background. This helps keep remote actor information (avatars, display names, etc.) up to date without relying solely on Update activities from remote servers. [#348]

    • Added REMOTE_ACTOR_STALENESS_DAYS environment variable to configure how many days before a remote actor's data is considered stale. Defaults to 7 days.
    • Added REFRESH_ACTORS_ON_INTERACTION environment variable. When set to true, checks for stale actors on all activity types (likes, emoji reactions, follows, etc.). When false (default), only checks on activities that appear in timelines (Announce, Create).
  • Added Mastodon 4.5-compatible quote post APIs. The quote field on Status entities now uses the Mastodon Quote entity format ({ state, quoted_status }) instead of the previous Fedibird-style flat status format. The quote_id field is kept for backward compatibility.

    • Added quoted_status_id parameter to POST /api/v1/statuses as the Mastodon 4.5 way to create quote posts (alongside existing quote_id).
    • Added quotes_count field to Status entities.
    • Added quote_approval field to Status entities indicating whether a post can be quoted.
    • Added GET /api/v1/statuses/:id/quotes endpoint to list quotes of a post with cursor-based pagination.
    • Added POST /api/v1/statuses/:id/quotes/:quoting_status_id/revoke endpoint to let users revoke quotes of their posts.
    • The quote_approval_policy parameter is accepted but ignored (all public/unlisted posts are freely quotable).
  • Added automatic cleanup of unreachable remote actors on permanent delivery failures. When sending activities to followers' inboxes fails permanently, Hollo now cleans up the associated records to avoid retrying delivery to dead servers.

    • On 404 Not Found: removes follower relationships for the failed actor so that future activities are no longer delivered to them. The account record itself is preserved.
    • On 410 Gone: deletes the remote account entirely (along with associated follows, mentions, likes, etc. via cascade) since the actor is explicitly marked as permanently gone.
  • Improved inbox handling for deleted remote actors using Fedify 2.1.0's unverified activity hooks. Hollo now acknowledges unverifiable Delete activities with 202 Accepted when the signing key fetch fails with 410 Gone, preventing repeated delivery retries for actors that have already been permanently deleted.

  • Optimized follower-only status visibility checks by preloading approved follow relationships and reusing simple WHERE IN conditions for status, conversation context, quote, and timeline queries. [#173, #448]

  • Added FEDIFY_DEBUG environment variable to enable the Fedify debugger, an embedded real-time dashboard for inspecting ActivityPub traces and activities. When enabled, the debug dashboard is accessible at /__debug__/. Intended for development use only.

  • Added outbound activity ordering keys for stateful federation actions, using Fedify 2.0's ordered message delivery support. This ensures remote servers process related actions in order, including post create/update/delete, reblog/unreblog, like/unlike, emoji reaction/unreaction, follow request lifecycle messages, block/unblock, and post updates triggered by replies and poll votes.

  • Fixed remote account force refresh and actor refresh getting stuck when a canonical fediverse handle had moved to a new actor IRI while a stale remote account row still claimed the old handle. Hollo now verifies the canonical handle owner via WebFinger, deletes the stale remote account and its dependent data, and then updates or inserts the current actor. When the conflict cannot be verified safely, force refresh now shows an explicit canonical handle conflict error instead of failing with a raw database unique-constraint error. [#424]

  • Added profile-specific tagged post pages at /:handle/tagged/:tag, so users can browse only posts from a given profile that use a particular hashtag. The Mastodon-compatible GET /api/v1/accounts/:id/statuses endpoint now also applies its existing tagged query parameter to filter account timelines by hashtag. [#420]

  • Added an account-level preference for whether content warnings should be expanded by default. The setting is available in the dashboard account editor and is now returned from GET /api/v1/preferences, which helps clients like Phanpy honor each account's preferred CW behavior. [#425]

  • Fixed Mastodon API compatibility for clients such as the official Mastodon iOS app by returning empty arrays for unimplemented trends and suggestions endpoints instead of 404 Not Found responses. The suggestions endpoints still require an authenticated user token. [#421, #427 by Vignesh]

  • Added a new dashboard page for thumbnail cleanup at /thumbnail_cleanup. Thumbnails from remote posts that have not been bookmarked, liked, reacted to, shared nor quoted by a local account before a given cut-off data can be mass-deleted in order to lower storage demand. The original posts are not deleted, neither is the relationship to the original media nor the alt text. [#409, #436 by aliceif]

  • Upgraded Fedify to 2.1.10.

Version 0.7.17

Released on May 21, 2026.

  • Upgraded Fedify to 1.10.10 to fix a security vulnerability in Linked Data Signature verification that could allow certain signed activities to be interpreted differently than intended. [CVE-2026-42462]

Version 0.7.16

Released on May 19, 2026.

  • Fixed a security vulnerability where any federated actor could send a Delete activity to remove cached remote posts authored by any other actor, because the inbox handler matched only on the post IRI without verifying the deleter's identity. Delete activities are now ignored unless the actor's origin matches the post author's origin.

  • Fixed a security vulnerability where an Update activity could overwrite or first-materialize a remote post under another instance's authority. The inbox handler now refuses an Update whose actor origin does not match the embedded object's id origin.

  • Fixed a security vulnerability where an Announce activity from a different origin than the announced object could first-materialize a cached post from attacker-controlled embedded content, masquerading as another actor's post. Cross-origin announces of previously unknown objects are now re-fetched from the canonical URL before being persisted, and the embedded body is no longer trusted to overwrite a post that is already known locally.

    As a deliberate trade-off, a cross-origin Announce of a previously unknown post is dropped when the canonical origin is unreachable (down, rate-limiting, or rejecting Hollo's signed fetch). Honoring the embedded body in that case would re-introduce the masquerade vector that this change closes—an attacker can always craft an embedded object whose id and attributedTo agree on a victim origin, so the only safe source for the canonical content is the canonical origin itself. In practice this affects relay-mediated boosts and cross-instance reposts when the source instance is temporarily offline; locally cached posts and same-origin announces are unaffected.

  • The login and OTP session cookies are now set with HttpOnly, SameSite=Lax, and (over HTTPS) Secure. Previously these cookies were set without explicit attributes, so a single reflected XSS could exfiltrate the session and cross-site POSTs could forge admin actions.

  • Hono's CSRF middleware is now applied to every cookie-authenticated web route (/login, /login/otp, /logout, /setup, /auth, /accounts, /emojis, /federation) and to POST /oauth/authorize. Without this, a malicious page could submit a hidden cross-site form to trigger state-changing actions (disable 2FA, delete an account, silently authorize an OAuth app, etc.) on behalf of a logged-in admin. /oauth/token, /oauth/revoke, /oauth/userinfo, and the /api/* namespace continue to authenticate with client credentials or bearer tokens and are intentionally not affected.

  • The application error handler now returns the response carried by HTTPException instead of rethrowing it as a generic 500. Without this, middleware that signals refusal by throwing HTTPException(403, …) (the new CSRF middleware, among others) would have surfaced as opaque 500 responses to clients.

  • Incoming Follow, Like, EmojiReact, and Announce activities from a blocked actor are now silently dropped. Previously a block only flipped auto-approval on incoming follow requests and did nothing for protected accounts, likes, reactions, or announcements—a blocker still saw notifications and timeline entries from the actor they had blocked.

  • Pinned the transitive fast-xml-parser dependency (carried in via the AWS SDK that backs S3 storage) using pnpm.overrides. v4 consumers now resolve to ^4.5.5 (fixing the critical entity- encoding bypass and several high-severity parser issues) and v5 consumers resolve to ^5.7.0. Each AWS SDK is kept on its expected major version to preserve API compatibility; the single remaining “XMLBuilder unescaped delimiter” moderate advisory is only patched on v5.7.0+ and is not addressed here because forcing AWS SDK v4 consumers onto fast-xml-parser v5 would risk runtime regressions on S3 deployments.

  • Hollo now warns at startup whenever LOG_QUERY=true is set. The flag causes drizzle-orm to emit every SQL query together with its bound parameter values, which include OAuth access tokens (stored plain in the database), authorization codes, and other secrets; leaving it enabled in production exposes those secrets to anyone with read access to the application logs (or to a downstream collector such as Sentry or a file sink).

  • The OAuth PKCE code-challenge check and the OAuth multi-credential client-secret consistency check are now compared in constant time using crypto.timingSafeEqual. (The primary client-secret authentication path runs as a Postgres equality predicate and is unchanged.) The PKCE comparison is between two SHA-256 hashes (low practical timing-attack risk) and the multi-credential consistency check only fires when a client presents the same credentials via more than one mechanism, so neither was a confirmed exploitation primitive, but constant-time comparison is the correct defence-in-depth posture for any user-space operation on a secret.

Version 0.7.15

Released on May 10, 2026.

  • Upgraded Fedify to 1.10.9 to fix a critical SSRF (Server-Side Request Forgery) vulnerability where private IPv4 addresses encoded as IPv6 literals could bypass security checks during remote ActivityPub object fetching.

Version 0.7.14

Released on May 5, 2026.

  • Fixed a security vulnerability where the hashtag follow/unfollow API endpoints were missing an ownership filter, allowing a single authenticated request to modify followed tags for all account owners in the database. [#429 by tomaioo]

Version 0.7.13

Released on April 26, 2026.

  • Fixed a Mastodon API compatibility regression where replies to local posts were stored as status notifications, causing clients to show generic “posted” titles instead of reply notifications. Replies are now stored as mention notifications. [#380]

Version 0.7.12

Released on April 25, 2026.

  • Fixed a federation bug where duplicate Announce activities from the same actor for the same post could fail with a database uniqueness error instead of being treated idempotently. [#443, #444]

Version 0.7.11

Released on April 21, 2026.

  • Fixed a security vulnerability where a public profile's Atom feed could expose followers-only posts and direct messages. The Atom feed now only serves public and unlisted posts. [#440]

Version 0.7.10

Released on April 8, 2026.

  • Upgraded Fedify to 1.10.8 for performance improvements and interoperability fixes.

Version 0.7.9

Released on March 29, 2026.

  • Reduced the risk of long-running PostgreSQL transactions during federation processing. Federation inbox handlers and remote actor post imports no longer wrap remote post/account persistence in explicit transactions, which could otherwise stay open while fetching remote ActivityPub objects, preview cards, and media attachments. This should reduce INSERT waiting pile-ups and improve resilience when remote servers are slow or unresponsive. [#411]

  • Fixed a bug where timeline markers hadn't allowed partial updates. [#412 by Nicole Mikołajczyk]

  • Fixed a Mastodon API compatibility bug where some serialized statuses had emitted null mention URLs or unsupported attachment types, which could break rendering in Moshidon custom lists. Mention URLs now fall back to the account IRI, and unsupported media types are normalized to unknown. [#414]

Version 0.7.8

Released on March 27, 2026.

Version 0.7.7

Released on March 13, 2026.

  • Fixed video thumbnail generation failing for some MP4/MOV files by writing the video data to a temporary file instead of piping it via stdin (pipe:0), which does not support seeking. [#397, #398 by NTSK]

Version 0.7.6

Released on March 11, 2026.

  • Fixed a federation interoperability bug where reactions (Like and EmojiReact) to remote posts could be ignored when the activity object used a remote IRI that did not match Hollo's local URI pattern. Inbox handlers now fall back to resolving posts by posts.iri, so remote self-reactions (e.g., Misskey users reacting to their own remote notes) are persisted and shown correctly in Mastodon-compatible clients. [#394]

  • Hardened inbox reaction processing to tolerate duplicate deliveries by making Like/EmojiReact inserts idempotent, preventing duplicate-key failures during federation retries.

  • Upgraded Fedify to 1.10.4.

Version 0.7.5

Released on March 3, 2026.

  • Fixed a bug where posts from blocked accounts could still appear in timeline inboxes (/api/v1/timelines/home and list timelines) when TIMELINE_INBOXES was enabled. Timeline filtering now consistently excludes blocked accounts, including shared posts and replies related to blocked accounts.

Version 0.7.4

Released on February 24, 2026.

  • Fixed a federation interoperability bug where follow requests to some Bonfire instances could remain pending even after receiving Accept or Reject activities. Inbox follow handlers now fall back to resolving the embedded Follow object (with crossOrigin: "trust") and match by actor when the object ID does not match Hollo's stored follow IRI. [#373]

  • Fixed a bug where the local account's followingCount was not updated when an Accept activity was processed via the fallback path that resolves the embedded Follow object (Path B). The handler was incorrectly passing the accepting actor's account ID to updateAccountStats instead of the local follower's account ID. [#374]

Version 0.7.3

Released on February 23, 2026.

  • Temporarily changed Fedify's firstKnock setting to draft-cavage-http-signatures-12 for outbound inbox deliveries as a compatibility workaround for Bonfire's current signature handling. This is intended to be reverted to Fedify's default RFC 9421-first behavior after the Bonfire fix is released. [bonfire-networks/activity_pub#8]

Version 0.7.2

Released on February 10, 2026.

  • Fixed a security vulnerability where DMs and followers-only posts were exposed through the ActivityPub outbox endpoint without authorization. The outbox now only serves public and unlisted posts. Any unauthenticated request to the outbox could previously retrieve all posts regardless of their visibility setting. [CVE-2026-25808]

Version 0.7.1

Released on February 4, 2026.

  • Fixed emoji reaction notifications not displaying emoji information in Mastodon-compatible clients. The /api/v1/notifications endpoint now includes top-level emoji and emoji_url fields for emoji_reaction notifications, compatible with Pleroma/Akkoma clients like Phanpy. [#358]

Version 0.7.0

Released on January 24, 2026.

  • Implemented advanced search query operators for the /api/v2/search endpoint, enabling Mastodon-compatible search filtering. Supported operators include:

    • has:media / has:poll — Filter by attachments
    • is:reply / is:sensitive — Filter by post characteristics
    • language:xx — Filter by ISO 639-1 language code
    • from:username — Filter by author (supports @user, user@domain)
    • mentions:username — Filter by mentioned user
    • before:YYYY-MM-DD / after:YYYY-MM-DD — Filter by date range
    • Negation with - prefix (e.g., -has:media)
    • OR operator for alternative matches
    • Parentheses for grouping (e.g., (from:alice OR from:bob) has:poll)
  • Significantly improved /api/v1/notifications endpoint performance by implementing a materialized notifications system. The endpoint now uses dedicated notifications and notification_groups tables instead of generating notifications on-demand via complex SQL queries, resulting in approximately 24% improvement (2.5s → 1.9s). Key changes include:

    • Added notifications table to store notification events as they occur during federation activities (follows, likes, mentions, shares, etc).
    • Added notification_groups table for Mastodon-compatible notification grouping and aggregation metadata.
    • Implemented automatic notification creation in federation inbox handlers for all notification types.
    • Backfilled recent notifications (100 per type) during migration to prevent empty notification lists after upgrade.
    • Poll expiry notifications are queried dynamically on-demand since they cannot be pre-generated without background job scheduling.
  • Enabled gzip/deflate compression for all API responses, reducing response sizes by 70–92% and improving overall API performance. For example, /api/v1/notifications responses are now compressed from 767KB to 58KB, /api/v1/timelines/home from 91KB to 14KB, resulting in faster load times and reduced bandwidth usage.

  • Implemented Mastodon v2 grouped notifications API (/api/v2/notifications), which provides server-side notification grouping to reduce client complexity and improve performance. The API groups notifications of types favourite, follow, reblog, admin.sign_up, and emoji_reaction together when they target the same post or account. New endpoints include:

    • GET /api/v2/notifications: Get paginated grouped notifications with deduplicated accounts and statuses
    • GET /api/v2/notifications/:group_key: Get a specific notification group
    • GET /api/v2/notifications/:group_key/accounts: Get all accounts in a notification group
    • POST /api/v2/notifications/:group_key/dismiss: Dismiss a notification group
    • GET /api/v2/notifications/unread_count: Get unread notification count
  • Fixed POST /api/v1/statuses and PUT /api/v1/statuses/:id endpoints rejecting FormData requests. These endpoints now properly accept both JSON and FormData content types, improving compatibility with Mastodon clients that send multipart/form-data requests. [#170, #171 by Emelia Smith]

  • Fixed a bug where multiple JSON objects were written on a single line in log files when LOG_FILE environment variable was set. Upgraded LogTape to 2.0.0 and now uses jsonLinesFormatter to ensure proper JSON Lines format with one JSON object per line. [#174]

  • Fixed POST /api/v1/statuses endpoint rejecting requests with null values in optional fields. The endpoint now properly accepts null values for fields like media_ids, poll, spoiler_text, in_reply_to_id, and other optional parameters, improving compatibility with Mastodon clients. [#177, #179 by Lee ByeongJun]

  • Implemented asynchronous import job processing with a background worker to improve the reliability and performance of account data imports (following accounts, lists, muted/blocked accounts, bookmarks). Large imports no longer block the HTTP request, and users can see real-time progress of their imports. [#94, #295 by Juyoung Jung]

  • Improved instance API responses for better third-party client compatibility. [#296 by Juyoung Jung]

    • GET /api/v1/instance: Added configuration.accounts.max_featured_tags field, thumbnail field with Hollo logo, and implemented actual stats values (user_count, status_count, domain_count) from the database.
    • GET /api/v2/instance: Added thumbnail object with url, blurhash, and versions fields, icon array, and updated max_featured_tags and max_pinned_statuses values from 0 to 10.
  • Fixed OAuth token endpoint rejecting requests from clients that send credentials via both HTTP Basic authentication and request body simultaneously. The endpoint now accepts such requests if the credentials are identical, improving compatibility with clients like tooot. [#296 by Juyoung Jung]

  • Upgraded Fedify to 1.10.0.

  • Added prev link to the Link header in /api/v1/notifications API responses for Mastodon-compatible pagination. This allows clients to efficiently fetch new notifications since the last received notification, improving caching capabilities and reducing server load. [#312]

  • Fixed OAuth token endpoint failing to parse request body when HTTP clients don't send Content-Type header. Some clients like Lobsters' Sponge HTTP client don't set Content-Type for POST requests with form data, causing authentication failures. The endpoint now correctly parses URL-encoded form data even when Content-Type is missing or set to text/plain.

  • Implemented Mastodon 4.5.0 quote notification types (quote and quoted_update) for improved quote post interaction tracking. Users now receive notifications when their posts are quoted by others and when posts they've quoted are edited by the original authors. Key features include:

    • Added quote notification type that triggers when someone quotes your post, with the notification showing the quote post itself.
    • Added quoted_update notification type that triggers when a post you quoted is edited, with the notification showing your quote post to provide context.
    • Both notification types are non-groupable, meaning each quote or edit generates an individual notification for better visibility.
    • Self-quotes (quoting your own posts) do not generate notifications to avoid unnecessary noise.
    • Existing quote posts are automatically backfilled with notifications during migration to ensure consistent notification history.
    • Added database index on posts.quote_target_id for improved query performance when looking up quote relationships.
  • Removed dependency on deprecated fluent-ffmpeg package and now invoke ffmpeg binary directly for video screenshot generation. This change improves reliability by preventing request failures when video screenshot generation encounters errors. On failure, a default screenshot (Hollo logo) is now returned instead of aborting the entire upload request, and ffmpeg error output is logged for debugging. [#333 by Peter Jeschke]

  • Fixed a bug where querying the /api/v1/notifications and /api/v2/notifications endpoints with unknown notification types (e.g., types[]=reaction from clients like Moshidon) resulted in 500 Internal Server Error responses due to database enum validation failures. The endpoints now filter out unknown notification types before passing them to the database layer, returning an empty result instead of an error. [#334 by Peter Jeschke]

  • Fixed a bug where the /api/v2/search endpoint did not properly enforce the limit parameter on search results. The endpoint now correctly limits the number of returned accounts and statuses to the requested limit (default 20, maximum 40), improving Mastodon API compatibility and preventing potential performance issues with large result sets. [#210]

  • Significantly improved /api/v2/search endpoint performance when searching by URL or handle. The endpoint now responds in approximately 1.4 seconds for URL searches, down from 8–10 seconds previously (approximately 85% improvement). Key optimizations include:

    • Skip unnecessary lookupObject calls for non-URL/non-handle queries, reducing remote federation lookups by 2–3 seconds.
    • Skip full-text search on posts.content_html column when the query is a URL and the post is found in cache lookup (by IRI or URL), eliminating expensive table scans that took ~8 seconds.
    • Added shared HANDLE_PATTERN regex in src/patterns.ts for consistent WebFinger handle validation across v1 and v2 APIs.

Version 0.6.20

Released on February 10, 2026.

  • Fixed a security vulnerability where DMs and followers-only posts were exposed through the ActivityPub outbox endpoint without authorization. The outbox now only serves public and unlisted posts. Any unauthenticated request to the outbox could previously retrieve all posts regardless of their visibility setting. [CVE-2026-25808]

Version 0.6.19

Released on December 20, 2025.

  • Upgraded Fedify to 1.6.15 to fix a ReDoS (Regular Expression Denial of Service) vulnerability in Fedify's HTML parsing code. An attacker could exploit this vulnerability to cause denial of service by sending malicious HTML responses during federation operations. [CVE-2025-68475]

Version 0.6.18

Released on November 15, 2025.

  • Reverted the /api/v1/notifications endpoint query optimization from 0.6.17 due to a regression that caused server errors when serializing reactions without account information. The optimization attempted to reduce query complexity by separating post data loading, but inadvertently broke reaction serialization for nested posts (shares and quotes). Database indexes added in 0.6.17 are retained.

Version 0.6.17

Released on November 15, 2025.

  • Significantly improved /api/v1/notifications endpoint performance by optimizing database queries and restructuring data loading strategy. The endpoint now responds in under 1.6 seconds, down from over 2.5 seconds previously (approximately 40% improvement). Key optimizations include:

    • Pre-fetching muted and blocked account IDs to eliminate correlated subqueries in notification type queries.
    • Separating post data loading into multiple targeted queries instead of using deeply nested lateral joins, reducing query complexity and execution time.
    • Adding strategic database indexes on follows, mutes, likes, and reactions tables to improve query performance.

Version 0.6.16

Released on November 12, 2025.

  • Fixed search functionality not returning any results when searching for post content.

  • Fixed search results including shared posts (reposts/reblogs). Search now shows only original posts and replies, excluding shares.

Version 0.6.15

Released on November 7, 2025.

  • Significantly improved /nodeinfo/2.1 endpoint performance by optimizing database queries and adding appropriate indexes. The endpoint now responds in under 1 second even with millions of federated posts, down from 5–15 seconds previously. This prevents load balancer health check failures and external service timeouts. [#282]

Version 0.6.14

Released on October 7, 2025.

  • Fixed a critical security vulnerability where direct messages (DMs) were visible to all authenticated users regardless of whether they were participants in the conversation. The visibility filter now correctly restricts direct messages to only the sender and mentioned recipients, preventing unauthorized access to private conversations. [#247, #255 by Hyeonseo Kim]

Version 0.6.13

Released on October 7, 2025.

  • Fixed a bug where replies from followers who are not followed back were not visible in conversation threads. The visibility filter now correctly includes posts that mention the authenticated user, ensuring that all replies directed to the user are displayed regardless of follow-back status.

Version 0.6.12

Released on October 4, 2025.

  • Fixed a critical security vulnerability where direct messages were leaked on public post pages. The replies list below posts now correctly filters to show only public or unlisted replies, preventing private conversations from being exposed. [#246, #248 by Hyeonseo Kim]

Version 0.6.11

Released on September 17, 2025.

  • Fixed a bug where Like activities from Bluesky via BridgyFed were not being received due to invalid AT Protocol URIs. This was resolved by upgrading Fedify to 1.5.9, which includes improved AT Protocol URI handling to properly parse URIs with DID authorities. [#217]

Version 0.6.10

Released on August 26, 2025.

  • Upgraded Fedifyh to 1.5.7 which fixes a bug where HTTP Signature verification failed for requests having created or expires fields in their Signature header, causing 500 Internal Server Error responses in inbox handlers.

Version 0.6.9

Released on August 25, 2025.

  • Fixed a bug where ActivityPub Discovery failed to recognize XHTML self-closing <link> tags. The HTML/XHTML parser now correctly handles whitespace before the self-closing slash (/>), improving compatibility with XHTML documents that follow the self-closing tag format.

  • Upgraded Fedify to 1.5.6.

Version 0.6.8

Released on August 21, 2025.

  • Fixed a critical bug introduced in 0.6.7 where the search query would return too many results, causing out-of-memory errors and query timeouts. The issue was caused by incorrect logical operator precedence when filtering future-dated posts. [#207, #208 by aliceif]

Version 0.6.7

Released on August 19, 2025.

  • Fixed timeline pollution caused by future-dated posts from malicious or misconfigured remote instances. Posts with timestamps more than 5 minutes in the future are now filtered from all timeline endpoints while preserving them in the database for future display. [#199, #201 by Hyeonseo Kim]

Version 0.6.6

Released on August 8, 2025.

  • Upgrade Fedify to 1.5.5, which includes a critical security fix CVE-2025-54888 that addresses an authentication bypass vulnerability allowing actor impersonation. [CVE-2025-54888]

Version 0.6.5

Released on July 17, 2025.

  • Fixed an HTML injection vulnerability where form elements, scripts, and other potentially dangerous HTML tags in federated posts were not properly sanitized before rendering. This could allow malicious actors to inject forms for phishing, execute JavaScript, or perform CSRF attacks. The fix implements strict HTML sanitization using an allowlist approach to ensure only safe HTML elements and attributes are rendered. [CVE-2025-53941]

Version 0.6.4

Released on July 7, 2025.

  • Fixed a regression bug where follower-only posts were returning 404 Not Found errors when accessed through conversation threads. This was caused by improper OAuth scope checking that only accepted read:statuses scope but tokens contain read scope: [#169, #172]

    • GET /api/v1/statuses/:id
    • GET /api/v1/statuses/:id/context

Version 0.6.3

Released on June 23, 2025.

  • Fixed a bug where remote posts mentioning the same user multiple times could not be retrieved due to database constraint violations.

Version 0.6.2

Released on June 8, 2025.

  • Fixed an issue where Hollo 0.6.x installations upgraded from Hollo 0.5.x or earlier failed to sign in with Elk, a popular Mastodon client. This was caused by old application registrations incorrectly defaulting to non-confidential. All existing applications are now properly set as confidential clients. [#167, #168 by Emelia Smith]

Version 0.6.1

Released on June 5, 2025.

  • Fixed POST /oauth/token endpoint rejecting requests with additional parameters not required by RFC 6749 but commonly sent by clients. The endpoint now gracefully ignores extra parameters like scope in authorization_code requests and redirect_uri in client_credentials requests instead of returning validation errors. [#163, #164 by Hong Minhee]

Version 0.6.0

Released on June 5, 2025.

  • Revamped the environment variables for asset storage configuration. [#115, #121 by Emelia Smith]

    • Added FS_STORAGE_PATH environment variable, which is required where DRIVE_DISK is set to fs.
    • Added STORAGE_URL_BASE environment variable, which is required.
    • Deprecated FS_ASSET_PATH in favor of FS_STORAGE_PATH.
    • Deprecated ASSET_URL_BASE in favor of STORAGE_URL_BASE.
  • Implemented OAuth 2.0 Authorization Code flow with support for access grants. This improves the security of the OAuth authorization process by separating the authorization code from the access token issuance. [#130 by Emelia Smith]

  • Hollo now requires the SECRET_KEY environment variable to be at least 44 characters long. This change ensures sufficient entropy for cryptographic operations. [#126 by Emelia Smith]

  • Hollo now lets /.well-known/ and /oauth/ endpoints allow cross origin requests which is aligned with those of Mastodon. [#126 by Emelia Smith]

  • Added the BIND environment variable to specify the host address to listen on. [#114, #120 by Emelia Smith]

  • The theme color of the profile page is now customizable. The list of all available theme colors can be found in the Colors section of the Pico CSS docs.

  • You can now sign out from the administration dashboard. [#50, #122 by Emelia Smith]

  • On profile page, shared posts are now more visually separated from the original posts, and the time of sharing is now shown. [#111]

  • On profile page, alt texts for images are now expanded within <details>. [#99, #110 by Okuto Oyama]

  • The scope parameter is now optional for POST /oauth/token endpoint.

  • The current version string is displayed at the bottom of the dashboard page. [#136, #137 by RangHo Lee]

  • Increased the maximum character limit for posts from 4,096 to 10,000 characters.

  • EXIF metadata of attached images are now stripped before storing them to prevent privacy leaks. [#152 by NTSK]

  • Code blocks inside Markdown are now highlighted. The syntax highlighting is powered By Shiki. See also the complete list of supported languages. [#149]

  • Implemented OAuth 2.0 Proof Key for Code Exchange (PKCE) support with the S256 code challenge method. This enhances security by preventing authorization code interception attacks in the OAuth authorization flow. [#155 by Emelia Smith]

  • Added support for the profile OAuth scope for enhanced user authentication. This allows applications to request limited profile information using the new /oauth/userinfo endpoint and enables the profile scope to be used with the GET /api/v1/accounts/verify_credentials endpoint. [#45, #156 by Emelia Smith]

  • Made few Mastodon API endpoints publicly accessible without authentication so that they behave more similarly to Mastodon:

    • GET /api/v1/statuses/:id
    • GET /api/v1/statuses/:id/context
  • Upgraded Fedify to 1.5.3 and @fedify/postgres to 0.3.0.

  • The minimum required version of Node.js is now 24.0.0.

Version 0.5.7

Released on August 8, 2025.

  • Upgrade Fedify to 1.4.13, which includes a critical security fix CVE-2025-54888 that addresses an authentication bypass vulnerability allowing actor impersonation. [CVE-2025-54888]

Version 0.5.6

Released on April 29, 2025.

  • Fixed a bug where voting to a poll which had been shared (boosted) had not been sent to the correct recipient. [#142]

  • Upgrade Fedify to 1.4.10.

Version 0.5.5

Released on March 23, 2025.

  • Fixed a bug where private replies were incorrectly delivered to all recipients of the original post, regardless of visibility settings.

  • Improved privacy for direct messages by preventing delivery through shared inboxes.

Version 0.5.4

Released on February 26, 2025.

  • Fixed a bug where custom emojis in the display name and bio had not been rendered correctly from other software including Mitra.

  • Upgrade Fedify to 1.4.4.

Version 0.5.3

Released on February 22, 2025.

  • Fixed a bug where when an account profile had been updated, the Update activity had been made with no assertionMethods field, which had caused interoperability issues with Mitra.

  • Upgrade Fedify to 1.4.3.

Version 0.5.2

Released on February 20, 2025.

  • Fixed a bug where the follows.follower_id column had not referenced the accounts.id column. [#112]

  • Fixed a bug where GET /api/v1/notifications had returned server errors with some filters. [#113]

  • Fixed a bug where the federation dashboard had not shown due to server errors when an instance had just been set up.

  • Upgrade Fedify to 1.4.2.

Version 0.5.1

Released on February 14, 2025.

  • Fixed a bug where GET /api/v1/accounts/:id/statuses had tried to fetch remote posts for local accounts. [#107]

Version 0.5.0

Released on February 12, 2025.

  • The number of shares and likes became more accurate.

    • The Note objects now have shares and likes collections with their totalItems numbers.
    • When a remote Note is persisted, now the totalItems numbers of shares and likes are also persisted.
    • When a Announce(Note) or Undo(Announce(Note)) activity is received, now it is forwarded to the followers as well if the activity is signed.
  • Added GET /api/v1/mutes API to Mastodon comapatiblity layer. This API returns a list of accounts that are muted by the authenticated user. [#103]

  • Added GET /api/v1/blocks API to Mastodon comapatiblity layer. This API returns a list of accounts that are blocked by the authenticated user. [#103]

  • On profile page, backward pagination (newer posts) is now available. [#104, #105 by Okuto Oyama]

  • On profile page, images are no more captioned using <figcaption> but use only alt attribute for accessibility. [#99, #100 by Okuto Oyama]

  • Fixed a style bug where horizontal scrolling occurred when the screen size was reduced when there were many custom fields on profile page. [#106 by Okuto Oyama]

  • Added ALLOW_HTML environment variable to allow raw HTML inside Markdown. This is useful for allowing users to use broader formatting options outside of Markdown, but to avoid XSS attacks, it is still limited to a subset of HTML tags and attributes.

  • On profile page, the favicon is now switched between light and dark mode according to the user's preference. [#101]

  • The S3_REGION environment variable became required if DRIVE_DISK is set to s3. [#95]

Version 0.4.12

Released on August 8, 2025.

  • Upgrade Fedify to 1.3.20, which includes a critical security fix CVE-2025-54888 that addresses an authentication bypass vulnerability allowing actor impersonation. [CVE-2025-54888]

Version 0.4.11

Released on March 23, 2025.

  • Fixed a bug where private replies were incorrectly delivered to all recipients of the original post, regardless of visibility settings.

  • Improved privacy for direct messages by preventing delivery through shared inboxes.

Version 0.4.10

Released on February 26, 2025.

  • Fixed a bug where custom emojis in the display name and bio had not been rendered correctly from other software including Mitra.

  • Upgrade Fedify to 1.3.11.

Version 0.4.9

Released on February 22, 2025.

  • Fixed a bug where when an account profile had been updated, the Update activity had been made with no assertionMethods field, which had caused interoperability issues with Mitra.

  • Upgrade Fedify to 1.3.10.

Version 0.4.8

Released on February 20, 2025.

  • Fixed a bug where the follows.follower_id column had not referenced the accounts.id column. [#112]

  • Fixed a bug where GET /api/v1/notifications had returned server errors with some filters. [#113]

  • Fixed a bug where the federation dashboard had not shown due to server errors when an instance had just been set up.

  • Upgrade Fedify to 1.3.9.

Version 0.4.7

Released on February 14, 2025.

  • Fixed a bug where GET /api/v1/accounts/:id/statuses had tried to fetch remote posts for local accounts. [#107]
  • Upgrade Fedify to 1.3.8.

Version 0.4.6

Released on February 1, 2025.

  • Upgrade Fedify to 1.3.7.

  • Fixed a bug where LOG_LEVEL environment variable had not been respected.

  • Fixed a bug where when DRIVE_DISK is set to fs and FS_ASSET_PATH is set to a relative path, Hollo server had failed to start.

Version 0.4.5

Released on January 31, 2025.

  • Fixed a bug where the migration dashboard had not been shown correctly when the aliases of the account contained an actor whose the server was unreachable. [#98]

  • Fixed a bug where Hollo posts had included unintended extra line breaks on Iceshrimp. [#88]

  • Fixed a bug where importing emojis from remote servers had failed when some shortcodes were already in use. [#102]

  • Upgrade Fedify to 1.3.6.

Version 0.4.4

Released on January 21, 2025.

Version 0.4.3

Released on January 11, 2025.

  • Fixed a bug where mutes with duration had not been expired correctly. [#92]
  • Fixed a bug where importing follows from CSV generated by Iceshrimp had failed. [#85]

Version 0.4.2

Released on December 31, 2024.

  • Prefer IPv6 to IPv4 addresses when connecting to remote servers.

Version 0.4.1

Released on December 31, 2024.

  • Upgrade Fedify to 1.3.3.

  • Fixed an interoperability issue with GoToSocial.

Version 0.4.0

Released on December 30, 2024.

  • Hollo is now powered by Node.js 23+ instead of Bun for more efficient memory usage.

  • Added an experimental feature flag TIMELINE_INBOXES to store all posts visible to your timeline in the database, rather than filtering them in real-time as they are displayed. This is useful for relatively larger instances with many incoming posts, but as of now it may have several bugs. It is expected to be the default behavior in the future after it is stabilized.

  • Now you can import and export your data from the administration dashboard in CSV format: follows, lists, accounts you muted, accounts you blocked, and bookmarks.

  • You can now make your profile discoverable.

  • The profile page now shows a user's cover image if they have one.

  • Added GET /api/v1/statuses/:id/reblogged_by API to Mastodon comapatiblity layer. This API returns a list of accounts that have shared a post.

  • Fixed a bug where a server error occurred when an invalid UUID was input via URL or form data. [#65]

  • Fixed a bug where the same post could be shared multiple times by the same account.

  • Added LOG_FILE environment variable to specify the file path to write structured logs. The logs are written in JSON Lines format.

  • Improved the performance of recipients gathering during sending activities.

  • For the sake of concision, now log sink for Sentry is removed.

Version 0.3.11

Released on August 8, 2025.

  • Upgrade Fedify to 1.3.20, which includes a critical security fix CVE-2025-54888 that addresses an authentication bypass vulnerability allowing actor impersonation. [CVE-2025-54888]

Version 0.3.10

Released on March 23, 2025.

  • Fixed a bug where private replies were incorrectly delivered to all recipients of the original post, regardless of visibility settings.

  • Improved privacy for direct messages by preventing delivery through shared inboxes.

Version 0.3.9

Released on February 26, 2025.

  • Fixed a bug where custom emojis in the display name and bio had not been rendered correctly from other software including Mitra.

  • Upgrade Fedify to 1.3.11.

Version 0.3.8

Released on February 22, 2025.

  • Fixed a bug where when an account profile had been updated, the Update activity had been made with no assertionMethods field, which had caused interoperability issues with Mitra.

  • Upgrade Fedify to 1.3.10.

Version 0.3.7

Released on February 14, 2025.

  • Fixed a bug where GET /api/v1/accounts/:id/statuses had tried to fetch remote posts for local accounts. [#107]
  • Upgrade Fedify to 1.3.8.

Version 0.3.6

Released on January 21, 2025.

Version 0.3.5

Released on December 28, 2024.

  • Fixed a bug where validation check for the account username had not been performed correctly. [#80]

  • Documented the TZ environment variable. [#82]

Version 0.3.4

Released on December 20, 2024.

  • Fixed a bug where deleting a post had not been propagated to the peers.

Version 0.3.3

Released on December 19, 2024.

  • Fixed a bug where generated thumbnails had been cropped incorrectly if the original image had not the EXIF orientation metadata. [#76]

Version 0.3.2

Released on December 18, 2024.

  • Fixed a bug where generated thumbnails had not copied the EXIF orientation metadata from the original image. [#76]

  • Fixed a bug where looking up remote Hubzilla actors and objects had failed. [#78]

  • Upgrade Fedify to 1.3.2.

Version 0.3.1

Released on December 13, 2024.

  • Fixed a bug where Undo(Like) activities on a Question object had not been handled correctly.

  • Fixed a bug where EmojiReact activities on a Question object had not been handled correctly.

  • Fixed a bug where Undo(EmojiReact) activities on a Question object had not been handled correctly.

Version 0.3.0

Released on December 1, 2024.

  • Added support for local filesystem storage for media files. You can now configure DRIVE_DISK=fs and FS_ASSET_PATH to store media files in the local filesystem. [#59]

    • Added DRIVE_DISK environment variable.
    • Added FS_ASSET_PATH environment variable.
    • Added ASSET_URL_BASE environment variable to replace S3_URL_BASE.
    • Deprecated S3_URL_BASE environment variable in favor of ASSET_URL_BASE.
  • Added support for Sentry.

    • Added SENTRY_DSN environment variable.
  • Added pagination to the profile page. [#40]

  • Upgrade Fedify to 1.3.0.

Version 0.2.4

Released on December 13, 2024.

  • Fixed a bug where Undo(Like) activities on a Question object had not been handled correctly.

  • Fixed a bug where EmojiReact activities on a Question object had not been handled correctly.

  • Fixed a bug where Undo(EmojiReact) activities on a Question object had not been handled correctly.

Version 0.2.3

Released on November 22, 2024.

  • Fixed a bug where followees and followers that had not been approved follow requests had been shown in the followees and followers lists.

  • Fixed a bug where followees and followers had been listed in the wrong order in the followees and followers lists. [#71]

  • Upgrade Fedify to 1.2.7.

Version 0.2.2

Released on November 7, 2024.

  • Fixed a bug where replies without mention had not shown up in the notifications. [#62]

Version 0.2.1

Released on November 4, 2024.

  • Fixed a bug where posts from some ActivityPub software (e.g., Misskey, Sharkey, Akkoma) had empty url fields, causing them to be displayed incorrectly in client apps. [#58]

Version 0.2.0

Released on November 3, 2024.

  • Dropped support for Redis.

  • Added two-factor authentication support. [#38]

  • Custom emojis now can be deleted from the administration dashboard.

  • Renamed the Data menu from the administration dashboard to Federation.

    • Now posts also can be force-refreshed.
    • Now the number of messages in the task queue is shown.
  • Added support for reporting remote accounts and posts. [#41 by Emelia Smith]

  • Improved alignment on Mastodon API changes about OAuth and apps. [#43 by Emelia Smith]

    • GET /api/v1/apps/verify_credentials no longer requires read scope, just a valid access token (or client credential).
    • POST /api/v1/apps now supports multiple redirect URIs.
    • redirect_uri is deprecated, but software may still rely on it until they switch to redirect_uris.
    • Expose redirect_uri, redirect_uris, and scopes to verify credentials for apps.
  • Added support for RFC 8414 for OAuth Authorization Server metadata endpoint. [#47 by Emelia Smith]

  • On creating a new account, the user now can choose to follow the official Hollo account.

  • Added a favicon.

  • Added PORT and ALLOW_PRIVATE_ADDRESS environment variables. [#53 by Helge Krueger]

Version 0.1.7

Released on November 4, 2024.

  • Fixed a bug where posts from some ActivityPub software (e.g., Misskey, Sharkey, Akkoma) had empty url fields, causing them to be displayed incorrectly in client apps. [#58]

Version 0.1.6

Released on October 30, 2024.

  • Fixed a bug where followers-only posts from accounts that had had set their follower lists to private had been recognized as direct messages. Even after upgrading to this version, such accounts need to be force-refreshed from the administration dashboard to fix the issue.

  • Fixed the federated (public) timeline showing the shared posts from the blocked or muted accounts.

  • Fixed the list timeline showing the shared posts from the blocked or muted accounts.

Version 0.1.5

Released on October 30, 2024.

  • Fixed the profile page showing the shared posts from the blocked or muted accounts.

Version 0.1.4

Released on October 30, 2024.

  • Fixed the home timeline showing the shared posts from the blocked or muted accounts.

Version 0.1.3

Released on October 27, 2024.

  • Fixed incorrect handling of relative path URIs in Link headers with rel=alternate. This caused inoperability with some software such as GoToSocial.
  • It now sends Delete(Person) activity to followees besides followers when a user deletes their account.

Version 0.1.2

Released on October 24, 2024.

  • Fixed the last page in the profile using Moshidon leading to infinite pagination. [#48 by Emelia Smith]

Version 0.1.1

Released on October 24, 2024.

  • Upgrade Fedify to 1.1.1.

Version 0.1.0

Released on October 22, 2024. Initial release.