This guide provides instructions for upgrading InvoicePlane to newer versions.
- Instructions to upgrade to 1.7.2 from 1.7.0 / 1.7.1
- Instructions to upgrade to 1.6.3 from 1.6.2
- Instructions to upgrade to 1.6.0 from 1.5.11
This is a critical security release. v1.7.0 and v1.7.1 contain a Remote Code Execution vulnerability (CVSSv3 9.9). Upgrade immediately. Consult MIGRATION_GUIDE_v1.7.2.md for a full pre-upgrade security audit checklist.
The full, GHSA-linked list of every vulnerability fixed in v1.7.2 lives in the CHANGELOG. The table below is a quick reference to the most impactful fixes.
| Severity | Vulnerability | Details |
|---|---|---|
| Critical | Remote Code Execution via dynamic template whitelist (bypass of v1.7.1 LFI fix) | SECURITY_ADVISORY_RCE_FIX.md |
| Critical | Broken authentication – password reset tokens never expired | CHANGELOG |
| High | Open redirect via unvalidated HTTP_REFERER |
CHANGELOG |
| Medium | SQL query hardened in guest payments | CHANGELOG |
| Medium | HTTP_REFERER injection in AJAX filter controllers |
CHANGELOG |
| Medium | PHPMailer SMTP debug output logged unsanitized (log injection) | CHANGELOG |
| Medium | phpmail_send() masked send failures by always returning true |
CHANGELOG |
| Low | Binary data corruption in Cryptor::decryptString() (mb_strlen/mb_substr) |
CHANGELOG |
| Low | GitHub Actions GITHUB_TOKEN over-broad permissions |
CHANGELOG |
The following changes alter observable behavior or API contracts. Review each one before upgrading.
Who is affected: Installations with custom code that calls phpmail_send() directly and
relies on its return value.
Before (v1.7.0–1.7.1): phpmail_send() always returned true, even when the underlying
SMTP/sendmail call failed. Delivery failures were silently dropped.
After (v1.7.2): phpmail_send() returns the actual boolean result — true on success,
false on failure. Failed sends now set a flash error message for the user.
Action required: If your custom code calls phpmail_send(), update it to check the return
value:
// Before — always truthy, failures silently ignored
phpmail_send($from, $to, $subject, $body);
// After — check for failure
if ( ! phpmail_send($from, $to, $subject, $body)) {
// handle delivery failure
}Who is affected: All installations using the email template editor.
Before: The live preview panel in the email template editor rendered the template source as
HTML, using innerHTML to update a preview iframe.
After: The preview panel now displays the raw template source as plain text
(textContent). This eliminates a DOM-based XSS risk. The templates themselves are not
affected — this change only affects the in-browser preview.
Action required: None. Existing templates continue to send as HTML. If you need to visually check HTML formatting, send a test email instead of relying on the preview panel.
Who is affected: Installations that add their own invoice or quote templates.
Before: The template selector was built by scanning the templates directory on the
filesystem. Any .php file present in the directory appeared in the selector automatically —
the same dynamic scan that caused the RCE vulnerability (see #4 below).
After: The filesystem is never scanned. The selector is built from the built-in templates plus only the custom template names you explicitly allowlist. Built-in templates always appear in the selector. Adding a custom template is a two-step operation — both steps are required:
-
Place the
.phpfile underCUSTOM_TEMPLATES_FOLDER, in the sub-path that matches the template's type and scope:<CUSTOM_TEMPLATES_FOLDER>/invoice_templates/pdf/MyTemplate.php <CUSTOM_TEMPLATES_FOLDER>/invoice_templates/public/MyTemplate.php <CUSTOM_TEMPLATES_FOLDER>/quote_templates/pdf/MyTemplate.php <CUSTOM_TEMPLATES_FOLDER>/quote_templates/public/MyTemplate.phpCUSTOM_TEMPLATES_FOLDERonly tells InvoicePlane where the file lives on disk at render time. On its own it adds nothing to the selector. -
Add the template name (without
.php) to the matching allowlist variable inipconfig.php. Only names listed in these variables appear in the selector:CUSTOM_INVOICE_TEMPLATES_PDF="MyTemplate,Corporate - Modern" CUSTOM_INVOICE_TEMPLATES_PUBLIC="MyTemplate" CUSTOM_QUOTE_TEMPLATES_PDF="MyTemplate" CUSTOM_QUOTE_TEMPLATES_PUBLIC="MyTemplate"
Quote the value when a name contains spaces or hyphens.
Requirements for a custom template name:
- The corresponding
.phpfile must exist underCUSTOM_TEMPLATES_FOLDERat the matching sub-path (step 1). - The name may contain only alphanumeric characters, spaces, hyphens (
-), and underscores (_). Names with any other character are skipped and a warning is written to the CI log.
See CUSTOM_TEMPLATES.md for the full walkthrough, and section #4 below
if you previously kept custom templates inside application/views/.
Upgrade aid: After upgrading and running /setup, the Settings page checks the saved PDF
and public template settings in the database. If one of those settings names a template that is
not built in and not present in the matching CUSTOM_*_TEMPLATES allowlist, InvoicePlane shows
an administrator warning with the exact template name and ipconfig.php variable to update.
This warning intentionally uses only saved database settings; InvoicePlane still does not scan
template folders to discover unused template files.
Who is affected: Installations with custom invoice or quote templates stored inside the
application's application/views/ directory.
Background: The RCE fix replaced the dynamic filesystem scan with an allowlist mechanism.
Built-in templates are listed in hardcoded constants; custom templates can be added via explicit
allowlist config variables. Templates stored outside the application (via CUSTOM_TEMPLATES_FOLDER)
with explicit allowlisting are now the supported way to add custom templates.
Action required: If you previously added custom templates directly into
application/views/invoice_templates/ or application/views/quote_templates/, move them
to a directory outside the web root and configure CUSTOM_TEMPLATES_FOLDER in
ipconfig.php to point to that directory, then add each template name to the matching
allowlist variable:
# ipconfig.php
CUSTOM_TEMPLATES_FOLDER=/srv/invoiceplane-templates/
CUSTOM_INVOICE_TEMPLATES_PDF="MyCustomTemplate"Then place your templates in e.g. /srv/invoiceplane-templates/invoice_templates/pdf/MyTemplate.php.
See section #3 above for the full two-step process.
Alternatively, if you prefer to keep templates inside the application, add each template name
to the appropriate constant in application/modules/invoices/models/Mdl_templates.php:
private const ALLOWED_INVOICE_TEMPLATES = [
'pdf' => [
'InvoicePlane',
'InvoicePlane - paid',
'InvoicePlane - overdue',
'MyCustomTemplate', // ← add your template name here
],
// ...
];Run the full pre-upgrade checklist in MIGRATION_GUIDE_v1.7.2.md before applying the upgrade, especially if you are upgrading from v1.7.0 or v1.7.1.
- Back up your database and all files.
- Copy all new files to your InvoicePlane installation root, but do not overwrite:
ipconfig.php- Custom templates in
application/views/(better: move them toCUSTOM_TEMPLATES_FOLDER) - Custom styles:
assets/core/css/custom.css,assets/core/css/custom-pdf.css - Uploaded images in
uploads/ - Custom language keys:
application/language/COUNTRY/custom_lang.php
Open http://yourdomain.com/index.php/setup and follow the on-screen instructions. The
setup wizard runs the required database migrations automatically, including adding the
user_passwordreset_token_expiry column for the password reset token expiry fix.
After /setup completes, log in as an administrator and open Settings. If InvoicePlane
finds saved custom template names that are not listed in ipconfig.php, it shows a warning
with the names to copy into CUSTOM_INVOICE_TEMPLATES_PDF,
CUSTOM_INVOICE_TEMPLATES_PUBLIC, CUSTOM_QUOTE_TEMPLATES_PDF, or
CUSTOM_QUOTE_TEMPLATES_PUBLIC.
chmod 555 application/views/invoice_templates/public/
chmod 555 application/views/invoice_templates/pdf/
chmod 555 application/views/quote_templates/public/
chmod 555 application/views/quote_templates/pdf/
find application/views/invoice_templates/ application/views/quote_templates/ \
-name "*.php" -exec chmod 444 {} \;Confirm the template system no longer scans the filesystem and only serves allow-listed templates by following the manual verification steps in the RCE advisory. For the arbitrary file-deletion fix, run the bundled checker:
php .github/security/verify_file_deletion_fix.phpExpected output: all checks pass with no warnings.
Follow the procedure outlined in Upgrade 1.6.0 from 1.5.11.
-
Copy all files to the root directory of your InvoicePlane installation but do not overwrite the following files:
- The
ipconfig.phpfile - Customized templates in the
application/views/folder - The files for custom styles:
assets/core/css/custom.cssandassets/core/css/custom-pdf.css - Uploaded images in the
uploads/folder (e.g. your company logo) - Custom language keys at
application/language/COUNTRY/custom_lang.php
Hint: An easy way of performing this operation is to upload the whole new InvoicePlane version in a different folder, outside of your current installation root folder, and copy the above mentioned files in the new folder you just uploaded. Afterwards just rename your current folder to something like
my_current_folder_oldand rename your new-version-folder with the name ofmy_current_folder. - The
-
Open
http://yourdomain.com/index.php/setupand follow the instructions. The app will run all updates on its own.- If you encounter any errors when upgrading the table, press "Try Again" to resolve those errors and continue with the setup.
-
Now that the update is installed, moved and protected, it's time to log in and see if everything is working: login again and check if everything is working.
-
Make a backup of your database and all files. (This is very important to prevent any data loss)
-
Download the latest version from InvoicePlane.com.
-
Copy all files to the root directory of your InvoicePlane installation but do not overwrite the following files:
- The
ipconfig.phpfile - Customized templates in the
application/views/folder - The files for custom styles:
assets/core/css/custom.cssandassets/core/css/custom-pdf.css - Uploaded images in the
uploads/folder (e.g. your company logo) - Custom language keys at
application/language/COUNTRY/custom_lang.php
Hint: An easy way of performing this operation is to upload the whole new InvoicePlane version in a different folder, outside of your current installation root folder, and copy the above mentioned files in the new folder you just uploaded. Afterwards just rename your current folder to something like
my_current_folder_oldand rename your new-version-folder with the name ofmy_current_folder. - The
-
Now that the files are placed, it's time to fix the
ipconfig.phpfile.- Open
ipconfig.phpand comment out the top line in the file by adding a#at the beginning of the first line. The result should be like this:# <?php exit('No direct script access allowed'); ?> - Close the
ipconfig.phpfile
- Open
-
Open
http://yourdomain.com/index.php/setupand follow the instructions. The app will run all updates on its own.- If you encounter any errors when upgrading the table, press "Try Again" to resolve those errors and continue with the setup.
-
Now that the
ipconfig.phpfile is fixed, moved and protected, it's time to log in and see if everything is working- Login again and check if everything is working.
- If you were using the online payments module please navigate to
//your-domain.com/settingsand to the tabonline paymentand disable all payment methods that are not stripe. InvoicePlane 1.6 at the moment supports only Stripe as a payment gateway.
Note: For additional help and support, visit the official wiki or the community forum.