Skip to content

e107 v2.3.13

Latest

Choose a tag to compare

@Deltik Deltik released this 21 Oct 08:02
· 2377 commits to master since this release
v2.3.13

Caution

v2.3.13 is a security release for sites on v2.3.12 or earlier. Upgrade from any 2.x at or below v2.3.12. If your site tracks the master branch, update from master instead: installing v2.3.13 would be a downgrade. v2.4.x is planned to be the next forward step.

Important

Upgrade PHP first, now. PHP 8.5.12, 8.4.27, 8.3.36, and 8.2.35 fix two critical vulnerabilities in PHP itself, CVE-2026-109618 and CVE-2026-109619, that can let an unauthenticated request run code on the server. Every PHP that serves web requests is at risk, whether it runs as PHP-FPM, mod_php, or php-cgi. Upgrade PHP to one of these releases right away, even before you upgrade e107.

PHP 8.1 and older no longer get updates from PHP itself. If your PHP comes from a provider of extended support, such as Freexian or Ondřej Surý, follow that provider's guidance for your PHP version. If you use Remi Collet's repository, PHP's announcement says it will not have updates today, and recommends distribution packages or building from source instead. Until you can update, the announcement lists settings that narrow the exposure. e107 v2.3.13 runs on PHP 5.6 and later.

Then upgrade e107 promptly. This release closes 114 security advisories: 29 Critical, 37 High, 39 Medium, and 9 Low. Security below lists them by area.

Most advisories name a way to narrow the exposure until you can upgrade, such as a setting, a permission to withdraw, or a web-server rule. None of those is a fix.

Before upgrading:

  • If e107_config.php sets $mySQLport, check that your database server listens on it. e107 now connects on that port, where it used to ignore the line.
  • On nginx with PHP-FPM, make sure PHP is told the script's own name, or the web address on pages a named location hands to index.php follows the request. The settings are under Site address and database below.
  • If an alias, symlink, or /~user/ address serves the site from a folder whose name holds anything but ASCII letters, digits, and - . _ ~, rename it to keep e107's cookies to the site. e107 now sets them on the folder above, the whole host when that folder is at the root, where other applications receive them. Visitors signed in before the update sign in once more.

After upgrading:

  1. Run the core database update in Admin » Database » Check for Updates. It switches the discontinued CHAP login setting off, removes a dead "Registered Members" entry from the search settings, and removes duplicate ban rows, then allows one per address and type.
  2. Run the forum plugin's update when the admin area offers it, then check the edited posts it counts, with the query under For Administrators » Changed » Forum.
  3. Delete e107_plugins/faqs/controllers/ if it is still on disk, then run the FAQs update in Admin » Plugin Manager. Run its other updates too, such as the PM plugin's 3.2.
  4. If caching is on, clear the cache once in Admin Area » Settings » Cache.
  5. If your site defines e_HTTP_STATIC, clear your CDN's cache.
  6. If e107_config.php has no site_path and files saved since v2.3.4 are missing, merge the folder marked Known bad, as For Administrators » Fixed » Site address and database describes.
  7. Check content stored before the upgrade:
    • re-save what an untrusted HTML author could have changed, which each advisory's read-only queries find;
    • review the stored link addresses, which are kept even where they start javascript:;
    • open and save each mailout that uses an email template, or its shortcodes show as typed;
    • check downloads made from uploads, and uploads still waiting in Admin » Public Uploads, for { in their name, description, or author website or email, where a shortcode still runs.

Warning

Some of these fixes change behavior you may be relying on. All but the last group close a way to attack a site. For Administrators » Changed has the details under each area's name; plugin and theme items are under For Developers » Changed.

For site owners:

  • To prevent cross-site scripting (XSS), where someone's text or link runs script in a reader's browser:
    • HTML saved by an author who may not post script (on a site installed since 2.3.0, everyone) loses its data- attributes when next saved, so a page relying on data-toggle stops working. If you trust the author, let them post script in Admin » Preferences.
    • Shortcode parameters in content arrive with quotes, angle brackets, and { as entities, so a key=value reader such as {URL=search|q=O'Brien} gets its value cut at the quote. Shortcodes in templates are unaffected.
    • Link fields refuse a new javascript:, vbscript:, or data: address, or one starting with a shortcode other than an {e_…} folder, unless you may post script. A heading that goes nowhere takes #.
    • Some unusual bbcode and markup, such as a block bbcode inside an HTML attribute, now shows as typed. Move the bbcode out of the HTML tag.
    • Forum thread names render only inline bbcode, such as bold and color, and where uploads allow SVG, an SVG attachment is offered as a download.
    • List New Items shows bbcode in headings as typed.
    • comment.php now sends its answers as application/json, so a theme or plugin script that parses them itself stops posting or moderating comments until that theme or plugin is updated.
  • To stop a member's text from running the site's shortcodes, one of which could read the database:
    • Shortcodes run only in text an administrator wrote; a member's approved news, an FAQ question, or a forum post in a notification shows them as typed. To run them in an approved news item, make an administrator its author.
    • A news menu's order setting must name columns, such as n.news_datestamp DESC; any other value sorts newest first.
  • To keep administrators, moderators, and visitors to what they were granted:
    • Admin lists check each action against its permission, so a delegated administrator may be refused an inline edit, sort, batch, copy, or delete; pages and menus take separate permissions. Grant the permission the action needs.
    • With the classes "Set a default user hierarchy" builds, a forum moderated by Admins and Mods loses the administrators outside that class, and one moderated by Main Admin keeps only main administrators; members of classes that inherit a moderator class now moderate too. Add an administrator to Admins and Mods to keep them moderating.
    • Forum permissions hold on the server, so a new topic needs Thread Creation Class and Post Permission both, and a sub-forum is closed to whoever its forum is closed to. Clear the Sub-forum setting of one meant for a wider audience.
    • Stored social login provider settings only a site's own code should set, such as an adapter class, a log file, or curl options, are ignored.
    • Deleting, converting, rotating, or resizing a Media Manager item leaves a file outside the media folder in place, including files the 1.x upgrade listed from e107_images and e107_files. Remove those by hand if you meant to.
  • To stop a link from another site acting through a member who signs in:
    • A members-only site sends a visitor whose remembered query held %, +, or / to the front page after sign-in.
  • To make sure social login is talking to the real provider:
    • Hybridauth 3.13.0 checks the provider's TLS certificate (OpenID 2.0 providers such as Steam aside), so social login fails on a host without a usable CA bundle, where plugin downloads already fail. Installing one fixes both.
  • Bug fixes that change what you see:
    • A forum [hide] block now opens to a signed-in member who can view the forum and has posted in its thread; none ever opened before.
    • In news and pages, an [img] of a site file outside the Media Manager is resized to the Default Image Sizes, 300 by 300 on a new install, where it used to arrive full size. Change them in Admin » Media Manager » Preferences.
    • Shortened text now counts characters, so Chinese, Japanese, or Korean text shows twice as much.

For plugin and theme authors, any row of the Behavior changes table under For Developers » Changed may matter; these most:

  • Fatal: the global GuzzleHttp\Psr7\* functions and bbcode_shortcodes::renderEmotes() are gone, and on PHP 8 front-end code that relied on e_pref::save() defining admin phrases hits undefined constants.
  • Plugins that save comments of their own type, search comments, or post admin options or inline edits their screen does not declare may stop saving or showing them, and a script that parses comment.php's answers itself may stop working.
  • Plugins that rely on a database session of their own, make requests where curl cannot be limited to HTTP and HTTPS, send templated email, save text on another user's behalf, find their own cache files by name, list forums for a visitor who may view none, or read a refused social sign-up's message may behave differently.
  • Themes and templates that pass markup, constants, or addresses to core's shortcodes, put constants other than folder paths in HTML attributes, lean on core's show-more, pop-up, Ajax, or rating links, draw their own required-field asterisk, bundle Bootstrap older than 3.1.0, or style bootstrap5's Font Awesome SVGs may display differently.

Highlights

  • Most pages are built in about half the time. On a stock site, on PHP 8.2 and 8.5, v2.3.13 takes 30% less server time than v2.3.12 for the front page, 45 to 60% less for other public pages, and 30 to 68% less in the admin area, with one database connection per page instead of five to eight. A heavier page saves about as many milliseconds, a smaller share. (#6704, #6696, #6724, #6697, #6732)
  • Regression fixed: logout links work again. Since v2.3.12, a logout link without a security token, in a theme, a bookmark, or Site Links, left the member signed in with an error. It now asks "Are you sure you want to log out?", and Navigation offers Logout as a predefined link. (#6741, #6753)
  • Sites with no site_path are back on their own media and system folders. They saved uploads, backups, and logs under a stray folder; the dashboard links to the merge. (#6498)
  • Uninstalling a plugin that declares comment types no longer deletes every comment on the site. Its own comments now go only when its tables do. (#6780)
  • An & stays an &. Since 2.2.0, text saved by anyone outside "Class which can post HTML" showed & for a typed & (older text until re-saved), and a bbcode link or image to ?a=1&b=2 lost its second parameter. (#6791, 94ef3d1ae4, 73227b2392)
  • Social login runs on Hybridauth 3.13.0, checks the provider's TLS certificate (OpenID 2.0 providers such as Steam aside), and offers LinkedInOpenID, OktaOIDC, and X. (#6372)
  • A page that cannot send its email now says so. The contact form, account removal, and most admin test emails reported success either way. (#6743)
  • Regression fixed: the FAQ page no longer sends visitors to the admin login. On v2.3.12, /faqs could open the admin area instead. (#6502)

Security

An "HTML author" below may post HTML but not script: on a new install, any administrator.

BBCodes and posted HTML

Advisory Severity What it was
GHSA-j4jr-2rjm-rmpq 9.9 Critical A member's [video] could run script for every reader with no click, administrators included.
GHSA-948v-m8j8-77vm 9.9 Critical A member's [glyph] could run script for every reader with no click, administrators included.
GHSA-x3h8-x4r6-mc6x 9.0 Critical A member's comment or forum post could run script for forum topic visitors, or for an administrator opening the admin comment list.
GHSA-pggp-3p94-5mpc 9.0 Critical A member's bbcode inside a [table], [hide], or [html] block, such as in a signature, could run script for every reader.
GHSA-m88q-h57q-w28x 9.0 Critical A forum member's image caption could run script for a moderator or administrator who opened the post to edit it.
GHSA-9jr4-3wxc-m2cm 9.0 Critical A member's [file] could carry a script link that ran for whoever clicked it.
GHSA-x2x3-xr6p-4xc2 9.0 Critical A member's [url] or [link] could get a script address past the link check through an e107 path constant.
GHSA-frc7-3r8j-5pw3 9.0 Critical A member's [img] thumbnail could carry a script link that ran when clicked in comments paged in with Next.
GHSA-pr63-vf44-2whp 9.0 Critical A forum member could run script for every reader of a thread with a quote in its title, through {e_PAGETITLE}.
GHSA-hgqv-65ww-wq7p 8.5 High Under a Turkish or Azerbaijani locale, an HTML author could keep a script address in a link or frame.
GHSA-cmcq-6m83-2w77 8.4 High An HTML author could turn a quote inside an attribute into an event handler that ran for every reader.
GHSA-28qc-h8v2-55rf 8.4 High An HTML author could put a bbcode inside an HTML attribute that added script for every reader.
GHSA-x3v9-7pgp-6c4f 8.4 High An HTML author could make a tag inside an [scode] block, or a malformed [code] block, run script for every reader.
GHSA-8j93-fv53-8498 8.4 High An HTML author could hide markup in an HTML comment that escaped the cleaning and ran for every reader.
GHSA-fhp6-g58h-v9w3 8.4 High On libxml2 before 2.15, an HTML author could hide markup in a processing instruction, running for every reader.
GHSA-vj2h-r54v-2533 8.4 High On libxml2 2.14 or later, an HTML author could hide tags in an iframe's text, running for every reader.
GHSA-xj8c-p924-m7pq 8.4 High An HTML author could end a bbcode tag inside an HTML tag or comment, turning the text after it into script.
GHSA-53pg-w64x-rch7 8.4 High An HTML author could hide markup in an editor-inserted bbcode element, running for every reader.
GHSA-rqf5-2crw-v646 8.0 High With clickable links opening in the same window (not the default), a member's plain-text script address became a link that ran when clicked.
GHSA-46mx-667v-9hwp 8.0 High On PHP before 8.2 under a Turkish or Azerbaijani locale, a member's [url] or [link] could get a script address past the check.
GHSA-2x4v-8xq6-mp82 8.0 High An HTML author, or a member whose news submission was approved, could run script through a shortcode inside an HTML attribute.
GHSA-wpp9-c4vh-p9fq 6.8 Medium A member's bbcode image or link could send each reader's security token to another site, enabling token-protected admin actions.
GHSA-j5mj-c54p-ccw8 5.0 Medium A member's [img] could make the server list any folder it could read, outside the website included, or an FTP server's.
GHSA-33g6-fqff-2w9p 4.4 Medium A member not allowed to post HTML could get working HTML into RSS feeds and forum subscription emails.

Flowchart of how a post becomes HTML in e107 2.3.13. When it is saved, an author who may not post HTML has tags removed and an ampersand stored once, while an author who may post HTML has every tag and attribute vetted, and a quote inside an attribute value is stored apart from the markup's own quotes. When it is shown, in this order: text inside comments and iframes is made inert; block bbcodes written inside an HTML tag stay as typed; hide blocks are set aside for the readers allowed to see them; a bbcode tag that ends inside HTML stays as text; bbcodes inside an attribute are encoded for that attribute; link bbcodes check the scheme and encode once; and shortcodes run only where allowed, with inert parameters. The result is the HTML sent to the browser.

Links and controls in posted HTML

Advisory Severity What it was
GHSA-7w79-c68w-m3hq 9.1 Critical An HTML author could run script in readers' browsers through data- attributes, some needing no click.
GHSA-x99q-r9j9-wr88 8.4 High An HTML author could make a show-more link run script for whoever clicked it.
GHSA-4chr-7w3m-mqq3 8.4 High An HTML author could make a pop-up link run script for whoever clicked it.
GHSA-8cw5-vrrm-639v 8.4 High An HTML author could make a comment edit button run script for whoever clicked it.
GHSA-8698-q2q9-x4xm 8.4 High An HTML author could make a rating run script when a signed-in reader hovered over it.
GHSA-5hp5-4669-q626 8.4 High An HTML author could write a link that fetched script from another site and ran it on one click.

Two checks stand between the markup of an author who may post HTML but not script, which on a new install means every administrator, and a reader's browser. First, when the text is saved, script tags and event handlers are removed, as before, and data- attributes are now removed too. The text is stored as a page, news item, or post. Second, when core's page script reads a link, four checks are new in 2.3.13: show-more and comment edit look their target up as a selector only; a modal pop-up opens only an http, https, or relative address; e-ajax fetches only from this site and takes back only a page or JSON; and modal captions and rating status are written as text.

Forum

Advisory Severity What it was
GHSA-39qm-9c2q-qvwp 9.6 Critical A forum post's attachment list could be read back naming files its poster never uploaded, so a guest could make the forum serve another guest's attachment.
GHSA-m95h-mp65-826r 9.6 Critical A visitor posting without an account could give a name that ran script for everyone shown it.
GHSA-6m74-6r8m-92wx 9.0 Critical A forum poster could name an attachment so that it ran script for the topic's readers.
GHSA-c32r-5vgh-pxmg 9.0 Critical A thread's starter could edit its title to run script for everyone shown it.
GHSA-x3x6-97h2-7xp4 9.0 Critical A member could name a thread so that it ran script when an administrator opened its report.
GHSA-hj5v-m79p-4cjq 9.0 Critical A member could edit their own post to run script for everyone who opened the topic.
GHSA-4h6f-79jg-c8fw 9.0 Critical A member's post could run script in the editor of an administrator who quoted or edited it.
GHSA-cr4j-g226-94fx 9.0 Critical A code in a thread's name could run script for everyone who opened its forum.
GHSA-gmxq-j944-84rf 6.5 Medium A moderator of one forum could act as one in other forums.
GHSA-h763-2g75-85x2 6.5 Medium A member who may post in a forum but not view it could read its posts.
GHSA-3qc7-83pq-gf73 5.4 Medium A member who could start a thread could overwrite any poll on the site.
GHSA-6qr8-c9rm-jc72 5.3 Medium A visitor allowed to view no forum was shown the whole forum index.
GHSA-cj4m-q95v-98c6 5.3 Medium Anyone could learn the titles of threads in forums closed to them.
GHSA-3w6f-q2fp-3qcm 5.3 Medium A forum's page named the sub-forums in it that were closed to the visitor.
GHSA-f6wf-9rgv-v6m5 5.3 Medium The forum search named every forum to any visitor, admin-only ones included.
GHSA-835r-q7wf-499j 5.3 Medium A forum moderated by a class in a class tree gave moderator powers to the wrong users.
GHSA-9qxp-m7jg-9xwf 4.3 Medium A member could quote a post into any open thread, even one in a forum hidden from them.
GHSA-xj38-4v6m-2c83 4.3 Medium The author of any reply could rename its thread and unpin it.
GHSA-pg3x-w47r-26c2 4.3 Medium Members could start topics in forums where only staff may start them.
GHSA-hg7j-grmq-hwwv 4.3 Medium A moderator could split posts into a forum they do not moderate.
GHSA-fr3x-g52f-pg45 3.1 Low A member could save a post to a forum or thread their permission was not checked against.

Comments, search, and List New Items

Advisory Severity What it was
GHSA-vfc3-x99c-2j47 9.6 Critical Anyone could craft a comment.php link that ran script for whoever opened it while signed in.
GHSA-g7rc-4jvq-27m9 9.6 Critical Anyone could send a link that ran script, through the advanced search's Author field, for whoever opened it, administrators included.
GHSA-7232-gr39-h92m 9.0 Critical A member's thread name, comment subject, or chatbox message could run script on List New Items and its menus.
GHSA-96vv-8fmj-6xfq 5.3 Medium comment.php showed visitors the titles and comments of items their own pages withheld.
GHSA-c3hr-jgwg-r7xv 5.3 Medium The latest comments menu showed comments left on password-protected pages.
GHSA-58j5-4h2g-fh4c 5.3 Medium The comments search showed anyone comments, with the item's title, on news items and downloads they could not read.
GHSA-xpgr-mpvw-m63w 5.3 Medium The comments search showed comments an administrator had blocked or not yet approved.
GHSA-2rfr-36m8-hjc2 4.3 Medium A member could page through the comments of items they may not read.
GHSA-xf8f-w5mv-hcg3 4.3 Medium A member could post comments onto items they may not read.

Shortcodes in pages, FAQs, and lists

Advisory Severity What it was
GHSA-ff9g-2q9w-43gh 9.6 Critical Anyone could send a link to an admin list or a search whose page links ran script for whoever opened it.
GHSA-prf8-95f7-7q86 9.0 Critical A member's news submission approved unedited, or any page, news item, or FAQ question, could run script for readers through shortcode parameters.
GHSA-xpfc-85q6-4659 8.0 High A page or FAQ question naming {IMAGESELECTOR} could run script when a reader picked an image.
GHSA-hxpw-337x-cj7g 8.0 High A page or FAQ question naming {IMAGESELECTOR} could make its preview link run script on a click.
GHSA-6r9c-6jvj-5wrp 8.0 High Another website could run script in an administrator's browser through any page whose text names {IMAGEPREVIEW}.
GHSA-mc79-4frh-x2p7 8.0 High A page or FAQ question naming {UPLOADFILE} could run script when a reader clicked Add Another File.
GHSA-994c-jv82-j79r 5.9 Medium A member's news submission, once published, could send each reader's security token to another site.
GHSA-55xx-wjmc-63jc 5.4 Medium A page or FAQ question naming {BREADCRUMB=...} could print markup from a crafted link, running its script.

Admin area

Advisory Severity What it was
GHSA-r42m-hch3-vg4g 9.6 Critical A crafted link could run script in a signed-in administrator's browser through the PHP Errors debug panel, even with debugging off.
GHSA-fmrc-cg23-8fmv 9.6 Critical A crafted link to the news page could run script in a signed-in administrator's browser through its debug table, even with debugging off.
GHSA-q899-38jg-q5hm 9.6 Critical A crafted link could run script in a signed-in administrator's browser through the Shortcodes / BBCode debug panel, even with debugging off.
GHSA-pwhr-95w9-f629 9.0 Critical A member's comment, signature, or submitted news could run script for an administrator who opened it for editing.
GHSA-v773-ph53-fmx6 8.4 High An administrator limited to pages could run script for the main administrator through a page title in an admin list.
GHSA-p622-mg4c-fpc6 6.8 Medium An administrator who may manage users could read every account's password hash from the user list's search suggestions.
GHSA-g676-96h8-qgv5 6.0 Medium A delegated administrator could make an admin form write a row it never loaded, such as the main administrator's account.
GHSA-r7xc-wvxg-23j5 5.5 Medium Any administrator, whatever permissions they held, could change any site preference through an admin page's options.
GHSA-h657-rx62-qm6j 4.9 Medium An administrator holding any news permission could rewrite news items inline and reorder every news category.
GHSA-ccrh-5wjq-72mq 4.4 Medium An administrator holding only the news category permission could rewrite any news item by front-end inline editing.
GHSA-78j8-h8ww-p8wf 3.3 Low On PHP before 8.2 under a Turkish locale, a delegated administrator could reach an admin route its permission refused.
GHSA-3cjg-6rq3-m3qr 2.7 Low An administrator allowed only to manage bans could change the ban messages and durations reserved to the main administrator.

Site links, pages, and menus

Advisory Severity What it was
GHSA-2vhc-52q2-2j5f 8.4 High An administrator limited to one area, such as Navigation, could save a javascript: link that ran for whoever clicked it.
GHSA-fm7r-8pvc-x36q 8.4 High An administrator limited to Navigation could add a popup link whose address ran script for whoever clicked it.
GHSA-8wmw-xrxv-hvrm 8.4 High An administrator limited to pages could put script in a chapter's custom field settings, run when the main administrator edits one of its pages.
GHSA-fhcg-cf34-cg8h 8.4 High An administrator limited to the hero plugin could put script in a slide's bullets or buttons, run for every home page visitor.
GHSA-c8wm-82cq-3qj2 8.4 High An HTML author could plant a menu link that, clicked in the Menu Manager, ran another site's script as the administrator.
GHSA-chxg-8grm-hpmq 8.0 High With screentips on, a link description could run script for every visitor of a theme using the older {SITELINKS} menu.
GHSA-86rc-hq8m-mwwr 7.6 High An administrator limited to pages could put script in a custom page field, run for anyone viewing a layout that prints it.

Media Manager and uploads

Advisory Severity What it was
GHSA-3gqj-7q5v-m8wg 9.6 Critical On sites with public uploads switched on, an uploader could run script in the browser of an administrator reviewing Admin > Uploads.
GHSA-7xc8-m3cv-mq65 7.2 High An administrator could store a Media Manager upload under a file type the site does not allow to be uploaded.
GHSA-v6mf-xx46-236j 3.8 Low An administrator with Media Manager access could move a file from elsewhere on the server into the public media folder.
GHSA-3c5x-q658-vx68 3.8 Low An administrator with Media Manager access could delete or overwrite files outside the media folder.
GHSA-69r3-7r4c-6gmw 3.8 Low An administrator with Media Manager access could delete files outside the avatars folder.
GHSA-w39w-6mq9-p36q 2.7 Low An administrator with Media Manager access could import a file into folders outside the media folder.
GHSA-768c-62jm-23j8 2.7 Low An administrator with Media Manager access could change a database query with a quote in a file's name.

Downloads, FAQs, and news menus

Advisory Severity What it was
GHSA-cx6q-399j-w6fw 9.0 Critical A download's name, set by a downloads administrator or an accepted public upload, could run script for an administrator opening its edit page.
GHSA-hhh4-9hgp-84w8 8.4 High An administrator who manages downloads could give a mirror an address that ran script for any administrator opening that download's edit page.
GHSA-7hgq-9836-h28c 8.0 High Where members may ask FAQ questions, an answered question could run script, through its share buttons, for everyone opening the FAQ page.
GHSA-x33v-p7mw-q88f 5.7 Medium Anyone who could get a {MENU} shortcode into displayed text, such as an answered FAQ question, could read the database through a news menu.

Social login

Advisory Severity What it was
GHSA-45hh-fwg8-24j2 8.4 High An administrator holding only the social plugin's permission could run script on every page through a social page address.
GHSA-2vgc-f528-4vvf 8.4 High An administrator holding only the social plugin's permission could run script in other administrators' sessions, the main administrator's included, through a stored provider or file name.
GHSA-gg38-5hqf-7h6r 7.6 High An administrator holding only the social plugin's permission could run script through the Facebook app id on pages that load Facebook's SDK.
GHSA-q9p8-h9h3-r5v5 6.1 Medium When social login has an OpenID provider enabled, anyone could write a sign-in link that put their script on the page a visitor lands on.
GHSA-p4fv-hmmr-38p8 4.9 Medium An administrator holding only the social plugin's permission could make social login read files on the server, e107's configuration file included.
GHSA-mg3f-xg6g-g3pc 3.8 Low An administrator holding only the social plugin's permission could choose the classes, files, and servers social login uses, and what it unserializes.

Sign-in, sign-up, and requests from other sites

Advisory Severity What it was
GHSA-6mxv-9x4j-8rhr 8.3 High On some nginx and PHP-FPM setups, a crafted link could rewrite the link and stylesheet addresses on a page and run script for whoever opened it.
GHSA-g2gx-997c-mc67 7.1 High Any page an administrator visited could make the plugin manager install, repair, or upgrade a plugin by hiding a made-up token from e107's check.
GHSA-wjmf-r4mf-m9vg 6.5 Medium On a site at the root of its host, a crafted link could make the navbar sign-in form send a visitor's username and password to another host.
GHSA-cvhc-885w-mm2m 6.5 Medium Where the signup form's Password field was set to Hide, anyone could replace the password of an account still awaiting activation.
GHSA-93ff-wc89-mhjf 6.3 Medium On an HTTPS site, any member could set a profile picture that made an administrator's browser carry out admin actions, such as installing a plugin.
GHSA-6wf7-qwj9-hr3r 5.9 Medium A page on a neighboring subdomain could make an administrator's browser carry out admin actions, such as installing a plugin.
GHSA-hq36-v99x-77g4 5.9 Medium A neighboring subdomain could choose the page an administrator landed on after signing in, and make that page carry out an admin action.
GHSA-9mrp-hhpm-ph93 5.3 Medium The activation resend form showed anyone the email address of an account awaiting activation, given only its user name.
GHSA-p8q2-x72j-8mvj 4.3 Medium With friendly URLs on, a link from another site could make a signed-in member carry out a front-end action, such as blocking a message sender.
GHSA-9f6g-4wp7-whmj 4.3 Medium A link from another site could make a member who then signed in on that page carry out its action, such as blocking a message sender.

For Administrators

Added

  • Navigation offers Logout as a predefined link, which logs out at once. Choose Logout under "Predefined link", or write index.php?logout&e-token={E_TOKEN}: e107 fills in each visitor's token, in navigation links only. (#6303)
  • A logout link without a security token now asks "Are you sure you want to log out?" instead of refusing. Since v2.3.12 such links, in themes, bookmarks, and Site Links, left the member signed in with an error. Cancel returns to the page they came from if it is on this site, or to the front page. (#6741, #6753)

Changed

BBCodes and HTML

  • Shortcodes now run only in text an administrator wrote. News titles and bodies, poll titles, news feeds, and notification emails with a user's text run them only for a current administrator author; others show them as typed. FAQ questions and forum posts in notifications never do. (080505b260)
    • An approved news submission keeps the member as author. Make an administrator its author for them to run.
    • A mailout with an email template saved before you upgrade shows its shortcodes as typed until you open and save it again.
    • Downloads made from uploads before 2.3.13, and uploads still waiting, can still run shortcodes in their name, description, or author website or email. Check those for {.
  • Shortcode parameters in content receive quotes, angle brackets, and { as entities. Pages, news, and other stored text are covered; templates are not. A shortcode reading key=value pairs, such as {URL=search|q=O'Brien}, now gets its value cut at the quote. (GHSA-prf8-95f7-7q86)
  • HTML saved by an author who may not post script now loses its data- attributes. A page or news item relying on data-toggle stops working when next saved; stored content is not changed. Since 2.3.0 a new install lets no one post script, main administrators included; choose who may in Admin » Preferences. (GHSA-7w79-c68w-m3hq)
  • Re-save content an untrusted HTML author could have changed. Content saved before the upgrade keeps what the old cleaning let through; each advisory has read-only queries to find it. (GHSA-cmcq-6m83-2w77, GHSA-fhp6-g58h-v9w3, GHSA-hgqv-65ww-wq7p)
  • Some unusual bbcode and markup displays differently. (GHSA-28qc-h8v2-55rf, GHSA-xj8c-p924-m7pq, GHSA-x3h8-x4r6-mc6x)
    • Inside an HTML attribute, a [code], [scode], [table], [html], or [php] block shows as typed, and another bbcode shows its HTML as text.
    • A [hide] block that opens inside an HTML tag and closes outside it shows, as typed, to every reader.
    • A bbcode tag whose ] falls inside an HTML tag or comment shows as text, and such a [hide hides nothing.
    • Shortened text counts characters, so Chinese, Japanese, or Korean text shows twice as much.
  • Local images in news and pages are now resized. An [img] of a site file outside the Media Manager asked for its thumbnail with a broken size, so it got the full-size file. It now follows the Default Image Sizes (300 by 300 on a new install). (73227b2392)

Forum

  • After updating, run the forum plugin's update when the admin area offers it. It changes no post, but counts edited posts holding markup their author or last editor may not post; some may be legitimate HTML. Check those whose post_user or post_edit_user may not post HTML, without viewing them on the forum as an administrator. If the author may not post HTML, saving the post from Edit strips it; fix the rest in the database. (GHSA-hj5v-m79p-4cjq)

    This read-only query lists every edited post holding <; the posts to check are among them (adjust the e107_ prefix):

    SELECT post_id, post_thread, post_user, post_edit_user FROM e107_forum_post
    WHERE post_edit_datestamp > 0 AND post_entry LIKE '%<%';
  • Forum moderators are the users who hold the moderator class, including members of the classes that inherit it. On the tree "Set a default user hierarchy" builds, a forum moderated by Admins and Mods is now moderated by its members and the main administrators, no longer by every administrator; add an administrator to Admins and Mods to keep them moderating it. A forum moderated by Main Admin is now moderated by main administrators alone, who moderate every forum. (GHSA-835r-q7wf-499j)

    Table beside the tree "Set a default user hierarchy" builds, which runs from No One (inactive) to Main Admin, then Admins and Mods, then Admin; a member of a class also holds every class below it. A forum whose moderator class is Main Admin was moderated in 2.3.12 by every administrator and every Admins and Mods member, and in 2.3.13 by main administrators only. A forum moderated by Admins and Mods was moderated by every administrator and every Admins and Mods member, and is now moderated by Admins and Mods members and main administrators. A forum moderated by Admin is moderated by every administrator in both versions. Main administrators still moderate every forum, whatever class moderates it.

  • A new topic needs Thread Creation Class and Post Permission both. (GHSA-pg3x-w47r-26c2)

  • A forum a member may post in but not view takes no posts from them. (GHSA-h763-2g75-85x2)

  • Only an opening post's edit renames a thread, and a non-moderator's edit no longer unpins it. (GHSA-xj38-4v6m-2c83)

  • Split and move list only forums the moderator moderates and can view. (GHSA-hg7j-grmq-hwwv)

  • "Enable polls for" refuses a poll, not just its form. It ships set to No One. (GHSA-3qc7-83pq-gf73)

  • A sub-forum is closed to whoever its forum is closed to, whatever its own Visibility says. Clear the Sub-forum setting of one meant for a wider audience. (bf9538c730)

  • A [hide] block opens for a signed-in member who can view the forum and has posted in its thread. None ever opened before, so every stored block now opens to them. Hidden text also stays out of the RSS feed and the latest forum posts menu. (#6782, f28d0802aa)

  • Thread names render only inline bbcode, such as bold, color, and size; other bbcode keeps only its text, and HTML stored in a name shows as typed. (GHSA-c32r-5vgh-pxmg)

  • Where uploads allow SVG, an SVG attached to a forum post is offered as a download, not shown as a picture. (#6748)

Comments and List New Items

  • If posting or moderating comments stops working after the update, a theme or plugin script needs updating, as comment.php now sends its answers as application/json. Sites defining e_HTTP_STATIC should clear their CDN's cache. (GHSA-vfc3-x99c-2j47)
  • List New Items prints headings and info lines as each section built them. BBCode or shortcodes in a heading show as typed, as does chatbox bbcode. (GHSA-7232-gr39-h92m)

Admin area

  • Admin lists check each action against its permission, so a delegated administrator may be refused where a list let them through. (#6443, GHSA-g676-96h8-qgv5, GHSA-h657-rx62-qm6j, 2aa750e4e4, e8fd7337e2)
    • Inline edits, sorting, and batch changes need the edit permission, a copy the create permission, a delete the delete permission. Without edit, inline editors are not drawn, FAQs aside.
    • Batch Copy, Export, Create Navigation Link, and Create Featurebox Item run only where offered, the last two also needing the Navigation or Feature Box permission.
    • A batch skips rows the list no longer shows, and says how many. A delete posted for a row the list does not show answers "Deletion Unsuccessful".
    • Lists sharing a table stay apart, such as user ranks and failed logins. The old user ranks editor needs the ranks permission.
    • Custom pages and menus are separate. Of the two permissions labeled "Pages/Menus", 5 covers pages and chapters, J menus; deletes need J1, page options the main administrator.
  • Holders of the Theme Manager permission now see its whole menu. Upload Theme, Tools, and the rest were hidden, though each opened by address. The permission now reads "Theme Manager", without "(Preferences)". (#6274, #6428)
  • With sessions kept in files, the dashboard no longer makes your next page wait while it contacts e107.org. The add-on update notice is kept site-wide, refreshed after a plugin upgrade or uninstall, a site theme change, or a cache clear. (#6700)

Site links, pages, and menus

  • Link fields refuse a javascript:, vbscript:, or data: address, or one starting with a shortcode other than an {e_…} folder, unless you may post script: Navigation, social links, Custom Button URL, custom page URL fields, Linkwords, download mirrors, feature box images, hero buttons, and public uploads. Stored addresses are kept, so review yours; a heading that goes nowhere takes #. (GHSA-2vhc-52q2-2j5f)

    Flowchart of saving a record with a link field in e107 2.3.13. Anyone in the class that may post script saves it. For anyone else, an address that is the stored one, unchanged, is saved. A new or changed address is saved unless, once decoded, it starts with javascript:, vbscript:, data:, or a shortcode. Then the save is refused: nothing is saved, and the form names the field and the reason. An inline edit shows the same reason and leaves the cell as it was.

  • Custom page fields and hero slides no longer run script their author may not post. Field values and hero bullets saved before 2.3.13 keep their formatting but lose script and event handlers, with no re-save, except icon, tag, checkbox, and progress-bar values, which show HTML only when saved by someone who may post script. Where you narrowed who may post HTML, kept formatting can include some their author may not post. Old field labels and hero buttons show HTML as text until changed. (GHSA-86rc-hq8m-mwwr, GHSA-fhcg-cf34-cg8h)

  • With caching on, a fragment holding a visitor's security token is not cached, so the comment form is built fresh. Clear Admin Area » Settings » Cache once after upgrading. (#6307)

Sign-in and accounts

  • The activation resend form gives every request the same answer, and mails an account at most once every ten minutes. A repeat sends nothing unless the last email failed, and the email carries no new password. (#6519, GHSA-cvhc-885w-mm2m)
  • CHAP login is discontinued, along with the Password transmission method setting. With CHAP on, the admin login form never submitted, and since v2.3.12 that included sites upgraded from cookie mode. Passwords are now checked as typed. The core database update switches the old setting off, so an old theme login template stops hiding its form. (#6653)
  • After signing in, a visitor is returned only to an address with no security token and a plain query. The login menu drops a query holding a token or anything but letters, digits, and _ . , : = & -. The address remembered for after sign-in now comes only from the session, so a members-only site sends a visitor whose remembered query held %, +, or / to the front page. (GHSA-9f6g-4wp7-whmj, GHSA-hq36-v99x-77g4)

Social login

  • Social login now ignores stored provider settings that only a site's own code should set. The social plugin saves provider settings only under names Hybridauth supports. Telegram's form no longer offers a callback field. Nothing stored is rewritten; a social sign-in in progress during the upgrade may have to start over. (GHSA-mg3f-xg6g-g3pc, GHSA-p4fv-hmmr-38p8)

    The Configured Login Providers save stores only a provider that Hybridauth supports. When e107 builds each provider from its stored settings, it drops the adapter class, the debug mode and log file, curl options, tokens, endpoint addresses, the callback, authorization parameters, and a key file named by an address (one containing ://). e107 sets its own callback address, logs errors to hybridAuth.log, and keeps requests to HTTP and HTTPS, redirects included, except an OpenID 2.0 provider's. Keys, scope, and every other setting the form saves are passed on as stored. Hybridauth gets the result, and its session values are kept as they are, never unserialized.

  • Social login checks the provider's TLS certificate, except for OpenID 2.0 providers such as Steam, and offers LinkedInOpenID, OktaOIDC, and X. The bundled Hybridauth is now 3.13.0. A host without a usable CA bundle, which already fails plugin downloads, now fails social login too. (#6372)

  • Signed-in pages no longer load the social login library just to ask whether social login is on. Answering used to parse every bundled provider file on every signed-in page, even with social login off. (#6514)

Media Manager

  • The Media Manager now touches files only inside its own folders, and says when it keeps one. Deleting a media item, or converting, rotating, or resizing it from the list, leaves a file outside the media folder in place and says it "lies outside the media folder, so it was kept." That covers theme, plugin, and core images, and files the 1.x upgrade listed. The Avatars page's Delete Checked does the same for the avatars folder. Imported files are stored under their cleaned names, and an upload renamed to a type that may not be uploaded is removed. (GHSA-3c5x-q658-vx68, GHSA-69r3-7r4c-6gmw, GHSA-w39w-6mq9-p36q, GHSA-7xc8-m3cv-mq65)

Search

  • The core update removes a dead "Registered Members" entry from the search settings. (#6422)
  • Advanced search shows the options of one search type at a time. Types share field names, so one type's filter applied to all of them. (#6321)
  • A custom page's search result is summarized from its meta description, when it has one. (#6421)

Content plugins

  • A news menu's order setting must name columns. The latest-news and news-grid menus accept only a list of columns, each optionally followed by ASC or DESC. Any other value now sorts newest first. (GHSA-x33v-p7mw-q88f)
  • The Banner plugin's admin pages can be translated. Their help texts, placeholders, and menu notice now come from the plugin's language file. (#6520, #6354)
  • The Tag Cloud menu writes its cache only while the content cache is on. With it off, as a new install leaves it, every page showing the menu wrote a cache file that nothing read. (#6728)

Site address and database

  • e107 keeps path info, markup, and other hosts out of the site's web address, and files its caches under it. (GHSA-6mxv-9x4j-8rhr)
    • Expect one cache rebuild after the update. Cached pages, menus, and the combined CSS and JS file get new names; the combined file's name now carries the release, so script fixes reach visitors without emptying the cache. Empty All Cache removes the old ones.
    • On nginx with PHP-FPM: in a PHP location, use fastcgi_split_path_info with PATH_INFO, add try_files $uri =404;, or set cgi.fix_pathinfo=0; in a named location that hands unknown addresses to index.php, add fastcgi_param SCRIPT_NAME /index.php;, with the site's folder in front if it has one.
    • Behind an alias, symlink, or /~user/ address, a web folder whose name holds anything but ASCII letters, digits, and - . _ ~ is percent-encoded in the site's address, and the site's cookies are set on the folder above it. Every application under that folder receives them. Where the name holds a comma, a sign-in from before the update survives signing out until its cookie expires, within a day by default.
  • e107 connects on the database port set in e107_config.php. A $mySQLport line was ignored. If yours sets one, check that your database server listens on it. (#6663)

Fixed

BBCodes and HTML

  • BBCode links and images lead where their author typed them. An & in a [link], [url], [file], [email], [img], [flash], or [stream] address was encoded too often, so ?a=1&b=2 lost its second parameter. An apostrophe in an [img] alt text or caption no longer shows as an entity. (94ef3d1ae4, 73227b2392)
  • A member's & is stored once. Since 2.2.0, text from anyone outside "Class which can post HTML" showed &amp; for a typed &. Older text loses the extra level when next saved, except inside [code], where you remove it by hand. (#6791)
  • The first click on a bbcode toolbar button inserts its code. It inserted nothing until you had clicked into the text box. (#6135, #6367)
  • An unclosed tag such as [color=#ff0000] stays as typed, not a bare [color]. (#6444)
  • Text in malformed bbcode such as [size2]hello[b]world[/size] no longer vanishes. (#6573)
  • Plain-text summaries, such as a forum topic's meta description, convert bbcode whichever tags the text holds. (#6323)
  • The editor and the parser keep what was typed in six more places. (GHSA-53pg-w64x-rch7, 5d9c02d80c, GHSA-x3v9-7pgp-6c4f, 7df2136d20, 605d4f5c0c, ddcf90a96e)
    • Two bbcodes inserted in one paragraph with the editor's Insert e107 BBcode both survive.
    • Saving from the editor keeps a quote that is part of an attribute value.
    • Tags inside [scode] keep the quotes around their attribute values.
    • With the editor on, a + in a field after an editor field, such as a page's meta title, is no longer saved as %2B.
    • On PHP 8, a page showing a [sanitised] block no longer fails; it shows ##Sanitised##.
    • Text such as a < b beside markup keeps its < on hosts with libxml2 2.9.10 or older, which dropped it and what followed.

Forum, comments, and List New Items

  • Quoting a post keeps its bbcode in a [quote] block; one with bold text or a link was quoted as plain text. (#6782)
  • Deleting or moving a thread keeps a forum's counts right when a counter was already low. (#6664)
  • Forum and topic pages keep quotation marks and apostrophes in their description, and in the og:description and twitter:description copies link previews show. (0a6abeed56)
  • List New Items names the guest who started a thread, not an empty link. (#6360)
  • List New Items no longer stops with a fatal error with the profanity filter on, which now filters its headings too, nor on PHP 8 when its admin page had not been opened since a fresh install or reinstall. (#6375, d293ed98af)
  • Guests see comment lists on PHP 8 with "Display new comment icon" on; they stopped with a fatal error. (#6491)
  • Saving the comment menu's caption in one language keeps the others. (#6490)
  • A news item's comment count counts only its own comments. (#6766)

Mail

  • A page that cannot send its email now says so. The contact form, account removal, most admin test emails, and Users' approve, resend, and quick add all reported success. Account removal now stores no removal key when the email fails. (#6743)

Menus, pages, themes, and forms

  • A menu visible to "Everyone but.." a class shows; nobody saw it. (#6279)
  • Login and Online menu settings no longer report "Saved" for a failed save. (#6196)
  • A popup-window link opens where its link points, not relative to the current page. (GHSA-fm7r-8pvc-x36q)
  • A book listing's title, and its description when the book has none, no longer come from its chapters. (#6377)
  • A missing or hidden book or chapter answers 404 instead of showing a hidden chapter's name. (#6391)
  • On PHP 8, a language pack older than core no longer takes the admin area down through the admin menu. (#6223)
  • A date field's calendar stays hidden until clicked on a theme that loads no Bootstrap. (#6111)
  • Required fields on the signup and user settings forms are marked with an asterisk again. (#6124)
  • Right-aligned dropdowns line up with their button's right edge on Bootstrap 4 themes, core's sign-in and private-message menus among them. (#6328)
  • Each entry of the forum's post-options menu is clickable across its width on Bootstrap 4. (#6425)
  • On the bootstrap5 theme, the "New downloads" star is drawn at its normal size. (#6656)
  • A plugin filed under About appears under About in the admin menu, not in an untitled section. (#6801)
  • {UPLOADFILE} and upload.php stay closed while public uploads are switched off, as on a new install. (a7f86886a9)

Search

  • The advanced Author filter finds what the picked member wrote. The form sent the member under a name no search area read. (05e772dbb2)
  • The custom result prefix set in Admin » Search appears, followed by a space. (#6327)
  • Excerpts drop bbcode payloads such as an image's path. (#6299)
  • The PHP sort method works on MySQL 8, matches punctuation as typed, ranks on every weighted column, and keeps the words beside a stray +. (#6330, #6313, #6357, #6439)
  • A keyword holding # after a space finds matches on the default sort method. (#6478)
  • Comments search is offered when no plugin search area is configured. (#6422)
  • Leftover entries for removed plugins no longer list their comments or break the search pages on PHP 8. (#5267)
  • The search form's advanced button opens on Bootstrap 4 and unframed themes. (#6312)
  • Each advanced search label names its own field. (#6300)

Content plugins

  • Regression fixed: the FAQ page sent visitors to the admin login. On v2.3.12, /faqs could open the admin area for administrators and the admin login for everyone else. After upgrading, delete e107_plugins/faqs/controllers/ if it is still on disk, then run the FAQs update in Admin » Plugin Manager, which rebuilds the URL settings. (#6502)
  • Forum polls display on PHP 8. A topic with a poll, the preview of a new topic with a poll, and the archived polls page stopped with an error. (#5267)
  • Deleting a private message deletes its attachment. The file stayed on disk and the member was told the deletion failed. It now goes once neither another copy of the message nor a queued bulk send carries it. The PM plugin's update to 3.2 adds an index for that check. (#6159, #6420)
Chatbox, RSS, Downloads, and Submit News fixes
  • Chatbox: the chat page's page links reach older posts, and its count skips blocked posts. (#6143)
  • RSS: comment feed items name their author, and an & in an author's name no longer breaks the feed. (#6473)
  • RSS: news items open to comments carry a comments link in the RSS 2.0 feed. (#6497)
  • Downloads: the mirror page's breadcrumb names the category and the file, not just Downloads. (#6586)
  • Submit News: a guest whose submission is refused gets their name back, and their address and title unaltered. (#6291)

Users, sign-in, and social login

  • Users » Manage offers the built-in Members class in the edit form, Quick Add User, the list filter, and the batch menu. (#6137)
  • The delete button on a custom user rank deletes it. (#6527)
  • The Signin plugin's navbar form hides where nobody can sign in, as login.php already closes with User Registration/Login disabled and no social login. (#6501)
  • Password reset requests are rationed per account, as intended. (#6731)
    • Asking twice within ten minutes is answered "A request has already been sent" instead of mailing a second link.
    • A member whose login name is another account's id, such as 42, is no longer refused a link while that account has a reset outstanding.
  • Regression fixed: a guest who opens a logout link is no longer told about a missing security token. With a token, that link added one to every guest's flood-protection hit count. (#6306)
  • On PHP 5.6 to 7.2, a sign-in that Alternate Authentication passes on, such as a wrong password, no longer fatals. (#6469)

Bans and the request filter

  • Saving text that mentions wget, curl -o, lwp-download, or onmouse no longer ends on a blank page. The request filter answered any posted value or query string holding them with an empty 400 error. (#6759)
  • A flooding address is banned once, however many of its requests arrive together. Each parallel request over the threshold added its own ban row and sent its own flood notification. The core database update removes ban rows that repeat an address and type, keeping the first live one, else the earliest, then allows one per address and type. Admin » Users » Banlist refuses an entry already listed with its type, and a failed login logs an automatic ban, and fires user_ban_failed_login, only when it adds one. (#6771)
  • The ban list works as documented again. (#6077, #6115, #6408, #6409)
    • The CSV import on the Import/Export page runs. It stopped on a fatal error. It now lists skipped lines and why, refuses a file over 2 MiB, and enforces what it imports at once.
    • Replace all existing imported bans deletes the previous import once the whole file has imported, and a second one started meanwhile is refused.
    • Retriggering extends only the ban that matched, not every ban on the list or every row for the address.

Admin area, plugins, and media

  • Site URL can be a bare path such as / again. The Site Information tab silently refused to save it. Until it includes the site's host, the admin home warns main administrators that links in mail sent by scheduled tasks will be relative. (#6117)
  • Optimize SQL database now optimizes the site's tables. It named each table without the site's table prefix, reported success, and optimized nothing. Tables that fail are listed with the reason; on a large database the button takes a while. (#6665)
  • A Save stopped by the form's own checks now outlines the field at fault in red on the Corporate admin skin, and on K-Admin Inspired once the field loses focus, where nothing showed. (#6523)
  • Language Verify's editor for plugin and theme files shows Save beside Close, as it does for core files. (#6760)
  • Each Preferences tab is headed with its own name. Email & Contact Info was headed "Display Information". (#6524)
  • Uninstalling a plugin whose plugin.xml names comment types in <commentID> no longer deletes every comment on the site, nor fails with a single type on PHP 8. Its own comments are now removed only when its tables are, and kept when they are kept. No bundled plugin declares any. (#6780)
  • Regression fixed: the core database update no longer keeps asking to hash stored session ids. A stored session whose new key was already taken stayed behind, so pressing Update repeated the same step; that session is now removed. (#6691)
  • Installing or updating a plugin or theme from an archive works when e107_system is on another file system, such as a container volume of its own; it used to stop at "Couldn't Move". If the move into place fails during an update, the installed copy is put back. (#6713)
  • Admin » Public Uploads fixes. (#6385)
    • Accepting an upload whose plugin is gone is refused with a message naming it, not a fatal error.
    • The list shows every category name, and the edit form keeps the upload's category on save.
    • Renaming an upload in the list now saves.
  • The Media Manager's import list shows files such as stmp.jpg, whose second to fourth characters are tmp. (#6777)

Site address and database

  • A site with no site_path in e107_config.php is back on its own media and system folders. From v2.3.4 every such site saved uploads, backups, and logs under the folder 5058f1af83. If files saved since are missing, follow the dashboard's link to Database Utilities » Multi-Site and merge the folder marked Known bad. (#6498)
  • Download category links appear on MySQL 8 with binary logging on, its default. The Downloads "Download Categories" link list came back empty there for every account, because the server refused the stored functions it was built with. (#6297)
  • Canonical and og:url links are full addresses again where the Site URL holds only a folder, as a subfolder install's does. (#6601)
  • URL settings take effect at once where OPcache is set not to recheck changed files. (#6730)

For Developers

Added

  • e_parse::toBBCodeUrlAttribute() and e_parse::bbcodeTextAsTyped() encode a bbcode's values once. Give toBBCodeUrlAttribute() a bbcode's stored address; it returns '' for a refused scheme. bbcodeTextAsTyped() gives back any other parameter as typed, for the bbcode to encode once. A bbcode encoding $parm as stored shows &amp; for &. (GHSA-9jr4-3wxc-m2cm, GHSA-x2x3-xr6p-4xc2)

    Flowchart of how e107 2.3.13 writes the address in a [link], [url], or [file] bbcode. The stored address is decoded back to what the author typed, up to two stored levels, and only web folder paths such as {e_PLUGIN} are expanded. If shortcodes will run on the text, the address's shortcodes run with their parameters made inert. Then the scheme is checked. A javascript, vbscript, or data address, or any other scheme, gives no link, and the bbcode shows its text. An http, https, ftp, ftps, or mailto address, or one with no scheme, is encoded once, with braces as entities, so the link leads where the author typed.

New public API

Name What it does
e_parse::shortcodeModifiersForAuthor() Adds scparse_off unless the author is an administrator.
e_parse::toRssForAuthor(), notify::sendForAuthor() The same for feeds and notifications; toRss() and send() are unchanged.
e_parse::languageTerm($name) Static. A defined language term's value, else null.
e_parse::attributeValue() Now public. Encodes a value for an attribute.
e_bbcode::getRegistered(), isRegistered() Every registered bbcode and who provides it; whether a tag names one.
eShims::strtolower(), eShims::strtoupper() Static. ASCII-only case folding.
{E_TOKEN} In a stored navigation link, filled with each visitor's security token.
e_admin_controller_ui::$listScope The rows of a shared table an admin list owns, applied to the list, edit load, inline editor, and sort; its array form also pins those columns.
'linkAddress' => true Field option. Refuses a script address on every save, inline included, from a saver outside post_script unless it is unchanged; the form shows the stored bytes, and a refused inline edit answers 400 with the reason.
e_parse::maySaveLinkAddress() Whether the current user may save a link address.
e_admin_controller_ui::maySaveLinkAddresses() Protected. Asks maySaveLinkAddress() for each of a save's link fields, and refuses the save with an error on each field that fails.
e_parse::isUnchangedPost() Tells an untouched post from a changed one.
'search' => false Field option. Keeps search, filters, and sorting off a field, as users.php does for the password; the ajax filter suggests only searched columns, matching the term as text.
comment::canReadComments() Whether the visitor may read an item's comments.
FORLAN_HELP_IMAGE_DISPLAY, FORLAN_HELP_ICON_DISPLAY New forum admin phrases.
e_file::webOnlyCurlOptions() Curl options limiting a request and its redirects to HTTP and HTTPS; throws RuntimeException where curl cannot be limited.
e_file::currentUserMayUsePublicUploads() Whether public uploads are on and the current user is in the upload class.
e107.callbacks.isWebAddress(url) JavaScript. True for an http, https, or page-relative address.
e_search::authorId($author) The user id an advanced author filter sent, or 0.
e107\Database\IdentifierFilter identifier(), direction(), orderBy(), and filterOrderBy() check SQL identifiers and sort fragments, answering false or a default outside the grammar.
POLLAN_POST_POLL, BNRLAN_HELP_*, BNRLAN_PLACEHOLDER_*, BNRLAN_TITLE_REMOTE_IMAGE, BNRLAN_MENU_MANAGER_CONFIG New phrases: the forum poll heading, replacing the undefined LAN_4, and the Banner admin texts, with English fallbacks.
e107\Flood\SourceGate Rations an action per source: isClosedTo(), record(), forget().
e107::invalidateOpcache($file) Drops OPcache's copy of a PHP file e107 replaces or deletes.
e107::cookiePath($path) Static. A web path cut above its first folder holding a %; scope a plugin's own cookie with e107::cookiePath(e_HTTP).
Also public, for core's own wiring
e_parse::toDBWithoutScript()Converts as toDB() stores for an author who may post HTML but not script.
e_parse::toJsUrl(), sitelinks::popupScript()Build a javascript: address and a popup call.
e_bbcode::hideBlocks(), hideBlockTree()A text's [hide] blocks, and every one, nested ones included.
sitelinks::fillToken()Fills a stored navigation link's {E_TOKEN}.
e107forum::threadNameHtml(), withoutHiddenBlocks(), canAttachPoll(), mayReadHidden()The forum's thread-name renderer, [hide] stripper, and poll and [hide] checks.
forum_attachments::label(), asServed(), isSvg(), fileName()Static.
e107\SocialLogin\SessionStorageSocial login's Hybridauth session storage, which never unserializes a value.
media_admin_ui::mediaFolderPath()An item's expanded address, '' when its folder is missing, or false when it lies outside the media folder.
e107\Admin\AddonUpdateStatus, admin_shortcodes::renderAddonUpdateNotice()The dashboard's add-on update answer, kept site-wide, and its notice.
e_search::getCommentHandlerPath(), isCommentHandlerAvailable()A comment search handler's path, and whether its plugin can serve it.
e_plugin::isInstallRequired(array $meta)Static. Whether parsed plugin.xml asks to be installed.
e107\Database\TreeOrder::positions()Depth-first sort keys and depths for an adjacency list; selectTree() uses it.
private_message::QUEUE_TYPE, QUEUE_TYPE_RUNNINGgen_type of a queued bulk PM send, and of a claimed one.
e_online::defineUnsampledState()Defines the online constants as empty strings where goOnline() did not run.
banlistManager::importBanlistCsv()Imports a ban list CSV; returns counts and per-line errors.
redirection::isSafeLanding()Whether sign-in may land on an address, judged by its spelling, not its host.
e107\Storage\SiteFolder, SiteFolderScan, SiteFolderMergeSite folder pairs, the scan, and the merge.

Changed

  • Vendored guzzlehttp/psr7 is 2.13.1, so the global GuzzleHttp\Psr7\* functions are gone and a plugin calling them fatals. Use the static methods on Message, Utils, Query, Header, and MimeType. psr7 and what it requires are downgraded to run on PHP 5.6; Hybridauth 3.13.0 needs no downgrade. (#6372)

  • e_HTTP is cut at the running script and percent-encodes all but letters, digits, and - . _ ~ / %, unless its folders are the install's own on disk. e_REQUEST_URI and e_REQUEST_HTTP start with one slash, never /\ or /&, and e_SELF and e_REQUEST_URI spell the site's folders as e_HTTP does. (GHSA-6mxv-9x4j-8rhr, GHSA-wjmf-r4mf-m9vg)

    Two flowcharts of where e107's web path and request path come from, with the steps new in 2.3.13 marked. The web path, e_HTTP, starts from the script name the web server reports. New: path info after the .php script is cut off. The script's folder is stepped up to the site root. New: a leading run of slashes becomes one. A new check asks whether those folders are the same as the install's folders on disk; if not, everything but letters, digits, and - . _ ~ / % is now percent-encoded. The result becomes e_HTTP, SITEURL, and the _ABS paths, and it now also keys the content caches and the combined CSS and JS file. The request path, e_REQUEST_URI, comes from X-Rewrite-URL, else REQUEST_URI. New: tabs and line breaks are encoded, and leading slashes or backslashes are cut to one slash. That gives e_REQUEST_URI and e_REQUEST_HTTP, which the signin plugin, bootstrap3, and voux now escape in their sign-in forms.

  • e107\User\LogoutConfirmation asks a member who opens a logout link without a token whether to log out. index.php serves it through e107\Routing\RouteTable with e107\Http\Request, Response, and e107\Theme\Page, from the new logout_template.php, which a theme can override. A customized index.php that does not set $_E107['route_table'] keeps the old refusal. (#6753)

  • Inside an HTML attribute, print a custom page field with mode=raw, as in alt="{CPAGEFIELD: name=x&mode=raw}", and never a rich text or text area field or a hero bullet's text: printed normally, a value can end the attribute and run script, whoever saved it. (GHSA-86rc-hq8m-mwwr, GHSA-fhcg-cf34-cg8h)

Core internals: speed-ups, and the test suites and CI
  • Pages do less repeated work. (#6697, #6732, #6726, #6696, #6698)
    • The user class tree is read without a SHOW COLUMNS probe, and Who's Online classifies each user agent once.
    • The tmp table is pruned on one request in a hundred, and a database session close no longer collects expired sessions each time.
    • The strftime() shim reuses its IntlDateFormatter, and e_media::getGlyphs() builds each precompiled icon set once per request.
  • The test suites and CI were reworked. (#6744, #6746, #6796, #6702, #6690, #6684, #6297, #6721, #6722, #6287, #6503, #6506, 690be648b1)

Behavior changes for plugin and theme authors

Name What changed
bbcode_shortcodes::renderEmotes() Removed, so a theme or plugin calling it fails. r_emote() draws the emoticon panel.
e_parse::toAttribute(), replaceConstants() toAttribute() expands only web folder path constants, and encodes their values. replaceConstants() by default expands only web and server path constants; $all = true expands the rest.
e_parse::toHTML() A strip list that names hide strips [hide] blocks with the rest; they came back as the bbcode's box.
e_parse::toDB() A numeric fifth argument, a user id, only forced encoding; now that user's post_html and post_script decide what is kept.
text_truncate(), toEmail(), toForm() Keep < and > encoded where they used to decode them, and text_truncate() keeps every entity.
Shortcode parameters in content Quotes, angle brackets, and { arrive as entities.
A field whose whole text names a constant Converts only when the constant is a language term.
toWYSIWYG() hook Receives an admin UI bbarea field's text, and the news body's, encoded.
e107Email {BODY} Receives the body unparsed: render it first, or set mail_body_author on a bulk mail.
{LAN=X} Prints LAN_X, or X only when it is shaped like a language term: a capital first, word characters only, and either LAN inside or a final digit. Other constants print nothing.
{NEXTPREV} Re-encodes its address and drops a non-web one. pagetitle entries lose tags and shortcodes. bullet prints as text unless it is one <img> under THEME_ABS with only alt and class, like core's.
{BREADCRUMB=name} Reads only an array global with a plain variable name.
{IMAGESELECTOR}, {IMAGEPREVIEW}, {UPLOADFILE} Quote their values as JavaScript strings and refuse a non-web preview address. {IMAGESELECTOR} ignores undocumented parameters.
{PLUGIN=}, {MENU=}, {PAGE_NAVIGATION: name=} {PLUGIN=} and {MENU=} take only word characters and hyphens; name= takes only page_metatitle, or menu_title for the menu's class.
{SEARCH_ADV_ID} Binds the advanced search template's label; an overriding theme still on for="t" keeps the old binding.
Required-field marker e107.css draws the asterisk. A theme that draws its own may show two; .required:empty::after { content: none } turns core's off.
Right-aligned dropdowns and floats Core uses dropdown-menu dropdown-menu-right dropdown-menu-end, and right floats pull-right float-right float-end. Menus lost pull-right, so a theme bundling Bootstrap older than 3.1.0 loses their alignment.
bootstrap5 Font Awesome Loads as CSS, not script, so CSS aimed at svg.svg-inline--fa stops matching there.
e-expandit, e-comment-edit Look their target up as a selector only.
e-modal Opens only an http, https, or relative address, and prints data-modal-caption as text.
e-ajax Fetches only from this site, and inserts an answer only if it ends there as text/html or application/json. data-loading-icon is applied as class names.
.e-rate Its status line and vote count must be its siblings, as core writes them. A rating without data-hint is skipped.
comment::enter_comment() Refuses items the poster may not read, and comment types core does not model, such as a plugin's own.
comment.php AJAX answers application/json; read them with dataType: 'json', not $.parseJSON().
e107forum::forumGetForumList() Returns false to a caller who may view no forum, and to an object built with new e107forum(true); forumGetForumList(true) returns every row.
poll::submit_poll() Mode 1 needs poll admin rights.
e_list.php heading and info Printed as built; a section that wants them rendered renders them itself.
e107MailManager::sendEmails(), private_message::pm_send_notify() Return false when the send fails.
Admin UI routes Names fold case in ASCII; an unknown action falls back only to a granted default; an ajax page runs only on ajax; actions reach only action methods.
Admin UI saves Follow the route: create inserts; edit and inline update the loaded row or refuse. Inline, sort, and a plugin's batch_<plugin>_<command> need the edit route.
e_admin_ui::PrefsSaveTrigger() Saves only keys $prefs declares; declare every option you post.
e_front_model::getIfPosted() Writes a posted string's & as &amp;, so a form redrawn after a failed save shows what was posted, entities included.
Front-end inline editing Refuses a map without perms; inline.php used to read perm. Maps are kept under a new session key, so inline editing works once a page is loaded after the upgrade.
Menu Manager options A .e-menumanager-option link loads only from menus.php, and mode=conf redirects only to a config.php or *_menu_config.php.
e107plugin::manage_comments('remove', ...) Takes one type or a list; returns false for an empty list instead of deleting every comment.
e_file::curlOptions() Throws RuntimeException where curl cannot be limited to HTTP and HTTPS.
e_user_provider Builds Hybridauth on first use; its protected $hybridauth is null until then. Only stored settings are filtered, not a configuration passed to the constructor.
e_user_provider::login() A refused sign-up (code 5) throws with an empty message; its reasons go to the message stack.
Comment search handlers Skipped unless one sets $comments_class[key] or $comments_where[key], saying who may read its items, as the poll plugin's does. Blocked comments are excluded.
An addon's author search filter Receives the picked member's user id. e_search::authorId() returns it, or 0 for typed text; the _blank plugin's e_search.php shows the pattern.
e107_handlers/search/ Six dead legacy handlers are deleted. An upgrade leaves the old copies on disk.
e_pref::save() No longer loads the admin language pack, which a front-end, cron, or CLI request saving a preference, such as a new most-online record, gained. Front-end code reading admin phrases must load them or use defset().
e_db_pdo Instances share one connection per set of parameters, so session state set through one (temporary tables, SET SESSION, user variables, locks, transactions) is seen by the others. For a session of your own, call connect() with $newLink = true.
Preference cache files JSON wherever JSON reads back the identical array. e107::unserialize() reads both forms.
dbError() Answers alike on both backends: null, or "$from :: $text".
xmlClass::getLastErrorMessage() Always a string, naming the parse errors or a failed fetch's HTTP status.
selectTree() Same _treesort and _depth; needs only SELECT; refuses bad identifiers.
e_news_tree::loadJoin() db_order must be columns with optional ASC/DESC, else newest first; db_limit is cast to integers.
ecache::setMD5() Hashes text with the site's web path. Code that builds an entry's file name from md5($text) should use retrieve() and clear() with its tag; setMD5($hash, false) is unchanged.
e_array::unserialize() Reads a row as written before trying it unslashed, so a value containing 0 => ' no longer empties its row.
class_list() Deprecated, because only its user-id form includes inherited classes. Use e_user_model::getClassList().
CHAP e107_web/js/chap_script.js is deleted, UserHandler::CheckCHAP() and e_core_session::challenge() are deprecated and unused by core, and userlogin::login() ignores $response.

Fixed

Fixes with no visible effect: warnings only debug mode showed, and calls past PHP 5.6
  • A theme config markup row missing caption, html, or help no longer raises an undefined-key warning. (#6214)
  • {LOGO} no longer raises a diagnostic on a legacy theme whose logo file is missing or unreadable. (#6148)
  • e107_db_debug::log() and dump() name a top-level caller {main} instead of warning, and stop printing ()(). (#6378)
  • upload.php no longer reads form fields a first visit has not posted. (#6361)
  • Undefined variable and key reads in the news, FAQs, download, and RSS code are guarded. (#6156, #6376, #6502, #6497)
  • A call past PHP 5.6 that no code reaches is gone, and http_build_query() gets '', not null. (#6445)

Parser, shortcodes, and themes

  • usubstr() and html_truncate() keep the text they should. usubstr() without a length returned '' below PHP 8; html_truncate() with $exact = false lost text that had no space. (#6464, #6475)
  • A shortcode class that sets a property before parent::__construct(), or never calls it, no longer fatals on PHP 8, and keeps the value. (#6658)
  • The Theme Manager's style form saves only for the site theme, refusing a post that names another. (#6177)
  • On PHP 8, cleanHtml() no longer fatals on the call after a <pre> inside a stripped tag, nor e_form::uc_checkbox() on an array value. (#6801)

Admin UI and debug

  • "(Add all)" and "(Clear all)" batch options now dispatch, as they never had in v2. (#6089)
  • A field with no usable optArray leaves the batch and filter menus with a debug line instead of breaking the list page. (#6403)
  • Admin navigation reads its phrases through defset(), so a pack missing one no longer stops the page on PHP 8. (#6526)

Database, preferences, and files

  • selectTree() creates no stored functions, and siblings sharing an order no longer interleave. (#6297)
  • isTable() sees tables the same instance creates, drops, or renames. (#6374)
  • tables(), isTable(), and hasLanguage() no longer list another prefix's tables. (#6672)
  • e_db_mysql::lastInsertId() answers for the instance's own last statement. (#6715)
  • A multi_row plugin or theme preference keeps its own cache file and object. (#6338)
  • e107MailManager reads a queued email back as saveEmail() stored it; a raw apostrophe in its sender, copies, or attachment emptied all three. (34591e2243)
  • e_file::copy() passes its options into subfolders and returns false at the first entry it cannot copy; the theme converter's clone stops there. (#6713)
  • e_file::get_files()'s standard filter skips only names that start with .tmp. (#6777)

Core

  • Who's Online values are defined on every request. (#6362, #6396, #6522)
    • Where goOnline() is skipped, as on AJAX, the online constants are empty strings, so online.php no longer fatals.
    • With an empty online table, MEMBERS_ONLINE is 0.
    • {ONLINE_TABLE_MEMBERS_ONLINE} and {ONLINE_TABLE_GUESTS_ONLINE} were swapped.

Acknowledgments

Thanks to

  • @jamyiahxg954-arch for reporting the moderator who could split posts into a forum they did not moderate; to
  • @Jimmi08 for reporting the forum poll that a new thread could overwrite, for the forum poll error on PHP 8 (#5267) and the advanced search labels (#6295), for her Download plugin observations (#6497) and the Downloads breadcrumb built too early (#6525), and for the theme logout links refused since v2.3.12 (#6741); to
  • @dimante for the images missing since the v2.3.4 upgrade (#5810); to
  • @Taffman for the menu shown to all but one class, which nobody saw, and the Logout link v2.3.12 refused (#6275), and the date picker on a theme without Bootstrap (#6111); to
  • @KuroiPhoenix for the Site URL that would not save as / and the admin area an old language pack took down (#6101); to
  • @sindizzy for the Signin form shown where nobody can sign in (#6501) and the Preferences save that failed without a sign (#6103); to
  • @Alex-e107nl for the required fields shown without an asterisk (#6106); to
  • @NECPWAweb for the page-sized "New downloads" star on bootstrap5 (#6652); to
  • @tgtje for the debug logs in #6355 and #6479 behind six fixes (#6360, #6361, #6362, #6375, #6378, #6491); for reporting the FAQ page that sent visitors to the admin login (#6502); and for the pull requests that made the Banner admin pages translatable (#6520, #6354) and added the forum's admin help phrases (#6647); to
  • @fizi for the comment menu caption that saving one language overwrote (#6490, from #6479), and the core database update that kept asking to hash stored session ids (#6691); to
  • @Kanonimpresor for the Language Verify editor whose Save button stayed inside it (#6760), and for reporting the request filter that refused text mentioning wget and the pull request that removed it (#6759, #6762); and to
  • @ericc-dream for the search pages that leftover entries of removed plugins broke on PHP 8 (#5267).

Full changelog: v2.3.12...v2.3.13