Download Latest Version e107 v2.3.7 source code.zip (17.0 MB)
Email in envelope

Get an email when there's a new version of e107

Home / v2.3.7
Name Modified Size InfoDownloads / Week
Parent folder
e107_v2.x_to_2.3.7_upgrade.zip 2026-06-14 12.3 MB
e107_v2.x_to_2.3.7_upgrade.tar.xz 2026-06-14 8.3 MB
e107_v2.x_to_2.3.7_upgrade.tar.gz 2026-06-14 11.5 MB
e107_v1.x_to_2.3.7_upgrade.zip 2026-06-14 14.8 MB
e107_v1.x_to_2.3.7_upgrade.tar.xz 2026-06-14 10.2 MB
e107_v1.x_to_2.3.7_upgrade.tar.gz 2026-06-14 13.7 MB
e107_2.3.7_full.zip 2026-06-14 14.7 MB
e107_2.3.7_full.tar.xz 2026-06-14 10.2 MB
e107_2.3.7_full.tar.gz 2026-06-14 13.6 MB
e107 v2.3.7 source code.tar.gz 2026-06-14 15.7 MB
e107 v2.3.7 source code.zip 2026-06-14 17.0 MB
README.md 2026-06-14 11.6 kB
Totals: 12 Items   142.0 MB 2

[!CAUTION] v2.3.7 is a security release for sites on v2.3.6 or earlier. Upgrade from any 2.x at or below v2.3.6. If your site tracks the master branch, you are already past v2.3.7, so installing it would be a downgrade. v2.4.x is planned to be the next forward step.

[!IMPORTANT] Upgrade immediately. v2.3.7 closes two unauthenticated, network-reachable, Critical vulnerabilities. Neither requires authentication, user interaction, or any special privilege, and every public-facing site on v2.3.6 or earlier is exposed.

  • Remote code execution via install.php (GHSA-c8h6-wpj3-4cr8, CVSS 9.8). Reachable on a default installation: install.php stays live and exploitable after setup.

Mitigation: Delete install.php. - SQL injection throughout the e107 core (GHSA-5f75-c25x-59wx, CVSS 10.0). Request data is interpolated into SQL across ordinary, unauthenticated front-end request handling, including code an anonymous visitor triggers with a single page view (online-presence tracking writes the request URI into the database after a sanitizer that still permits the closing quote). It is not confined to any one plugin or feature, so no configuration change mitigates it. The only protection short of upgrading is to keep the site off the public Internet.

Treat this as an emergency upgrade.

Highlights

  • [Security] Remote code execution through the installer (GHSA-c8h6-wpj3-4cr8, CVSS 9.8). On a normal site, install.php stayed reachable after setup and could be tricked into running an attacker's code, with no login. It now refuses to run once the site is installed, and the information the setup wizard carries between steps can no longer be used to smuggle in code. (https://github.com/e107inc/e107/commit/6c40429521, https://github.com/e107inc/e107/commit/5d6d649e8c)
  • [Security] Database break-in through ordinary pages (GHSA-5f75-c25x-59wx, CVSS 10.0). Many everyday pages passed details from the web request into database queries without making them safe, so an attacker could run their own database commands, with no login and often just by visiting a crafted web address. This is now fixed throughout the core. No setting protects an unpatched site: you have to upgrade (or keep the site off the public Internet). (https://github.com/e107inc/e107/commit/120bd4bdbe)
  • [Security] A database-safety function that did nothing. One of e107's built-in functions for making a value safe to use in a database query was handing it back unchanged, so any code that relied on it had no protection. It now works as documented. (#5749, https://github.com/e107inc/e107/commit/b467b74f72)

For Administrators

Changed

  • The installer locks itself after setup (security). Once your site is installed, the setup wizard refuses to run again, so it can no longer be reached or misused on a live site. e107 decides this from the configuration file alone, so a database outage cannot accidentally reopen it. If you ever need to reinstall on purpose, delete e107_config.php first. Automated ("unattended") installs are only accepted on a site that is not already set up. Ref GHSA-c8h6-wpj3-4cr8. (https://github.com/e107inc/e107/commit/5d6d649e8c)
  • Database queries protected across the site (security). Many parts of e107 (including who's-online tracking, the ban list, ratings, comments, login, and registration) took information from the web request and used it in database queries without making it safe first. That has been corrected everywhere it was found, including the alt_auth external-database login that the report originally came in on. There is nothing for you to configure and the site behaves exactly as before; installing this release is what protects you. Ref GHSA-5f75-c25x-59wx. (https://github.com/e107inc/e107/commit/120bd4bdbe)
  • The website-address header is checked before use (hardening). e107 builds some links from the Host header a visitor's browser sends; it now rejects a malformed value and uses the server's own hostname instead. On a correctly configured site the existing host check already turns away mismatched hosts, so this is an extra safety net, and it also makes sure a non-standard port is kept in the links e107 generates. Ref [#5734]. (https://github.com/e107inc/e107/commit/a2f386b27f)

Fixed

  • Welcome Message creation date. A rewrite had dropped the automatic creation date when a Welcome Message menu item is created; it is restored, so the date is available for themes that choose to show it. Fixes [#5739]. (https://github.com/e107inc/e107/commit/bdb6c35116)
  • Media-category create page on PHP 8. media_cat_ui::createPage() called count() on an unset writeParms value when every category owner is restricted, throwing a TypeError under PHP 8. It now uses a null-safe check and keeps the same "category creation not available" behavior. Fixes [#5741]. (https://github.com/e107inc/e107/commit/d5e0d07814)
  • Enter advances the install wizard. The buttons bar emitted Back before Continue, so an implicit submit (Enter in a text field) sent the wizard back a step. The forward control is emitted first and the bar laid out row-reverse, so the visible order is unchanged and only the Enter behavior is fixed. (https://github.com/e107inc/e107/commit/2865e98f96)

For Developers

Added

  • Test coverage. installStateTest builds the real guzzlehttp/psr7 POP chain and asserts the new JSON codec rejects it while round-tripping scalars; SqlInjectionFixesTest pins the core SQL-injection remediations; and acceptance coverage exercises the installer reinstall guard, paste-to-resume, and the unattended-install path end to end. (https://github.com/e107inc/e107/commit/6c40429521, https://github.com/e107inc/e107/commit/892758085c)
  • eShims::setcookie() options-array shim. Backported SetcookieTrait (the PHP 7.3+ options-array form with a pre-7.3 SameSite-into-path fallback) so the installer can set a hardened (HttpOnly, Secure, SameSite=Strict) resume cookie with one call across every supported runtime. Existing setcookie() callers are untouched. (https://github.com/e107inc/e107/commit/1063102678)

Changed

  • Installer wizard state is now signed JSON, and the installer fails closed. install.php previously unserialize()d base64-encoded $_POST['previous_steps'] with no allowed_classes, at file scope on every request and again in the e_install constructor; the bundled guzzlehttp/psr7 PumpStream POP chain reached arbitrary callable execution once the decoded value flowed into site_path and was coerced to a string. Wizard state now travels as base64(JSON).hex(HMAC), verified in constant time on every request against a per-install CSPRNG signing token, and json_decode() only yields arrays and scalars, so object injection (CWE-502) is impossible by construction. e107_config.php is read as one of three positive states (fresh, install-pending, installed) instead of an emptiness check; the unattended ?create_tables path compares credentials with hash_equals() and refuses a database that already holds an e107 schema; and the finished config is written last, so a half-finished install never looks installed. (https://github.com/e107inc/e107/commit/6c40429521, https://github.com/e107inc/e107/commit/5d6d649e8c)
  • Core SQL-injection remediation techniques. Because the 2.3.x line predates the e_db prepared-statement API, tainted values are escaped inside their SQL quotes, numeric / LIMIT / OFFSET positions are (int) cast, and dynamic table/column identifiers are confined to a strict [A-Za-z0-9_] allowlist (escaping cannot protect identifiers). Import providers are fixed at the root in base_import_class::database(). Many sinks are reachable without a login: the online-presence tracker, for example, wrote e_REQUEST_URI into online_location after only FILTER_SANITIZE_URL, which keeps the single quote, so a crafted address reached the query directly. If you maintain a plugin that builds raw SQL from request input, mirror these. (https://github.com/e107inc/e107/commit/120bd4bdbe)
  • e_db_pdo::escape() now escapes. The shared testEscape() expectation that codified the pass-through is updated, which makes the e_db_mysql override redundant. One caller (social_setup.php) used escape() on a value interpolated into an unquoted numeric context and is cast to int instead. (#5749, https://github.com/e107inc/e107/commit/b467b74f72)
  • Host resolution helper (hardening). The request host is resolved through a shared resolveHttpHost() backported from master: it accepts the client Host only when it matches a host[:port] shape and otherwise falls back to SERVER_NAME, preserving the visited port. On a configured site the isAllowedHost() killswitch (added in v2.3.6) already rejects a mismatched Host before it reaches a URL, so this is defense-in-depth (covering an unset or misconfigured siteurl, and partial-bootstrap entry points that skip the killswitch) plus a regression lock: the accompanying e107HostValidationTest pins port preservation so a future sync from master cannot silently reintroduce the port-strip. (https://github.com/e107inc/e107/commit/a2f386b27f)
  • GitHub contribution templates revamped. CONTRIBUTING.md is now a policy document (backwards compatibility as the primary constraint, AI-assisted contributions welcome on the same quality bar, explicit rejection criteria for low-effort output), with matching PULL_REQUEST_TEMPLATE.md, issue forms, FUNDING.yml, and a new SECURITY.md. (https://github.com/e107inc/e107/commit/2b49a62ce8)

Fixed

  • Install log moved out of the document root. e107Install.log was written into the docroot, where the shipped .htaccess has no rule for .log files, so its install diagnostics (DB host, table prefix, pref dumps on failure) were fetchable over HTTP. It now lives under the deny-by-default e107_system/. (https://github.com/e107inc/e107/commit/c1ef5bab81)
  • Installer reads its own config past opcache. With opcache on, a same-second rewrite of e107_config.php could be served from the prior compile, hiding the freshly written provisioning lock. The installer now opcache_invalidate()s the file around each read and write. (https://github.com/e107inc/e107/commit/72b333107e)
  • Non-destructive test isolation. GitPreparer's rollback used git reset --hard && git clean -fdx, which destroyed uncommitted work on a crashed run. It now runs each suite inside a disposable git worktree with flock()-based orphan cleanup, never touching the main tree. (https://github.com/e107inc/e107/commit/aac93f1791)

Acknowledgements

Both vulnerabilities were responsibly disclosed through GitHub Security Advisories. Our thanks to @baozongwi (GHSA-c8h6-wpj3-4cr8) and @Jimmi08 (GHSA-5f75-c25x-59wx) for the reports.

Source: README.md, updated 2026-06-14