Skip to content

Releases: fedify-dev/hollo

Hollo 0.9.4

04 Jun 08:14
0.9.4
5711c2d

Choose a tag to compare

Released on June 4, 2026.

  • Upgraded Fedify to 2.2.4 to address a security vulnerability in SSRF mitigation. [CVE-2026-50131]

Hollo 0.8.7

04 Jun 08:10
0.8.7
47dcf9e

Choose a tag to compare

Released on June 4, 2026.

  • Upgraded Fedify to 2.1.15 to address a security vulnerability in SSRF mitigation. [CVE-2026-50131]

Hollo 0.7.18

04 Jun 08:06
0.7.18
34e3b1d

Choose a tag to compare

Released on June 4, 2026.

  • Upgraded Fedify to 1.10.11 to address a security vulnerability in SSRF mitigation. [CVE-2026-50131]

Hollo 0.9.3

03 Jun 11:59
0.9.3
d7e0426

Choose a tag to compare

Released on June 3, 2026.

  • Fixed a bug where some remote accounts' custom profile fields were rendered as per-character entries (field names 0, 1, 2, … with one character of HTML in each value) in Mastodon API responses and on profile pages. The affected rows had their field_htmls (and potentially emojis or fields) stored as double-encoded JSON strings by an older Drizzle ORM version; a data migration repairs them, and new CHECK constraints enforce that these columns always hold JSON objects. [#504]

Hollo 0.9.2

25 May 12:51
0.9.2
94ed038

Choose a tag to compare

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]

Hollo 0.9.1

20 May 17:29
0.9.1
e32c9e8

Choose a tag to compare

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]

Hollo 0.9.0

20 May 11:14
0.9.0
033de82

Choose a tag to compare

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](https://brandur.org/...

Read more

Hollo 0.8.6

20 May 17:29
0.8.6
abdb279

Choose a tag to compare

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]

Hollo 0.7.17

20 May 17:29
0.7.17
24c4fec

Choose a tag to compare

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]

Hollo 0.8.5

19 May 02:41
0.8.5
a30908b

Choose a tag to compare

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.