Emoncms dashboard module security update

I’ve been continuing with the security focused work on emoncms that I’ve posted about a few times now, E.g Emoncms security notice: read to write apikey privileged escalation vulnerability, please update to emoncms 11.16.8+, Emoncms v11.12.3 stable release - security fixes, Emoncms v11.7.1+.

Latest is a fairly substantial security update to the Emoncms dashboard module, mostly focused on reducing the risk of cross site scripting, cross site request forgery and clickjacking attacks, but also fixing a few other things along the way.

We had been using a library called AntiXSS for this but it sat in the repository as a large dependency which was seldomly updated due to php version compatibility issues. Rather than try to list and guard against all possible attacks using AntiXSS the new approach uses a whitelist of specifically allowed dashboard content, this works for emoncms dashboards as dashboards are basically a list of widgets and graphs with known properties - it’s therefore possible to design a conservative whitelist approach, fully under our control, that only lets specific content passed.

This new approach also stores the dashboard data as a JSON object rather than raw HTML and that JSON object is used to re-build and render the dashboards. This is also going to help with future work such as refactoring the way the graphs are integrated in the dashboards (part of my ongoing goal to tidy up the code base).

Visible changes?

For most users there should be no difference. Widgets and charts keep their positions, sizes, options and text. A small number of dashboards will see changes, these are:

  • Dashboards using custom style blocks not in-line styles. Custom styles need to be added now as in-line styles.
  • Custom iframes inside the dashboards are now removed.
  • Links back to emoncms itself are disabled for now until other related work is completed on emoncms core.

Button and curl widgets

Disabled completely on emoncms.org. For local/self-hosted systems these now need to be enabled by adding the following setting to settings.ini:

[dashboard]
enable_action_widgets = true

Other fixes

This update also found and closed the following issues:

  • The dashboard editor loaded a dashboard by id alone, so any account could open the content (but not the feed data itself) of somebody else’s private dashboard by asking for its id. It would just show up as blank charts and widgets with NaN values.
  • A widget could be given a negative position and sit on top of the emoncms menu bar. Positions are now clamped to the page.
  • A widget could be made invisible with zero opacity and still take clicks. Invisible widgets are no longer possible.
  • An image could point at an emoncms API call and be fetched with the users session as the page drew. Locally loaded images now need to be placed in /var/www/emoncms/Modules/dashboard/Views/images.
  • An image could also leak the dashboard address, and any key in it, to the site it was loaded from. Images are now loaded with no referrer.
  • Dashboard names and other fields are now escaped, in the view, the editor and the config dialogue.

How to update

These latest changes are now available in Emoncms core, Dashboard and Graph modules:

On a emonHP, emonPi1/2/3, run Admin > Update > Full Update (this will also automatically update the database).

On custom self hosted, update core and modules and then update the SQL database.

Emoncms.org is updated already.

Emoncms core changes

There are also further security improvements to emoncms core in the v11.18.0 release, in particular changing an account email address now requires password verification, this helps reduce the potential for account takeover attacks via CSRF. There’s also new restrictions on which emoncms pages can be placed in a iframe on another site.

Troubleshooting

If you see issues with your dashboard after this change please let me know.

I used to have my emoncms.org apps displayed inside Iframes. Why this is not allowed anymore? Could you re-add it please?

Hello @Tuecki did you have emoncms.org/app inside an iframe in emoncms.org/dashboard? or is it an iframe issue embedding emoncms in another website that you have?

Yes, I would like to embed emoncms.org/app inside my website.

Another issue I noticed is that all the custom images in my dashboards that were loaded from my website have been deleted.

Thanks @Tuecki

Now fixed - I mistakenly blocked iframe access to all app module routes, the view route is now an allowed iframe route.

Custom images from external sources should still be allowed. Could you PM me your dashboard id and emoncms.org username and I can take a look at this for you.

Hi - I just did a full update to get the security enhancements, but following the required re-boot my dashboard doesn’t work, either in the browser (Safari) or in the EmonCMS iOS application. Here’s a snapshot of the error message…. I’m a bit sad to have lost my monitoring :frowning:

Extra info… This morning I started trying to edit a new dashboard to see if I could recreate the old one and when I went to save the new one after adding a couple of widgets I couldn’t - got this message:

§EmonCMS Error

Message: Error: Could not save Dashboard. parsererror
Route: dashboard/edit?id=13
Line: 1014
Column: 69

Cheers

Richard

Hello @RichardinCancale can you check which emonSD version you have and the PHP version on the Admin > Info page?

It looks like your version is missing a couple of requirements, running this via SSH might solve it:

sudo apt install php-xml php-mbstring
sudo systemctl restart apache2

Would you be able to try this? If it works I will add this to the automated updated scripts.

Hi Trystran - thanks for your rapid reply.

The emonSD version is emonSD-01Feb24 and the PHP version is 8.1.27 (Zend version 4.1.27).

I tried entering the sudo commands in the console box on the serial config page, but didn’t seem to do anything - not sure if this is the right place though!

Many thanks

Richard

Ah not there, you need to SSH into the PI to do this but dont worry, I’ve now updated the update process to pull these in. Can you run a full update again?

Thanks - I’d forgotten about SSH-ing!

However after doing another full update the dashboard is still dead in exactly the same way.

Hmm ok, can you copy the output of your admin > info page?
and do you see any local changes flagged on Admin > Components?

When you do get this working which Im sure we will solve shortly, there’s now some new dashboard module improvements in the latest version :slight_smile: (need to run update again to get these - v3.1.0).

  • There’s a more comprehensive widget for adding text that supports setting font size, family, decoration, color and text rotation (no need to enter HTML styles to do this now).
  • There a new image widget for more easily adding images, including automatic image sizing.
  • There’s a new panel/container widget that allows much more customisation, replacing the four presets.
  • The process of editing and moving widgets is easier, unconfigured widgets are highlighted, widgets show subtle boundaries in editor mode, it’s clearer when you clicked on a widget from the toolbox when placement is active.

I expect there will be a few steps backwards with this work, but hopefully once we iron the issues it will be a sufficient number of steps forward to make it worthwhile. Two other bits of work in the pipeline are:

  • Rendering the charts directly rather than via iframes (faster load times and cleaner implementation),
  • A new responsive dashboard layout option

System Information

System Information

Emoncms

Server

  • CPU: Cortex-A72 | 1 Threads(s) | - Sockets(s) | 108.00MIPS |
  • OS: Linux 6.1.0-rpi8-rpi-v8
  • Host: emonpi | emonpi | (192.168.1.173)
  • Date: 2026-09-17 13:32:09 BST
  • Uptime: 13:32:09 up 31 min, 0 user, load average: 0.14, 0.12, 0.09

Memory

  • RAM: Used: 30.35% | Total: 908.4 MB | Used: 275.68 MB | Free: 632.72 MB
  • Swap: Used: 0.00% | Total: 100 MB | Used: 0 B | Free: 100 MB

Disk

  • /: Used: 67.71% | Total: 4.39 GB | Used: 2.97 GB | Free: 1.2 GB | Read Load: 0.19 B/s | Write Load: 0 B/s | Load Time: 916 days 4 hours 13 mins
  • /boot/firmware: Used: 18.51% | Total: 509.99 MB | Used: 94.42 MB | Free: 415.57 MB | Read Load: n/a | Write Load: n/a | Load Time: n/a
  • /var/opt/emoncms: Used: 8.65% | Total: 9.68 GB | Used: 856.87 MB | Free: 8.35 GB | Read Load: 0 B/s | Write Load: 0 B/s | Load Time: 916 days 4 hours 13 mins
  • /var/log: Used: 12.35% | Total: 50 MB | Used: 6.18 MB | Free: 43.82 MB | Read Load: n/a | Write Load: n/a | Load Time: n/a

HTTP

  • Server: Apache/2.4.57 (Raspbian) HTTP/1.1 CGI/1.1 80

MySQL

  • Version: 10.11.3-MariaDB-1+rpi1
  • Host: 127.0.0.1 (127.0.0.1)
  • Date: 2026-09-17 13:32:09 (UTC 01:00)
  • Stats: Uptime: 1902 Threads: 5 Questions: 610 Slow queries: 0 Opens: 50 Open tables: 43 Queries per second avg: 0.320

PHP

  • Version: 8.1.27 (Zend Version 4.1.27)
  • Run user: User: www-data Group: www-data video Script Owner: pi
  • Modules: apache2handler , calendar , Core , ctype , curl , date , exif , FFI , fileinfo , filter , ftp , gd , gettext , hash , iconv , json , libxml , mbstring , mosquitto v0.4.0, mysqli , mysqlnd vmysqlnd 8.1.27, openssl , pcre , PDO , pdo_mysql , Phar , posix , readline , redis v6.0.3-dev, Reflection , session , shmop , sockets , sodium , SPL , standard , sysvmsg , sysvsem , sysvshm , tokenizer , Zend OPcache , zlib

Redis

  • Redis Server: 7.0.11
  • PHP Redis: 6.0.3-dev
  • Host: localhost:6379
  • Uptime: 0 days

MQTT Server

  • Version: Mosquitto 2.0.11
  • Host: localhost:1883 (127.0.0.1)

Pi

  • Model: Raspberry Pi 4 Model B Rev 1.5 - 1GB (Sony UK)
  • Serial num.: 1000000058E43E92
  • GPU Temperature: 49.1°C
  • File-system: read-write
  • emonpiRelease: emonSD-01Feb24
Client Information

Client Information

  • Browser: Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6.1 Mobile/15E148 Safari/604.1
  • IP: 192.168.1.68
  • Client Hostname: iphone-badger.home

No local changes, all on stable branch

I will get your image version running here, try to replicate and fix that way, will update shortly.