← Blog

Joomla

Joomla security audit: acht checks voordat je code raakt

Een klant geeft je SSH toegang tot een Joomla site die ze hebben overgenomen van een bureau dat in 2022 verdween. Voor je iets fixt, audit je. Dit is onze lijst.

Jacob Molkenboer· Oprichter · A Brand New Company· 3 jun 2026· 7 min
Gesloten leren logboek, messing sleutel op kaart, stempel, inktkussen, groen lakzegel, rood touwlabel op ivoren bureau.

Een klant mailt je op een dinsdag. Ze hebben net een Nederlandse groothandel overgenomen waarvan de website op Joomla draait. Het oorspronkelijke bureau werd stil in 2022. De overdracht is één Bitwarden share met SSH, FTP en een /administrator/ URL. Ze willen vrijdag een feature live hebben.

Raak de code nog niet aan. Eerst auditen.

We draaien dezelfde achtpuntencheck op elke geërfde Joomla site die op ons bureau belandt. Het kost ongeveer drie uur en het heeft van alles boven water gehaald. Van een vier jaar oud Super User account dat niemand meer kende, tot een stille image-gallery extensie die op een bekende RCE zat. De volgorde doet ertoe. En wat je met elke bevinding doet ook.

Een opmerking over timing: geautomatiseerde CMS scanners crawlen het publieke IPv4 ruwweg wekelijks. Een vergeten Joomla install achter een vergeten subdomein wordt binnen uren na de volgende sweep gefingerprint, en elke extensie die matcht met een rij in de Vulnerable Extensions List gaat in de wachtrij voor een exploitatiepoging. Het audit-venster is niet optioneel.

1. Core versie en de end-of-life klok

Open de admin footer of lees libraries/src/Version.php direct. Map dat tegen het officiële Joomla support venster. Joomla 3.x ging end-of-life op 17 augustus 2023. Joomla 4 krijgt security fixes tot zijn eigen einde. Joomla 5 is de huidige lijn. De gepubliceerde roadmap staat op docs.joomla.org/Joomla!_CMS_versions.

Staat de site op 3.x, dan audit je geen website, dan audit je een risico. Documenteer de versie, de EOL datum en de migratiekosten in dezelfde alinea van je overdrachtsnotitie. De klant moet die drie cijfers naast elkaar zien.

grep -E "RELEASE|MAINTENANCE" libraries/src/Version.php
# RELEASE = '4.4'
# MAINTENANCE = '8'

2. De extensions inventarisatie tegen de VEL

De Joomla Vulnerable Extensions List op vel.joomla.org is de belangrijkste bron die je dit uur gaat gebruiken. Elke third-party extensie die op de site staat gaat in een spreadsheet met: naam, versie, leverancier, installatiedatum, laatste update.

Vervolgens kruisreferentie je elke rij met de VEL. Elke match is een bevinding. Elke extensie waarvan de leverancierssite een 404 geeft is een bevinding. Elke extensie die voor het laatst geüpdatet is voor 2022 is een bevinding, zelfs als VEL schoon is, want het ontbreken van een recente update op een CMS extensie betekent meestal dat de ontwikkelaar is weggelopen.

Trek de lijst uit de database, niet uit de admin UI. Admin pagina's kunnen liegen als er iets half kapot is.

SELECT name, element, type, manifest_cache
FROM jos_extensions
WHERE type IN ('component','module','plugin')
  AND protected = 0
ORDER BY name;

Vervang jos_ door de echte table prefix uit configuration.php.

3. configuration.php blootstelling

Het configuration bestand bevat de database username, het wachtwoord en de host in plaintext. Ook de secret key voor session tokens staat erin. Er zijn twee vragen die je binnen vijf minuten moet kunnen beantwoorden.

Eén: is het bestand leesbaar via het web? Ga direct naar https://site.tld/configuration.php. Dat hoort blanco terug te komen (PHP parseert het bestand, maar het levert geen output op). Check daarna of er een backup kopie bestaat op configuration.php.bak, configuration.php~, configuration.old of in /tmp/. Oudere Joomla migraties laten die continu achter. Ze zijn leesbaar.

Twee: welke permissions staan op het bestand? Het hoort 444 te zijn, eigendom van de web user. Vind je 644 op een shared host, dan zijn de credentials al blootgesteld aan elke andere tenant op die machine.

find . -maxdepth 2 -iname "configuration*" -ls

4. Super User accounts en het admin login oppervlak

Open /administrator/index.php en check de gebruikerslijst. Je let op drie dingen.

Eén: hoeveel Super User accounts bestaan er, en welke daarvan horen bij mensen die de huidige klant kent. Zet de rest uit. Verwijder ze nog niet, je hebt ze nodig voor de audit trail.

Twee: zit er een extra laag voor het /administrator/ pad (htpasswd, IP allowlist, Cloudflare Access)? Zo niet, dan is het pad publiek te enumereren en alleen gerate-limit door Joomla's eigen brute-force logica. Wij zetten een htpasswd ervoor op elke site die we erven, voor we iets anders doen.

Drie: staat tweefactor aan op elke overgebleven Super User? Joomla heeft sinds 3.2 ingebouwde 2FA. Staat het uit, zet het dan aan voor de overgebleven accounts voor je de auditsessie verlaat.

Waarschuwing

Vind je een Super User account dat genoemd is naar iemand die het oorspronkelijke bureau heeft verlaten, verwijder het dan niet tijdens de audit. Zet het uit, leg het e-mailadres vast en vraag de klant of dat adres nog onder hun controle valt. Verschillende geërfde sites waar we mee gewerkt hebben hadden verlaten adressen die inmiddels door iemand anders waren geclaimd.

5. Bestandspermissies en eigenaarschap

Het klassieke Joomla deployment verhaal: iemand draaide chmod -R 777 om een vastlopende install te fixen, en zette het daarna nooit meer terug. Je vindt dit op ongeveer één op de drie geërfde sites.

De correcte stand op een Linux host: directories 755, bestanden 644, configuration.php 444, eigendom van de web user (vaak www-data of een per-site user op cPanel-achtige hosts). Alles wat schrijfbaar is en dat niet hoeft te zijn is een bevinding. Alles wat eigendom is van root binnen de webroot is een bevinding.

find . -type f -perm /o+w -ls    # world-writable files
find . -type d -perm /o+w -ls    # world-writable directories
find . -user root -ls            # files owned by root inside webroot

De tmp/ en cache/ directories horen schrijfbaar te zijn, maar hun parent niet. Oude Akeeba backup archieven die binnen administrator/components/com_akeeba/backup/ staan zijn een bevinding ongeacht de permissions, want er zit vaak een complete database dump in.

6. Database user privileges

Lees configuration.php voor de MySQL credentials, log dan in op de database en check de grants op die user.

SHOW GRANTS FOR 'site_user'@'localhost';

De Joomla user heeft SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX nodig op de eigen database. Geen GRANT OPTION, geen SUPER, en geen toegang tot andere databases. Vind je ALL PRIVILEGES ON *.*, dan komt dat in de eerste alinea van het rapport.

Nu je toch verbonden bent, check de jos_users tabel op accounts die je niet in de admin UI zag, en de jos_session tabel op actieve sessions ouder dan een dag. Beide kunnen wijzen op backdoor toegang.

7. Cron jobs, scheduled tasks en de vergeten one-liner

Dit is de check die voor ons de meeste levende compromittaties heeft opgeleverd. Kijk op drie plekken.

Server crontab voor de web user (crontab -l -u www-data), system cron (/etc/cron.d/, /etc/cron.daily/) en Joomla's eigen Scheduled Tasks onder System → Manage → Scheduled Tasks in Joomla 4 en 5.

Wat je zoekt: elke cron entry die een URL ophaalt met curl of wget, elke entry die een PHP bestand draait buiten de Joomla webroot, elke entry die /tmp/ aanraakt. Wij hebben cron jobs gevonden die elke zes uur een verse kopie van een webshell binnenhaalden van een domein dat het oorspronkelijke bureau had laten verlopen, en dat een nieuwe eigenaar inmiddels had geregistreerd.

Voor gepubliceerde advisories over Joomla core zelf is het Joomla Security Centre de autoritatieve bron. Lees het een keer voor de audit, dan weet je welke CVE patronen je zoekt.

8. Back-up en rollback stand

Als laatste, en het minst spannend. Voor je één byte verandert, moet je zeker weten dat je kunt terugrollen naar de staat waarin de site nu staat.

De vraag die je moet beantwoorden: als ik over vijf minuten een destructief commando draai, kan de klant dan binnen twee uur weer live zijn? Is het antwoord nee, dan bouw je eerst een back-up. Akeeba Backup is dé tool voor Joomla, en het JPA formaat restoret schoon via Kickstart. Wij installeren Akeeba op elke geërfde site als stap nul, configureren het zodat het naar off-site opslag schrijft (S3, Backblaze of sftp naar een aparte host), en draaien een test restore naar een staging URL voor we iets aanraken.

Takeaway

Een back-up die je nooit hebt teruggezet is geen back-up. Het is een map.

De audit afsluiten

Drie uur, acht checks, één rapport. De oplevering is één document met drie kolommen: bevinding, ernst, fixkosten in uren. De klant tekent af welke bevindingen worden gefikst voor het feature werk start, en welke we wegzetten als volgend kwartaal.

Ongeveer een derde van de tijd eindigt de audit de opdracht. De site staat op Joomla 3, de extensies zijn verlaten, de credentials zijn al in het wild, en de eerlijke aanbeveling is een rebuild in plaats van een patch. Toen we de groothandel site uit de opening van dit stuk erfden, eindigde het daar ook zo. We hebben hem opnieuw gebouwd op een moderne stack als onderdeel van een legacy migratie, en de nieuwe site is opgeleverd met dezelfde achtpuntenaudit ingebakken in het overdrachtsdocument, voor wie hem hierna erft.

Het kleinste dat je vandaag kunt doen: open /administrator/index.php op de oudste Joomla site in je portfolio, tel de Super User accounts en vraag jezelf af hoeveel van die namen je nog herkent.

Kern

Een Joomla site die je erft is een risico totdat je de audit hebt gedaan. Drie uur, acht checks, één rapport met bevinding, ernst en fixkosten.

FAQ

Hoe lang duurt de achtpuntenaudit?

Ongeveer drie uur op een kleine tot middelgrote Joomla site. Grotere installs met tientallen third-party extensies trekken het richting een hele dag, vooral omdat de VEL kruisreferentie en de extensions inventarisatie langer duren.

Patchen jullie Joomla 3 sites nog ter plekke?

Zelden. Joomla 3 ging end-of-life in augustus 2023, dus een Joomla 3 audit eindigt bijna altijd met een migratie aanbeveling in plaats van een patch lijst. Een dode branch patchen koopt je weken, geen jaren.

Wat is veruit de meest voorkomende bevinding?

Stale third-party extensies waarvan de leverancierssite niet meer resolvet. Ruwweg twee derde van de geërfde sites die we auditen heeft minstens één extensie die voor het laatst voor 2022 is geüpdatet, ongeacht of VEL hem noemt.

Kan ik de rest overslaan als ik de admin URL verberg?

Nee. /administrator/ verbergen helpt tegen opportunistische bots, maar het doet niets tegen een geauthenticeerde extensie exploit, een gelekte database user of een vergeten cron job. De acht checks bestaan omdat de dreigingen in verschillende lagen leven.

joomlasecuritylegacy sitesmigrationphpmysql

Iets bouwen?

Start een project