1
 
 

Just a quick note for NodeBB admins to update to v4.14.4 as there was a regression identified for versions v4.12.0 to v4.14.3 where federation was broken between NodeBB and Mastodon instances with authorized fetch enabled.

2
 
 

Starting with 4.13.3, the default value of trust_proxy will be false on new installs to ensure a secure default setting.

An upgrade script will set the value to true if it is not found in config.json to prevent breaking existing installs.

The documentation is updated to reflect the change:

  • trust_proxy (Default: false) Enables Express' proxy trust handling for req.ip and related values.
    • Only set this to true when NodeBB is behind a reverse proxy that strips or overwrites untrusted X-Forwarded-For headers.
    • If this is left unset, NodeBB will not trust forwarded client IP headers.
    • For more information see expressjs docs https://expressjs.com/en/5x/guide/behind-proxies/

If you are upgrading from 4.13.2 and already use a proxy like nginx, you don't have to do anything. trust_proxy: true will be automatically set in config.json

If your nodebb was facing the public directly on port 4567(which isn't recommended). Remove trust_proxy from config.json OR set it to false via trust_proxy: false.

3
 
 

With temperatures reaching well into the 30s (in celsius of course :sunglasses:) in the Toronto area, we're all firmly in summer mode :swimmer: :beach_with_umbrella: , but that won't stop us from forging on ahead with new features and fixes for NodeBB!

There are improvements across ActivityPub federation, administrative tooling, and security hardening. Our ActivityPub integration receives bug fixes including duplicate handling, configurable rate limiting, and better error reporting, alongside new hooks for remote user lifecycle events. The registration queue and invitations are reorganized into a dedicated UI with a new "Reject All" bulk action and improved notification handling. Security reports have been coming in consistently throughout the month with valid security reports (though almost all AI discovered and generated). This led to stricter privilege checks on post diffs, crossposts, and GDPR exports, plus protection against username enumeration. The NodeBB team strongly encourages upgrading to v4.14.0 for the latest security fixes and federation improvements. The release also includes a new tx() translation helper, Benchpress escaping improvements, and a first-run categories onboarding modal for fresh installations.

Here are the high level changes you can expect to see when you upgrade from v4.13.0 to v4.14.0...

:globe_with_meridians: Federation Regression Fixes!

Around v4.12.0 or so, a number of regressions were unintentionally introduced as part of security fixes that severely hampered federation — especially with Lemmy-based instances and relays. We've resolved those regressions and Relay/Lemmy federation should resume within 24 hours after upgrading.

The public key fetch rate limiter logic was simplified and updated (due to it being faulty and not really working in the first place), streamlined some duplicate logic with Like/Dislike activities, improved the AP Errors reporting page in the ACP, added a parent traversal depth guard, fixed an issue where updates to scheduled topics were accidentally being federated out, and about a hundred other smaller bugs :)

:ballot_box_with_check: Registration Queue updates

The registration queue was moved out of the ACP, and invitations are also managed in this page now. A "reject all" button was added to allow admins to quickly reject every queued registrant in one fell swoop.

🔒 Privilege & Security Fixes

  • Post diff access — Check topics:read privilege when loading post diffs
  • Crossposts — Added source category privilege check to crossposts
  • GDPR export — Prevented global moderators from performing GDPR data exports
  • Nids ownership — Don't mark nids as read/unread that you don't own
  • Upload privileges — Prevent uploading thumbnails without upload:image privilege; replaced extension-based MIME validation with content
    sniffing
  • Username enumeration — Use dummy lockout key for non-existent users to prevent enumeration
  • Category disabled flag — Check category disabled flag on getRaw

:interrobang: Benchpress Improvements

We use Benchpress as our templating engine. We updated our integration for security and performance. [@baris put together a thorough write-up for that one here](https://community.nodebb.org/topic/19364/upcoming-breaking-changes-for-4.14.0).

Miscellaneous

  • First-run modal — New categories onboarding modal for fresh installations
  • Dashboard warnings — Added localhost and URL mismatch warnings to admin dashboard notices
  • Push notifications should work on Safari/iOS devices now (via the web-push plugin)
4
Harmony Theme Upgrade Changes (community.nodebb.org)
submitted 1 month ago* (last edited 1 month ago) by to c/nodebb-development@community.nodebb.org
 
 

Organized by change type so upgrades can be done in passes and reviewed more easily.

1. Helper syntax changes ({helper()}{{helper()}})

header.tpl

  • {buildMetaTag}{{buildMetaTag}}
  • {buildLinkTag}{{buildLinkTag}}

Avatar helper (all templates showing user avatars)

  • {buildAvatar}{{buildAvatar}}

Category icon helpers

partials/account/category-item.tpl

partials/categories/item.tpl

partials/quick-category-search-results.tpl

partials/buttons/newTopic.tpl

category.tpl

world.tpl

  • {buildCategoryIcon}{{buildCategoryIcon}}

Category label helpers

partials/posts_list_item.tpl

partials/quick-search-results.tpl

partials/topics_list.tpl

topic.tpl

  • {buildCategoryLabel}{{buildCategoryLabel}}

Other helper conversions

partials/account/session-list.tpl

  • {userAgentIcons(@value)}{{userAgentIcons(@value)}}

partials/topic/post.tpl

  • {generateWrote(@value, config.timeagoCutoff)}{{generateWrote(@value, config.timeagoCutoff)}}

2. Translation (tx()) changes

Account templates

account/categories.tpl

account/uploads.tpl

account/tags.tpl

  • {title}{{tx(title)}}

account/info.tpl

  • {./reason}{{tx(./reason)}}

account/topics.tpl

  • {./name}{{tx(./name)}}

account/posts.tpl

account/shares.tpl

account/topics.tpl

  • {noItemsFoundKey}{{tx(noItemsFoundKey)}}

account/profile.tpl

account/settings.tpl

partials/account/sidebar-left.tpl

partials/categories/link.tpl

partials/skin-switcher.tpl

category.tpl

  • {./name}{{tx(./name)}}

account/settings.tpl

  • {./bootswatchSkinOptions.name}{{tx(./bootswatchSkinOptions.name)}}

  • {./name}{{tx(./name)}}

  • {./label}{{tx(./label)}}

Topic templates

partials/topic/necro-post.tpl

  • {text}{{tx(text)}}

partials/topic/post.tpl

  • {posts.replies.text}{{tx(posts.replies.text)}}

partials/topic/sort.tpl

  • {sortOptionLabel}{{tx(sortOptionLabel)}}

Navigation templates

partials/topic/breadcrumbs.tpl

partials/mobile-nav.tpl

partials/sidebar-left.tpl

  • {./text}{{tx(./text)}}

partials/mobile-nav.tpl

partials/sidebar-left.tpl

  • {./title}{{tx(./title)}}

Other translations

partials/cookie-consent.tpl

  • {message}{{tx(message)}}
  • {link}{{tx(link)}}
  • {dismiss}{{tx(dismiss)}}

notifications.tpl

  • {filters.name}{{tx(filters.name)}}

partials/breadcrumbs-json-ld.tpl

  • {stripTags(./text)}{{tx(./text)}}

3. HTML/raw output, txEscape() changes

Raw HTML rendering

account/profile.tpl

  • {./html}{{./html}}

account/settings.tpl

  • {./content}{{./content}}

partials/topic/post.tpl

  • {posts.user.custom_profile_info.content}{{posts.user.custom_profile_info.content}}

partials/topic/event.tpl

  • {./text}{{./text}}

partials/mobile-nav.tpl

partials/sidebar-left.tpl

  • {./dropdownContent}{{./dropdownContent}}

partials/notifications_list.tpl

  • {./bodyShort}{{./bodyShort}}
  • {./bodyLong}{{./bodyLong}}

txEscape() conversions

account/profile.tpl

  • {aboutmeParsed}{{txEscape(aboutmeParsed)}}

  • {posts.user.signature}{{txEscape(posts.user.signature)}}

partials/topics_list.tpl

  • {./title}{{{ if ./txTitle }}}{{tx(./title)}}{{{ else }}}{./title}{{{ end }}}

  • {./teaser.content}{./teaser.content} => {{txEscape(./teaser.content)}}

partials/topic/post.tpl

  • {posts.content}{{{ if posts.txContent }}}{{tx(posts.content)}}{{{ else }}}{{txEscape(posts.content)}}{{{ end }}}

partials/topic/navigation-post.tpl

  • {post.content}{{{ if post.txContent }}}{{tx(posts.content)}}{{{ else }}}{{txEscape(post.content))}}{{{ end }}}

partials/categories/lastpost.tpl

  • {./content}{{txEscape(./content)}}

partials/posts_list_item.tpl

  • {./content}{{{ if ./txContent }}}{{tx(./content)}}{{{ else }}}{{./content}}{{{ end }}}

4. Remove obsolete escaping

URL escaping

partials/account/header.tpl

  • {escape(cover:url)}{cover:url}

partials/categories/children.tpl

partials/categories/link.tpl

  • {txEscape(./link)}{./link}

partials/topic-list-bar.tpl

  • {escape(url)}{url}

category.tpl

  • {escape(./url)}{./url}

Value escaping

partials/category/tags.tpl

partials/topic/tag.tpl

partials/posts_list_item.tpl

partials/search-filters.tpl

partials/tags_list.tpl

partials/topics_list.tpl

  • {./valueEscaped}{./value}

Strip tags removal

partials/topics_list.tpl

  • {stripTags(./title)}{./title}

category.tpl

  • [[category:handle.description, {txEscape(handleFull)}]][[category:handle.description, {handleFull}]]

5. Translation string syntax updates

partials/sidebar/drafts.tpl

  • [[topic:composer.replying-to, "{txEscape(./title)}"]]{{tx("topic:composer.replying-to", txEscape(quote(./title)))}}

  • [[topic:composer.editing-in, "{txEscape(./title)}"]]{{tx("topic:composer.editing-in", txEscape(quote(./title)))}}

partials/search-results.tpl

  • [[search:results-matching, {matchCount}, {txEscape(search_query)}, {time}]]{{tx("search:results-matching", matchCount, txEscape(search_query), time)}}

6. Topic icon refactor

partials/topics_list.tpl

Replace:

{{{each ./icons}}}<span class="lh-1">{@value}</span>{{{end}}}

With:

{{{ each ./icons }}}

{{{ end }}}

topic.tpl

Replace:

{{{each icons}}}<span class="lh-1">{@value}</span>{{{end}}}

With:

{{{ each ./icons }}}

{{{ end }}}

Add new file

partials/topic/icon.tpl

<span class="badge border {./classes}">
{{{ if ./icon }}}<i class="fa {./icon}"></i>{{{ end }}}
{{{ if ./label }}}<span> {tx(./label)}</span>{{{ end }}}
</span>

7. Structural template updates

topic.tpl

Replace topic meta tags with:


5
submitted 1 month ago* (last edited 13 hours ago) by to c/nodebb-development@community.nodebb.org
 
 

Hello Everyone,

The upcoming 4.14.0 release will have breaking changes for themes and plugins that display html and translation tokens via template variables. This post will outline the changes required to custom themes based on the changes made in the Harmony theme to serve as a guide for upgrading your own themes & plugins.

1. Escape all template variables via {variable}

The first and biggest change is the introduction of html and translation escaping of all variables in templates. Prior to 4.14.0 if you wrote {variable} in a template the value would be inserted into the html page unchanged. Benchpressjs supports escaping these variables but it was disabled to prevent a breaking change when the migration was done from templates.js to benchpressjs. We are now aligning with how most template engines work.

What this means for themes is if variable contained html then it will no longer be displayed properly. For example the content of posts is rendered via {posts.content} in partials/topic/post.tpl. Upgrading to 4.14.0 without fixing the template would result in:

blog-1.png

To fix this in 4.14.0, you will have to wrap the variable with double braces like {{posts.content}}. This will stop the escaping and the post content will display properly. Double braces should only be used on content that is html sanitized. In this case NodeBB converts markdown to html and sanitizes it so it is safe. Do not use {{variable}} syntax on untrusted content.

The {{}} syntax should also be used on all helper functions that return html. For example buildAvatar function return html to display the user icon or picture. So {buildAvatar(user, "24px", true)} should be changed to {{buildAvatar(user, "24px", true)}}. We've updated all these helpers to escape the values and attributes used. If you have custom helpers you should do the same. Below is an example of a helper that is used in header.tpl. It uses the same escape function that {variable} uses.

function buildMetaTag(tag) {
  const name = tag.name ? `name="${escape(tag.name)}" ` : '';
  const property = tag.property ? `property="${escape(tag.property)}" ` : '';
  const content = tag.content ? `content="${escape(tag.content).replace(/\n/g, ' ')}" ` : '';

  return '\n\t';
}

Refer to section 3, for a full list of changes that were made to Harmony theme to upgrade it to 4.14.0.

2. Migration to tx() and txEscape() helper functions

This is the second major change, and we're introducing it as part of an ongoing upgrade process to help avoid creating too much work for theme maintainers at once.

The way translation works in NodeBB is through a post render step. After benchpressjs renders the template and generates the html page, our translator scans the html page and replaces translation tokens that look like [[namespace:key]] with their correct translation.

Here is roughly how it goes from request to final html presented to user.

  1. User requests /topic/1
  2. Load all required data from database
  3. Call filter:parse.post to turn post markdown into html
  4. Translator escapes the html from step 3, so tokens in the post content don't get translated
  5. Benchpress renders the html filling in all data
  6. Translator scans html replacing translation tokens with their translations
  7. Translator unescapes the result (reverses step 4)
  8. Final html sent to user

With the introduction of a helper function tx() instead of scanning the entire page, we can use the helper to translate tokens. For example instead of <button>[[topic:reply]]</button> we can use <button>{{tx("topic:reply")}}</button>. This approach is more efficient because only the translation tokens are processed.

With 4.14.0 we will still run the whole page translation to make migration easier, but for 4.15.0 we are going to remove that step, so the entire flow will be:

  1. User requests /topic/1
  2. Load all required data from database
  3. Call filter:parse.post to turn post markdown into html
  4. Benchpress renders the html, calls tx() to translate tokens
  5. Final html sent to user

We are introducing 2 new helper functions for templates:

  • tx() - translates the string or array passed in. This supports a variety of different usages:
Old New
[[namespace:key]] {{tx("namespace:key")}}
[[namespace:key, foo]] {{tx("namespace:key", "foo")}}
[[namespace:key, {arg1}, {arg2}]] {{tx("namespace:key", arg1, arg2)}}
{text} {{tx(text)}}

You can also pass an array to the tx() helper. For example if you have:

const myVar = ["namespace:key", "arg1", "arg2"];

This can be passed straight to tx in the template {{tx(myVar)}}

tx helper html escapes arguments and invalid translation keys.

  • txEscape() - escapes variable so it is not translated. This is a stop-gap solution until we remove the whole page translation. For example we use this on content that should not be translated. If someone puts [[namespace:key]] in their post it doesn't get translated. After 4.15.0 it will be safe to remove these since everything will use tx().

3. List of changes for Harmony Theme

Let's summarize the changes needed for 4.14.0.

  1. Wrap template helper functions that return html with {{}} instead of {}.
  2. Replace {translationString} with {{tx(translationString)}}.
  3. Wrap API values that should not be translated with {{txEscape(content)}}.
  4. (Ongoing) Replace old translation tokens [[namespace:key]] with {{tx("namespace:key")}}.

Refer to the Harmony Upgrade Changes Topic for the full list of changes.

4. Bootbox & app.renderAsync & Misc.

  1. The global bootbox object has been removed, there is a new modals module that also handles translations. Use modals.(dialog|confirm|alert|prompt) instead of bootbox variants. The only difference is these methods return a promise. So the old const modal = bootbox.dialog() becomes const modal = await modals.dialog()

  2. If you are using app.renderAsync to render a template it needs the translation context for tx() helper to work. NodeBB will automatically try to detect the user's language if app.renderAsync is called as part of a web request, but if it is called from a cron job or manually you can pass it the translation data like below:

const languages = nodebb.require('./src/languages);
const data = { 
  foo: 1,
  _i18n: languages.getFull('en-GB'),
};
const html = await app.renderAsync('mytemplate', data);
  1. config.assetBaseUrl was deprecated in 2.x, it is now removed, use config.asset_base_url
Why are we doing this?

As you know, we have a Bug Bounty Program, and the most commonly reported vulnerability is XSS, which is typically caused by unsanitized user input being rendered directly into HTML.

Currently we use the validator module to escape user controlled values however with the introduction of Activitypub support, attackers can manipulate data directly in the database of a remote NodeBB. When this category or user profile is displayed in a target NodeBB instance if any fields are not escaped via validator.escape() then it opens us up for XSS vulnerabilities. By moving the escaping to the template engine, we mitigate this and we no longer have to validator.escape() every value we load from the database.

All these changes are now live on this forum. Please let us know if you notice any issues. We plan to release 4.14.0 in July and follow up with 4.15.0 in August.

Let us know in the Technical Support category if you need help with updating your themes or plugins.

6
 
 

A new feature silently dropped in v4.12.0. NodeBB now supports Activity Intents!

Huh? What's an Activity Intent?

It is a proposal by @benpate@mastodon.social that aims to "extend the capabilities of an ActivityPub server beyond a user's outbox, and enable direct interactions with content on the wider social web."

In other words, it allows you to more seamlessly use your fediverse account on other sites without having to register a new account just to contribute.

In even simpler words, it means you can go to other forums and interact with content without needing to register a new account.

It directly tackles one of the fediverse "hard problems" I talked about last year — account fragmentation. You won't need additional accounts just to use other sites, your identity stays whole :sunglasses:

Let's learn more about how that works!

Account Fragmentation in a Nutshell

Right now, when you browse to a different site, you usually have to create a new account to interact with it. For example, if you check out someone's Pixelfed profile, you're not able to comment or like their pictures without an account there. This has always been how the internet worked, and before the advent of single sign-on, which lets you log in with a different account (but still creates a new account on that site), that was just how it was.

Essentially, there was no way to interact with content using your main identity. The workarounds were numerous... copying URLs, searching for the account on your instance, etc. All of which were fairly friction-heavy, so the next best thing was just to create a local account and fragment your identity.

Activity Intents intends (ha!) to address this by allowing servers to advertise support for different types of social actions.

How It Works

  1. You browse to another site and want to carry out an action, such as liking the post, or writing a reply.
  2. That site asks you to enter an Open Social Web handle (or log in, if you have a local account), and you enter it.
  3. It then queries your server to see what Intents it supports (e.g. "Like", "Create")
  4. If there's a match, it sends you back to your server, where you can complete the action.

That's about it! There are additional details about designing the actual flow, and how to "remember" each visitor's social web handle, but the basics are as listed above.

What it looks like in NodeBB

We've integrated support for four intents:

  1. Like/Dislike → These map to upvote and downvote respectively
  2. Create → These would be topic creations and replies
  3. Follow → self-explanatory
  4. Object → Load an ActivityPub resource in NodeBB

We integrated two-way support which means that if you land on a NodeBB and your fediverse account supports Activity Intents, then you can simply hit like, reply, or follow from NodeBB, and be sent back to your home server, all without the hassle of copying and pasting links into a search bar.

Integrating Activity Intents was a high-impact way to tackle the problem of account fragmentation. Users of NodeBB (whose forums have updated to v4.12.0) should not have to feel pressure to create local accounts elsewhere if the site they end up on supports Activity Intents as well.

7
NodeBB 4.12.0 & 3.12.9 Released (community.nodebb.org)
submitted 2 months ago* (last edited 2 months ago) by to c/nodebb-development@community.nodebb.org
 
 

Hello Everyone 👋,

Today we are releasing NodeBB 4.12.0 and 3.12.9.

These releases contain important security fixes, so upgrading is highly advised. NodeBB 1.x and 2.x no longer receive security updates.

🚨Minimum nodejs version required is 22.x and up.

Along with the security updates there are 4 new features.

Ability to see tags and thumbnails in post queue.

5be91e47-61a2-482a-8b40-69222f09bd5a-image.jpeg

The post will display the tags and thumbnails uploaded, and you can also edit them on the same page. The edit buttons were also moved from the bottom of the card to their respective areas.

Add visual indicators and filter tab for muted users

Muted users were not visible on the /users page and on their profiles. So we added a muted filter on the users page. A badge will also be displayed on their profile page.

Full-text search on chats list

fa732d8c-f196-489c-891e-77ec6fa5eee3-image.jpeg

If you have a lot of chats like @julian, you can now search them on the chat page. 🎊

Allow owners to move misplaced topics

Topic owners can now move their topic if they posted it in a wrong category. There is an admin setting to control the number of posts after this feature is disabled. Thanks to @palmoni for contributing this https://github.com/NodeBB/NodeBB/pull/14227

ESM migration of plugins and core

As part of our efforts to modernize the code base we have added support for writing plugins in ESM. Up until now plugins used require.main.require to import modules from core nodebb. This is now deprecated, the new method to require core modules is to replace it with nodebb.require.

Here is a sample plugin written in ESM that uses the new nodebb.require method https://github.com/NodeBB/nodebb-plugin-esm-test/blob/master/index.js.

Using require.main.require will generate a warning in development mode but will still work. We will slowly update bundled plugins over to ESM and the new method.

Bug fixes & Misc 🐛

Full list of closed issues.

8
 
 

Hi everybody — late last week we released v4.11.0, which contains the following changes:

ActivityPub Specific Fixes

:rotating_light: AP analytics and error pages

New pages have been added to the control panel to display analytics (send/receive counts) and error counts. There is also a new error page that will show error received within the last 24 hours, and their respective payloads. This will aid in debugging federation issues.

:writing_hand: Article vs. Note distinction updated

Prior to this version, NodeBB would determine whether a federated object was an Article or Note based on content length. This was confusing for end users, and was originally added before NodeBB supported title-less topics.

The revised distinction is much simpler. If it has a title, it's an Article. If it doesn't, it's a Note.

Smaller fixes

  • Threadiverse software publishes Delete objects wrapped in an Announce activity. This is how content is moderated across the threadiverse. NodeBB now supports this, although it has not been extensively tested at this time.
  • There was an interoperability issue with Mitra that was identified and fixed.
  • When group actors post content directly, the category info is shown in the user icon. It used to error out and show "Guest".
  • Optimized the outbound federation of content so the front-end is more responsive. A bunch of back-end optimizations to reduce the number of calculations needed.
  • Emojis now supported in DMs to remote users.

:no_bell: Ability to hide read notifications in user panel

A new option has been added to the "Notifications" sub-section of the user control panel.

d3f24e12-9426-459d-ad98-194057d76483-image.jpeg

This option will allow you to visibly hide read notifications from the notifications dropdown, which reduces visual clutter.

Tinycon customizations

Admins can now customize the notification badge shown in the browser tab icon. We use the Tinycon library for this, and the colour values can be customized now:

55e5cf07-5c70-4b01-97df-add1a3f57148-image.jpeg

9
 
 

Since 2017, we've maintained a bug bounty program that awarded responsible disclosure of security vulnerabilities on a sliding scale of $64 to $512 based on severity.

Throughout the years we've made some unpublished changes to this bounty program, mostly related to the format (no videos, text only, allowed testing endpoints) and in some cases expanding the scope of covered plugins (e.g. 2factor, web-push).

With the rise of LLMs and the corresponding drop in ability needed to analyze and send in reports, we have been receiving a large increase in reports whose submitters have no ability to defend or support their claims, but are happy to pretend that they do.

To be fair, this has been the case ever since the beginning. We've awarded our fair share of bounties to parties running static analysis scripts that output a ton of technical jargon that say very little. The difference today is the scale of these reports is whittling away what little patience I have left.

The easiest thing to do is to cancel the program outright. This would be unfair to the legitimate submitters of security vulnerabilities, and open us up to exploits that we simply would not learn about prior to exploitation. None of that sounds like the direction we want to go. I've gone on the record saying that the one thing OSS devs should set up (if they're able) is a bug bounty program, and I still stand by that claim.

Our bug bounty program remains, with one important change. AI-generated vulnerability reports will be rejected outright out of principle. If you did not do the work, you do not get to take credit for it. The social contract built into this program is, and has always been, a 1:1 exchange of humans talking to humans. Analyzing NodeBB's codebase using Claude (to use an example) and finding vulnerabilities means I should be paying Anthropic the bounty, not the person prompting Claude. If you spent 10 seconds prompting an LLM and I have to spend 20 minutes verifying that your report is not real, the only person's time wasted is my own.

Some use LLMs as a translation tool, and if this is the case, we will make a good-faith effort to take a look, although we are happy to accept reports in your native language.

Some others use LLMs to structure their reports more professionally. Please just speak to us with your own voice. It is vastly preferable.

10
submitted 3 months ago* (last edited 3 months ago) by to c/nodebb-development@community.nodebb.org
 
 

Nodejs 20.x is almost EOL. Starting with NodeBB 4.11.0 minimum nodejs version required will be nodejs 22.x

11
 
 

Hi everybody,

With spring around the corner (it is currently a balmy 5°C here right now), it's time to get crackin' on a new release of NodeBB!

We focused on a lot of user experience updates this time around, along with tweaking the new /world page that was introduced in v4.9.0. In the backend, lots of optimizations were implemented, which make federation processing (and day-to-day maintenance) faster.

Here's what you can expect from v4.10.0...

:globe_with_meridians: Updates to the /world page

The /world page got a makeover in v4.9.0, showcasing a more timeline-based feel. It more accurately represents the breadth of content available on the open social web, such as microblogging, in addition to long-form text (blogs), media-focused items, and everything in between.

We focused on UX updates to this page:

  • New sorts are available: You can now view just local content, as well as all known content.
  • The default sort continues to be "your followers", but also includes local content now as well, because you are also tracking those categories!
  • Guests were barred from /world in v4.9.0, but this is now opened up again. Their view of the /world page shows only local posts.
  • The /world page can now be set as a default home page.
  • Duplicate items were showing up when scrolling down /world (especially on very active timelines)
  • Uploaded images were showing up in the thumbnail/card headers, even if they were embedded in the post itself. The header is now restricted to topic thumbnails (and post attachments, which only occur with remote posts)
  • Posts are now height-restricted, so long posts don't take up an inordinate amount of space. A "show more" button is available to expand posts in-timeline.
  • The "quick create" editor at the top of this page now also lets you choose a category to post to. Administrators can update the default value as desired. It defaults to World/Uncategorized.

:speech_balloon: Alt Text now federating outward

Alt text was always supported in NodeBB, but this was not federated outward to remote instances. This is now supported for uploaded images and externally-linked images. Topic thumbnails do not support alt text at this time.

:arrow_upper_left: Soft redirects of remote content

Users unfamiliar with NodeBB were often surprised to see their content cached by NodeBB, despite this being how federation works. In order to reduce surprise, any guest navigating directly to a remote post or remote user will be soft-redirected out to the original source. This goes hand-in-hand with the topic-restriction feature in v4.9.0.

:computer: ActivityPub Outboxes published

For ActivityPub developers, we now publish outboxes as of this version.

:frame_with_picture: More profile pics!

@baris improved the avatar handling code so that NodeBB now remembers your last three used avatars, allowing you to toggle between them. You will no longer need to upload new pictures if you want to switch between previously-used avatars!

Follow counts better synchronized

@panos@catodon.rocks reported awhile back that follow counts in user pages were off. The logic was updated and should be back in sync with the real values once you follow/unfollow a user.

12
 
 

Up until today, when you queried a NodeBB user or category's outbox, you would receive an empty OrderedCollection. This was done because the property's inclusion in the actor object was required, but it was not immediately apparent in 2024 how many people utilised this property. Thus it was easier to just send the empty outbox and pursue more urgent functionality.

While sending that empty outbox has not broken any implementations, but it has come to my attention that a few (read: more than 1) other implementors already do, or plans to, read from an actor outbox for backfill purposes.

The upcoming NodeBB v4.10.0 will contain an outbox populated by the contributions by that user or category.

Here's how that works...

For both users and categories, a standard OrderedCollection is returned, with first, last, prev, and next properties for navigation.

For users:

  • A combined set of the user's activity is returned in the form of activities (Create, Like, etc.) — these activities include the user's posts, votes (both up and down), and shares.
  • Unlike other collections, this one uses a cursor. You can pass ?before= or ?after= values in the query string to retrieve items 20 at a time.

For categories:

  • A set of posts curated by this category is shown. It can contain both posts local to the instance, and remote posts from outside of the instance.
  • All posts are wrapped in the Announce activity. If the post is local, it is an Announce(Create(Note/Article)), if it is a remote post, then it is just an Announce(Object) by reference.
  • This collection is paged like other collections served by NodeBB.

It is possible that this implementation serves data in an unexpected manner. If this is the case, please reply here to contact me directly so it can be fixed.

I used my best judgement for what to include in the outboxes, as well as using Piefed as a reference implementation. @rimu@piefed.social, I notice that Piefed's community outboxes serve up Announce(Create(Page)) even if the Page is not local to the instance. I was under the assumption that remote content couldn't (shouldn't?) be expanded in this manner because you cannot guarantee the integrity of the data, and so announcing the object by reference is preferred. Just wondering your thoughts on that.

13
 
 

We are publishing a notice today to bring to attention an unintentional breaking change that could affect some users of NodeBB.

v4.5.0 contained an update to src/request.js that calls a DNS resolver to ensure that the destination address is not a reserved IP address (e.g. 192.168..., 127.0..)

This change was introduced in order to close off any potential for Server-Side Request Forgery for any calls made within the NodeBB codebase.

In the vast majority of installations, this has no unintended effects. In some installations, custom plugins or themes may call URLs that resolve to an internal address on purpose (e.g. to query an internal database or similar.) In those situations, the call will now fail as of v4.5.0.

In those situations, you will need to update the plugin to add the domain to the allow list by calling the filter:request.init hook:

plugin.json

{
  ...
  "hooks": [
    ...
    { "hook": "filter:request.init", "method": "allowInternalHostname" },
    ...
  ]
  ...
}

library.js or similar

const plugin = module.exports;

plugin.allowInternalHostname = async ({ allowed }) =&gt; {
  allowed.add('example.org');
  return { allowed };
});
14
 
 

Hello all!

(Sorry, I could not resist with the title :laughing:)

Today we are releasing NodeBB v4.9.0, on a Friday, toward the end of the day, because we like having our weekends ruined.

As usual, we recommend you update to this stable version of NodeBB, not least because it fixes a federation issue accidentally introduced last month.

There are a bunch of new features and usability improvements here, for both end users and admins. Federation improvements abound, as well as a few moderation upgrades. As usual, we fixed a ton of bugs, and even a couple open issues from the 2010s :scream:

Here is a list of the changes and new features you should expect to see!

:world_map: New "World" page

/world has been updated so that is closer to a feed-reader than a topic list. While I will continue to iterate on this design over time to better promote topics, I am hoping that this proves to be more accessible of an interface compared to the old topic listing.

Your watched/tracked remote categories will be listed in a sidebar (hidden behind a drawer on mobile views) for easy access.

The default view ("Latest") continues to be a list of content from people you follow, and content shared by those same people. The other view ("Popular") shows unconstrained content, and can include content from people you don't follow.

:lock: Remote topics now unavailable to guests

After an Alibaba bot was recorded mercilessly scraping a lot of the public content served up by NodeBB, we decided to restrict access to that content to registered users.

While this would normally mean that "View Original URL" would stop working from other federates sites (since visitors are usually guests), we have added an exclusion to this logic that will continue to serve up the content to guests if at least one local user has commented on the topic.

:writing_hand: UX change for composer and chats

@baris worked on a number of usability fixes that make the experience of using our post composer and chat interface much better. For the longest time we had issues with the composer not properly resizing when mobile keyboards opened.

Composing and replying should work much better now that we are using the latest CSS and javascript tooling to properly detect visual viewport changes.

:bell: Better notifications

@baris also updated the notifications system so that bodyLong, which usually contains post text, is now sent with all notifications. This should increase the usability of notifications (both via web, email, or push).

:arrows_counterclockwise: Cross-posting privilege

A previous release introduced the ability to cross-post content into local categories. This functionality can now be gated behind a privilege at the category level.

:wave: Guest call-to-action

@baris introduced a new guest "call-to-action" banner that will help guide guests toward registering a new account to contribute to your community :blush:

:label: Title-less topics

As part of the changes to /world, we also allow the creation of topics without a title. If you don't pass in a title, we will generate one for you based on the first sentence in your post. The same title generation logic was applied to remote content in the past, and now it also applies to local content.

This also means you can use the /world page to just fire off something quickly without having to do the hard work of thinking up a title. You're welcome :laughing:

:sparkles: Opportunistic backfill

Now that the fediverse's largest implementor, Mastodon, supports context, which enables backfill, we have implemented an opportunistic backfill feature that will check for new replies when you enter a topic. It'll also regularly check the top most popular remote topics known by the instance for new posts.

:no_entry: Reasons

You can now set up a recurring list of "reasons", which you can invoke on certain moderation actions. These custom reasons can be used when a user is banned, muted, or on post queue rejection.

You can set up these reasons from ACP > Manage > Users > (Gear) > Manage Custom Reasons

image (2).png

:information_desk_person: Registration queue now applies for SSO plugins

This issue, open since 2016 is finally fixed. SSO plugins don't automatically bypass the registration queue anymore. This was a common vector for spammers to bypass registration limitations.

:bug: Additional features and bug fixes

  • An improvement to auto-installation of plugins
  • Removed many remote tids and pids stored in the db for no reason (thanks @baris)
  • A regression that caused nodebb-to-nodebb federation to fail (and possibly many others)
  • Notifications can now be passed custom icons
  • ACP privilege selector now no longer shows remote categories
  • Improvements to mentions to better handle periods at end of sentences, or names within names
  • All cached used internally are now exposed in the admin panel for better management.
  • Sitemap cache duration is now configurable
  • Infinite scrolling now works on /world
  • Slug generation errors when you mixed and matched - and .
  • Topic pruning applies to all remote cids now, not just cid -1
  • Chats list updated properly now, when new messages are received, chat messages now properly backfilled upon reconnection
  • NodeBB now federates Delete on both deletion and purge

For the full changelog, please take a look at the closed issues list for this milestone, or take a gander at the much less impressive CHANGELOG.md in our repository root.

15
 
 

Last month I teased a new interface for the /world page, a feed-style interface that attempts to straddle the line between microblog content and threaded content.

That interface is actually live on both community.nodebb.org and ActivityPub.space, so it's possible to try them out today.

Since it's a feed, it does take longer to scroll through than a traditional topic listing. So much so that for me, by the time I get to the end of the page, the things that were on page 1 have been bumped down to page 2, and when the new items load (via infinite scroll) or you go to page 2, it contains stuff you've already seen 😅

One way to handle this is to use an after token, whereby you calculate the next set of items relative to the last item on the page.

That actually does work okay, because when you are infinitely paginating, you can actually muck around with the order of items and nobody is the wiser about it (shh 🤫), as long as you don't repeat any items...

But paginating comes with some expectations about these things... and you also have a physical representation of which page you are on.

It certainly would be a little weird if after reading page 1, you hit "next page", and were suddenly on page 4 because of new content!

NodeBB supports both infinite scrolling and pagination, so any solution needs to take into account the needs of both users.

16
 
 

Coming soon to a NodeBB near you... a new way to browse both microblog and threadiverse content all in one feed. 👀

1000011037.png

17
 
 

Hello from Canada! :flag-ca:

We're a week behind the planned release, but we're dropping v4.8.0 today, containing some changes to our ActivityPub handling, along with a new API route, and bug fixes.

Crossposting

As briefly introduced in my earlier topic on cross-posting, NodeBB v4.8.0 supports cross-posting of topics between categories. More importantly, it means topics from other remote categories can now be added to local categories, which is another way to bring conversations to your local users.

Unlike before, where administrators were the only ones allowed to move topics from cid -1, cross-posting is available to all local users. If you see a topic on the fediverse you'd like to cross-post to a local category, just hit the cross-post button (it's a button with a little upward-right pointing arrow), and share it with other users on your forum!

2283791f-ba05-46fe-af32-4bf4f4915946-image.png

When you cross-post, it also shares the topic with all of your followers from outside of your forum.

cbeadd68-cfd0-4d05-903c-85c8f821b553-image.png

Federated topic moving and removals

This was actually released with v4.7.0 but was improved slightly in the intervening versions. NodeBB now follows the Draft FEP f15d: Context Relocation and Removal and will publish Remove activities when a topic is moved to "Uncategorized", and Move activities when moved to another category.

Developers of other ActivityPub software looking to implement similar mechanics are advised to read the FEP and provide feedback here: https://activitypub.space/topic/86/fep-f15d-context-relocation-and-removal

Other technical debt and bug fixes

  • Post ownership websocket call was migrated to a v3 REST API call
  • Notifications had issues when user display names contained commas
  • Piefed v1.5 supports emoji from remote instances; incoming custom emoji from Piefed are now handled
  • Nodeinfo fixes for if a NodeBB instance is not actually federating (has AP turned off)
18
 
 

Hope everybody is having a great autumn 🍂 — with temperatures slated to drop next week, I suppose it's almost time for winter 🥶

(and yes, I use em dashes. No LLM was used to write this travesty of a release post.)

We've just dropped NodeBB v4.7.0 with some nice QoL improvements for sites federating via ActivityPub.

Security Fixes

Just a note that v4.6.3 contained a dependency upgrade to the validator package that fixes CVE-2025-56200. v4.7.0 contains this fix as well.

New setting to control whether uploaded media is displayed as a topic thumbnail 🖼️

Early changes to better handle ActivityPub content meant that uploaded post content was shown in the topic thumbnails set. This is now a configurable option in Settings > Uploads.

Removal of the "federated description" 💬

We had a small postscript added by default when categories federated outward, and it even came with some default text about mentioning the category to create a topic. It didn't quite work out like we planned, and just looked plain weird when viewed through other threadiverse software (you don't mention a community to create a post in it).

For now I've removed that feature.

A link back to remote categories ↗️

Remote categories now have a button that allows you to navigate directly to the community itself — be it a Lemmy or Piefed community, Peertube channel, etc.

Category boost fixes 🚀

When a topic is moved between categories, the related categories will share (or "Announce" in AP parlance) OP. Likewise, it will be unshared by the other category is no longer belongs to.

N.B. For devs — categories will also federate out Move and Remove activities for the appropriate contexts, which is going to be part of an upcoming FEP the ForumWG is working on.

Improved handling of remote content in chats 😺

When receiving non-public content from remote sources (shown as a chat message), embedded images are now included.

When sending chat messages outside of NodeBB, emoji are now included.

19
 
 

We have released NodeBB version v4.6.3 to address a security issue.

If you discover a vulnerability, please report it responsibly via our bug bounty program.

20
 
 

We have just released v4.6.0 of NodeBB, containing fixes to our ActivityPub integration, minor fixes with SCSS, and some new functionality with topic templating.

:globe_with_meridians: ActivityPub Fixes

  • WordPress blogs can be properly pulled into NodeBB (via their URL) now
  • Fixed an error when moving a remote topic to another category
    • This also fixed the issue where moved topics didn't update topic/post counters
  • Fixed bug where NodeBB could not properly process Link headers when it contained the standalone crossorigin directive
  • Notifications for replies to topics made in remote categories now show the appropriate user
  • Fixed bug where remote users were not able to post to a local category if registered-users privilege was removed (now checks fediverse pseudo-user)
  • Nested remote categories can now be removed from the ACP
  • Remote categories can be renamed for de-duplication purposes
  • Improved title generation for quote-posts

Core fixes

  • Persona theme now shows hidden (zero-character) links in post content
  • _variables.scss page in ACP > Appearance can now override Bootstrap variables
  • A template can be provided in a category's settings. This template is auto-populated in the composer when a new topic is being authored.
21
 
 

Today we released v4.5.0 of NodeBB, which contains a multitude of fixes, refactors, and several new AP-related features.

Dependency Updates :gear:

  • connect-multiparty was replaced with multer for multi-part request body handling
  • ioredis was replaced with node-redis as the former was deprecated with the latter being the recommended replacement

Chat and notification updates :left_speech_bubble:

  • Administrators are now able to toggle the chat join and leave messages in chat rooms
  • Clicking "mark all read" on the notification page now marks only those matching the filter, read

Analytics updates :chart:

  • Page requests from ActivityPub now correctly increment the unique visitors metric

ActivityPub :globe_with_meridians:

  • Top-level posts (OP) federating out now contain a summary of roughly the first 500 characters, instead of sending the entire post content
  • Two-way Relay support (Litepub-style)
  • Auto-categorization logic for incoming post content from remote sources
  • Ability to add remote categories to the forum index
22
 
 

We have released NodeBB versions v2.8.20, v3.12.7, and v4.4.4 to address a security issue.

If you discover a vulnerability, please report it responsibly via our bug bounty program.

As mentioned before, we are going to support 2.x up to August 2025.

23
 
 

We have released NodeBB versions v2.8.19, v3.12.6, and v4.4.3 to address a security issue involving a potential XSS vector.

If you discover a vulnerability, please report it responsibly via our bug bounty program.

As mentioned before, we are going to support 2.x up to August 2025.

24
 
 

There have been some scattered feedback on a change I made for v4.0.0 that caught some people off-guard: Uploaded media is now shown in addition to topic thumbnails.

I'll start with why this change was made, and then solicit feedback.

The why

v4.0.0 introduced ActivityPub integration into NodeBB. This added dimension meant that content was consumed in a manner that was similar, but unfamiliar to NodeBB, and so much of the work involved normalizing that data into a format that made sense. (As an aside, I tell people that that's pretty much 99% of my job — glueing together APIs. I jest, but it's also basically true.)

One of those unfamiliar aspects was uploaded media in the form of attachments. NodeBB had discrete concepts of inline media and topic thumbnails, but attachments were something different entirely. Attachments were not inlined in the text (they tended to be added before or after the main content), and thumbnails were images only, while attachments could be lots of other things.

The second part was that a lot of the content I received relied on media to do the heavy lifting. Oftentimes the text would be minimal and in response to the attachment. After all, a picture's worth a thousand words.

Given those two things, I allowed NodeBB to consume and store attachments separately, and updated the topic thumbnail retrieval logic to pull media from both post attachments and inline media. That retrieval logic is what governs what you see next to the title. I also decided on the all-in approach because while NodeBB has multiple ways of slotting media, majority of ActivityPub software generally only uses attachments. This means both inline media and topic thumbnails were unceremoniously shoved into attachments when federating outward. There is movement toward changing this, and so this rationale may no longer make sense today.

c566206e-7083-4df8-a66f-e765117d2686-image.png

I initially did have concerns that perhaps this would dilute the meaning and specificity of the "topic thumbnail", but I also wagered that the UX improvement of promoting any and all media found would be of greater benefit.

Your turn — feedback!

Maybe I'm wrong!

  • Perhaps the media row is best used to showcase topic thumbnails and post attachments only (not inlined media.)
  • Perhaps a configurable option would appease all folks (although I'm usually loathe to add options purely for that reason.)
25
 
 

We have released NodeBB versions v2.8.18, v3.12.5, and v4.3.2 to address a security issue involving a potential XSS vector and a SQL injection vulnerability. We strongly recommend all users update to the latest patch version for their respective branches:

If you discover a vulnerability, please report it responsibly via our bug bounty program.

As mentioned before, we are going to support 2.x up to August 2025.

view more: next ›