Vulnerabilities
Two Joomla Upload Paths from Public Form to PHP Execution
CISA’s July 10 KEV action joined iCagenda and Balbooa Forms in one response queue, but their public upload paths, Joomla-version conditions, repairs, and evidence differ; the first fixes are iCagenda 4.0.8/3.9.15 and Balbooa 2.4.1, while the current reviewed releases are 4.0.11 and 2.4.2.

In this article
1 July 10 joined two incident clocks, not two mechanisms
On 10 July 2026, CISA placed CVE-2026-48939 and CVE-2026-56291 in the Known Exploited Vulnerabilities catalog and assigned both a 13 July remediation deadline for covered federal systems. That action is the decisive reason to investigate the iCagenda and Balbooa Forms defects together: it put two already exploited Joomla extension upload paths into the same operational queue. It is not evidence of a common operator, shared infrastructure, a coordinated campaign, or even the same software mistake. The public sources identify different discovery histories, different vulnerable functions, different repairs, and different conditions between accepting a file and executing it. Treating “two Joomla uploads” as one generic bug would erase precisely the distinctions an exposure owner needs to decide whether a site was vulnerable, whether it could have executed the stored content, and what must be verified after updating.
The clocks had already started before the KEV entry. JoomliC says automated exploitation of iCagenda began on 15 June at 08:00 UTC, the day it released iCagenda 4.0.8 for Joomla 4 through 6; it followed with the legacy Joomla 3 repair, 3.9.15, on 16 June. The Joomla CNA record for CVE-2026-48939 appeared on 20 June. CISA’s exploitation assessment moved from no public evidence to proof-of-concept evidence on 2 July and to active exploitation on 10 July. The Balbooa investigation began through a hosting-provider abuse notice and a raw live-site access log on 8 July, followed by private disclosure that day. Balbooa released Forms 2.4.1 and the CNA published CVE-2026-56291 on 9 July; CISA marked it active and added it to KEV the next day. Those sequences justify urgent compromise review, but neither supplies a victim count or enduring cross-incident indicator.
1.1 Put functions, versions, and interim controls on one map first
iCagenda fails at both the action entry and the attachment-write chain. In 4.0.7, Site\Controller\SubmitController::submit() checked a session token but did not enforce the submitAccess audience or bind the menu item to the submit view before model entry. SubmitModel::submit() then passed the attachment to frontendFileUpload(), which ultimately used Joomla\Filesystem\File::upload() to write below the default images/icagenda/frontend/attachments/ destination without the MediaHelper::canUpload() decisions added later. JoomliC’s affected subranges are 3.2.1–3.6.14 on Joomla 2.5, 3.2.1–3.9.14 on Joomla 3, 3.8.0–4.0.7 on Joomla 4, 3.9.0–4.0.7 on Joomla 5, and 3.9.14–4.0.7 on Joomla 6 before 6.1.2. The first repairs are 4.0.8 for Joomla 4–6 and 3.9.15 for Joomla 3; the current reviewed 4.x release is 4.0.11. Joomla 2.5 is unsupported, so 3.9.15 is not a repair for that platform.
Balbooa Forms exposes form.uploadAttachmentFile and writes through FormModel::uploadAttachmentFile(). In 2.4.0 and earlier, neither an account nor a CSRF token was required to reach the model; File::makeSafe() cleaned filename material but retained an extension derived from the client name before storage below images/baforms/uploads/form-<id>/. The CNA and NVD range is 1.0–2.4.0. Version 2.4.1 first added field-derived extension policy, optional MIME policy, a server-generated random name, and CSRF protection; 2.4.2 is the current reviewed release. Both paths require a permanent upgrade. Until upgrade and verification are complete, disable or tightly restrict the affected public submission surface and enforce no-script handling on the resolved upload directories. Those measures can interrupt reachability or the final storage-to-execution transition, but they do not repair old code or remove files written before the update.
1.2 Applicability begins with product, core, and handler state
An actionable inventory row needs more than a Joomla core version and a CVE flag. It should capture the extension package and exact installed release, whether the affected frontend feature is enabled and reachable, the configured submission audience or form fields, the resolved filesystem destination, and the web server’s handler policy for that destination. Disabled menus and unpublished forms deserve examination because presentation state does not necessarily remove a routable component task, while files written before an update can remain directly served. Alternate image roots, reverse-proxy mappings, per-directory configuration, PHP-FPM routing, and managed-hosting templates can also make the effective execution boundary differ from the apparent Joomla configuration.
The iCagenda matrix has two related but non-identical outcomes. JoomliC’s bulletin says the guest event-submission weakness affected the named Joomla generations: an unauthorized request could create a published-but-unapproved event that was not visible as an approved event. The bulletin and first-hand incident report scope the arbitrary executable attachment outcome to Joomla 6.0.0 through 6.1.1, where the earlier framework rejection did not stop the tested PHP upload. Thus an iCagenda site on an older generation may still have exposed the action even if its core media layer prevented the reported code-execution result. An iCagenda site on the affected Joomla 6 interval could satisfy both conditions: a caller outside the configured audience could reach processing, and an attachment retaining a server-executable type could be stored below a web-served media path.
The Balbooa record has a different graph. Forms 2.4.0 and earlier exposed a frontend attachment task whose controller-to-model handoff did not require an account or a CSRF token, and whose model trusted type information carried by the client filename. The first-hand report places the destination below images/baforms/uploads/form-<id>/. Storage becomes remote code execution only where the effective server configuration maps the stored type to an interpreter; a directory configured for inert download can break that final transition without repairing the task. The public evidence does not establish that every affected installation had an executable handler, so the precise conclusion is “unauthenticated arbitrary upload with an RCE outcome under executable storage,” not “every 2.4.0 site necessarily executed the file.”
2 iCagenda let a valid token reach an unauthorized action
The iCagenda failure begins before the attachment writer. A comparison of the official 4.0.7 and 4.0.8 component packages shows that the vulnerable controller possessed a CSRF check but did not enforce the component’s configured submission audience when the action executed. A public page can legitimately establish an anonymous session and issue its token; the observed request carried such a session token rather than forging or defeating Joomla’s token algorithm. Because that value is neither form- nor action-specific and authenticates no identity or permission, accepting it still leaves the controller to answer separately whether the caller may submit.
The evidence is pinned directly to vendor artifacts, not a reconstructed example. The official 4.0.7 outer package has SHA-256 F12E38D16F7C6CDF9BFD4BDE9AB2351F8123C78E09B1DB0846371EB42FB30537, and its nested com_icagenda.zip has 0143757AE58104A75634672D2C2BDFDD08753EEB9435AA058CDA49123C361D4C. The 4.0.8 outer and component hashes are respectively BE3788DAAEF85B903B540685EEBEEC2BF3257ED2CC02159F11FBDDF5E707CE74 and 2CB539DD2B118042B713D438932C2473BBDC72096ED8489474778F34BF8C17E0. In the nested component, Site\Controller\SubmitController::submit() in 4.0.7 began with $this->checkToken(), obtained the menu-item identifier, validated the form, and called the model. It did not compare authorized view levels with submitAccess or prove that the item selected iCagenda’s submit view. Menu visibility was therefore not action-time enforcement.
2.1 A session token never answered the permission question
Authorization also cannot be delegated to the menu. Joomla menus describe navigation and can apply view access, but the component action remains the point at which data is validated and persisted. In 4.0.7, a caller-controlled item identifier entered the action without a same-action proof that it resolved to the intended com_icagenda submission link. If an operator hid a menu item or assigned it to registered users, the visible interface changed; the processing routine still needed to reject identities outside that policy. This is a general controller rule with a concrete consequence here: once the request crossed into the model, iCagenda could create an event record and process the accompanying file before the application had established that the caller was allowed to submit.
JoomliC distinguishes the event consequence from the executable-upload consequence. Across the affected Joomla-generation ranges, a guest could create an event that was published in storage but not approved and therefore not exposed as an approved event in normal presentation. On Joomla 6.0.0 through 6.1.1, the same reachable flow could additionally carry an attachment through a media-policy gap described in the next chapter. This is why classification history should not be flattened. The initial incident analysis and earlier Joomla CNA history emphasized missing access control, CWE-284; the CNA record was changed on 5 July to the current CWE-434 dangerous-file-upload classification. The former identifies the action layer that admitted the wrong audience, while the current record names the file-handling weakness that produced code execution. They describe layers and record history, not two interchangeable labels that should be asserted as simultaneously authoritative.
For defenders, the distinction guides log interpretation. A session-establishing request or a valid token is not suspicious by itself, and neither is a rejected guest submission proof of exploitation. The reported iCagenda sequence becomes significant when public session or token context is followed by a submission request and then by retrieval of a newly stored attachment from the component’s frontend attachment tree. The observed user agent icagenda-batch/1.0 can help pivot through retained logs, but it is mutable client text, not a canonical indicator. Detection should preserve the behavior and timing without making the investigation depend on that string.
2.2 Version 4.0.8 moved audience and menu policy into the action
Version 4.0.8 places three gates before any model side effect. checkToken() still compares the current session token. The controller then obtains the identity’s authorized view levels and the component’s submitAccess policy: anonymous use is accepted only when the public level is explicitly allowed, while an authenticated identity must intersect the configured set. Finally, the supplied menu item must exist and link exactly to index.php?option=com_icagenda&view=submit. The gates answer different questions—current-session origin, submission authorization, and whether presentation metadata names the intended action—so removing any one reopens a different control gap.
Operational verification should assert these branches without attempting code execution. In an owned staging copy with the fixed package, configure a non-public submission audience and confirm that an anonymous request is rejected before any event or attachment state is committed. Confirm that an authenticated identity outside the allowed view levels is also rejected, while an explicitly authorized identity can submit a benign business file. Repeat the negative case with a missing or invalid token and with an item identifier that does not resolve to the iCagenda submit view. The acceptance evidence is the decision order—authorization and menu binding before model effects—not merely an error message rendered by the frontend.
3 iCagenda carried caller type into public attachment storage
Once the 4.0.7 controller admitted a request, the 4.x model supplied the second half of the reported chain. SubmitModel::submit() passed the jform attachment to frontendFileUpload() without asking Joomla’s media policy whether it could be uploaded. The sink derived the extension from the client name, normalized the basename, retained the extension through collision handling, and used the Joomla Framework Joomla\Filesystem\File::upload() move-only sink below icagenda/frontend/attachments/. With the default image root, that is images/icagenda/frontend/attachments/.
The API boundaries matter. File::getExt() extracts an extension but does not approve it; name normalization does not decide whether a type is safe; and the Framework File::upload() used by 4.0.7 moves the temporary file without applying Joomla CMS safe-file policy. MediaHelper::canUpload() is the missing 4.x media-policy decision. The legacy 3.9.14 line differs: its Joomla CMS/JFile upload wrappers apply the default safe-file gate. Static review of the 4.0.7 Framework sink therefore cannot establish executable placement for every Joomla 3 combination.
3.1 Version 4.0.7 retained the extension through the write sink
The vulnerable 4.0.7 transition can be described without an exploit body. The request contributed a file object whose name contained a basename and extension. The sink separated those parts, sanitized or slugified the basename, and joined the original extension back onto the stored name. Collision handling changed the basename while retaining that extension. Finally, Joomla\Filesystem\File::upload($src, $dest, false) moved the temporary file and the event retained its relative path. Cleaning the basename reduced punctuation and traversal-style filename risk; it did not transform a forbidden executable type into an allowed attachment.
The destination supplies the final environmental condition: a file below the document root becomes code only when the web server routes its stored type to an interpreter. JoomliC and the first-hand report both scope the reproduced upload-to-shell outcome to Joomla 6.0.0–6.1.1 and say earlier generations blocked the unsafe upload in the tested configuration; JoomliC further says Joomla 6.1.2 restored the framework block. The CNA/NVD CWE-434 classification, CVSS v4 score of 10.0, and CISA active-exploitation status must therefore be read with that boundary. The missing media check allowed caller-controlled type to reach a public attachment target, and the affected Joomla 6 interval permitted the reported PHP execution transition, but that does not establish execution under every server mapping or every affected Joomla generation. A no-script rule can break the final transition without preventing an unauthorized event, while an older Joomla safe-file gate can reject the tested type without enforcing iCagenda’s audience.
3.2 Two media gates repaired different transaction boundaries
Version 4.0.8 adds MediaHelper::canUpload($file) twice. The first call appears in SubmitModel::submit() before the model invokes frontendFileUpload(). It protects the event transaction: an unacceptable attachment should be rejected before the event path treats the file as successfully processed or commits related state. The second call appears at the entry to frontendFileUpload(). It protects the write routine itself, so another present or future caller cannot bypass the policy simply by reaching the reusable sink through a different model path. The checks look redundant only if transaction integrity and sink hardening are treated as the same requirement; they are not.
The fix does not randomize iCagenda attachment names, and Balbooa’s repair shape cannot be imported into this path. The iCagenda sink still constructs a readable name and retains an allowed extension; its new guarantee is that Joomla media policy approves the file before the write at both the event caller and sink boundary. Later releases add defense in depth: 4.0.9 introduced media-folder no-script files and further checker/upload hardening, while 4.0.11 adjusted SubmitModel extension retention for permitted non-image attachments. Those changes make the current supported release the deployment target and leave 4.0.8 as the first fixed baseline, not a permanent destination.
Safe validation should make both boundaries observable. In owned staging, an authorized user should be able to submit each required business file type and recover the expected attachment with the intended content and disposition. An inert fixture representing a forbidden extension, and a separate benign extension/content mismatch, should be rejected before the temporary file is moved and before an event or attachment record is committed. A test can instrument application decisions or compare database and filesystem state; it does not need an executable marker. Server behavior should be tested through a configuration-level or otherwise non-executing observation that proves the resolved attachment directory cannot invoke PHP or another server-side handler.
4 Balbooa trusted the client name across an anonymous handoff
Balbooa Forms reached the same possible endpoint—server execution of a publicly stored attachment—through a different control graph. The first-hand incident report identifies the exposed frontend task as form.uploadAttachmentFile, the model routine as FormModel::uploadAttachmentFile(), and the storage tree as images/baforms/uploads/form-<id>/. In the reviewed 2.4.0 package, the frontend task required neither an authenticated account nor Session::checkToken(). The controller passed the uploaded file into the model, where the implementation derived an extension from the caller-provided filename, applied Joomla File::makeSafe() to filename material, reattached the extension, and wrote the result below the web-served per-form directory.
Balbooa’s public changelog confirms the releases and repair controls, but it does not expose source history that can be compared as directly as the iCagenda packages. The form.uploadAttachmentFile route, controller-to-model handoff, and 2.4.0/2.4.1 package differences therefore come from the first-hand package analysis cited in the references; the vendor changelog independently corroborates the fixed release and four controls. That evidence establishes the vulnerable path and repair shape, but the absent public source history cannot be rewritten as an independent repository diff.
4.1 Filename cleaning did not create a type policy
File::makeSafe() addresses a filename problem. It removes characters that Joomla does not want in a stored name, reducing ambiguity and unsafe path material. It does not inspect whether a form field permits the extension, whether declared MIME agrees with content, whether the file should be stored under a server-generated name, or whether the destination can execute the result. In the reported 2.4.0 path, the model extracted the extension from client-controlled name data and preserved it after cleaning. An executable suffix can remain executable even when every character in the basename is “safe.” Conflating sanitization with authorization is therefore the Balbooa mechanism’s central mistake.
The anonymous handoff amplified that mistake. With no authentication requirement and no CSRF token check at the frontend upload task, any internet client able to reach the route could present a file to the model. The absence of a server-side per-field extension policy meant the Upload File field’s intended business constraint did not govern the write. The public destination then made the result retrievable; if the web-server handler executed the retained type in that directory, retrieval crossed from arbitrary upload to remote code execution. The CNA record captures versions 1.0 through 2.4.0, rates the issue critical, and CISA’s 10 July active-exploitation assessment requires retrospective review; update-only closure is inadequate.
The surviving incident trail began outside the application: a hosting-provider abuse notice and raw live-site access log on July 8 led to private disclosure and the 2.4.1 release the next day. Preserve that notice unchanged and record every source timezone; provider and egress evidence may be as important as origin requests after local rotation. Correlate upload-task POSTs, later requests into the per-form tree, file creation times, process and PHP telemetry, outbound connections, web-server errors, and hosting-panel activity on one timeline. A route, user agent, address, or status code cannot establish attribution by itself, especially where shared hosting and reverse proxies distort context. The available material establishes neither an operator, campaign scale, nor a connection to the iCagenda automation; the shared KEV date joins response priority only.
4.2 Version 2.4.1 split repair across four independent controls
Balbooa’s official 2.4.1 changelog lists four independent controls. Server-side allowed-extension validation asks whether the configured Upload File field permits the type. The optional MIME Types setting adds content policy, but existing fields may retain an empty value after upgrade and need individual review. A random server-side name removes client control over the stored filename. CSRF protection requires the current session token, but it is not authentication, so the repaired public form may remain intentionally anonymous. A valid token does not make a forbidden type safe, and random naming cannot replace type policy.
Version 2.4.2, released on 16 July, is the current reviewed Balbooa target. Its changelog adds random naming for signature and PDF outputs and corrects caching behavior. Those changes should not blur the earlier boundary: frontend attachment upload was repaired in 2.4.1, and the signature/PDF naming change in 2.4.2 concerns other outputs. Operators should deploy the current supported package, then verify the specific frontend controls; a later version number alone does not prove them. Record trusted package origin, installed extension metadata, loaded code, configured field allowlists and MIME policy, and effective storage location; reinstall from a trusted package if a partial update or manual emergency edit makes package identity uncertain.
The upload tree needs an independent no-script contract even after 2.4.1 or 2.4.2. Configure the effective Apache, Nginx, IIS, PHP-FPM, or managed-hosting layer so that images/baforms/uploads/ and every per-form descendant are served only as inert content or denied, never routed to a server-side interpreter. Verify that rule through a non-executing staging observation and preserve the configuration and response as evidence. This containment cannot replace the extension fix, but it limits the consequence of a future validation regression. If the host was exposed while 2.4.0 or earlier was reachable, preserve evidence before package mutation, search the entire Joomla tree and sibling virtual hosts, rebuild compromised systems from trusted packages or known-good infrastructure, and rotate Joomla, database, hosting, SSH, SMTP, and API credentials; an empty-looking upload folder does not close the incident.
5 The same RCE endpoint has two different prerequisite graphs
Both investigations end at the same dangerous state: an unauthenticated Internet request can leave attacker-chosen content in a web-served directory, and a compatible server handler can interpret it as code. That endpoint explains why the records belong in one urgent queue after CISA added both to the Known Exploited Vulnerabilities catalog on July 10. It does not make their paths interchangeable. CVE-2026-48939 crosses iCagenda's public event-submission action and attachment writer; CVE-2026-56291 crosses Balbooa Forms' frontend upload task and attachment model. Product, version, Joomla generation, configuration, storage, and handler state still determine exposure.
5.1 Exposure preserves Joomla generation, extension version, and handler state
| Decision plane | iCagenda / CVE-2026-48939 | Balbooa Forms / CVE-2026-56291 |
|---|---|---|
| Affected extension boundary | NVD ranges are ≥3.2.1 and <3.9.15, and ≥4.0.0 and <4.0.8; JoomliC maps subranges by Joomla generation. First repaired in 4.0.8 for Joomla 4–6 and 3.9.15 for Joomla 3. Joomla 2.5 has no current supported repair and must migrate or remove iCagenda. | CNA/NVD range is 1.0 through 2.4.0; first repaired in 2.4.1. |
| Additional execution condition | JoomliC limits the executable-upload condition to Joomla 6.0.0–6.1.1; execution still depends on how the stored type is served. | The record does not publish an equivalent Joomla-generation limit; code execution still requires the web server to execute the stored type. |
| Untrusted transition | Public submit action could reach an attachment sink that retained the caller's extension without the media-policy checks later added in 4.0.8. | Public frontend upload task could reach a model writer that cleaned the name but did not enforce the configured allowed type before storing beneath a web-served tree. |
| Repair shape | Audience and submit-view menu authorization at the controller; media validation at caller and sink boundaries. | Field-derived extension policy, optional MIME policy when configured, randomized stored names, and a session-token check that is neither authentication nor authorization. |
| Current reviewed release | 4.0.11, released July 18; later than the first fixes and carrying subsequent upload hardening and compatibility corrections. | 2.4.2, released July 16; its additional randomization for signature/PDF outputs is not the original frontend-upload repair. |
5.2 Two kinds of evidence answer different questions
The official iCagenda 4.0.7/4.0.8 packages establish the controller and model transitions, JoomliC supplies the Joomla-generation matrix and exploitation start time, and the site request sequence shows that the path was exercised in an observed environment. Code reachability and single-site incident evidence reinforce one another but prove different things. Balbooa has a different evidence shape: the vendor changelog independently confirms the 2.4.1 date and four controls; the exact task, function, filename handling, destination, and before/after package differences come from the first-hand package analysis in the references; the provider notice and raw log establish activity only on the investigated site. None of those sources establishes campaign size, a shared operator, or a durable infrastructure cluster.
iCagenda’s classification history also describes two real layers. The earlier CWE-284 label points to an action that admitted the wrong audience, while the current CWE-434 assignment, changed on July 5, points to the attachment pipeline’s failure to reject a dangerous type before a web-served write. Balbooa’s CWE-434 is consistent with its missing server-side type policy. Regardless of label or severity, a stored file becomes code only if the server maps its type to an executable handler. Inert delivery breaks that transition but does not erase an unauthorized upload, and an upgrade does not remove earlier changes. Release, Joomla generation, upload policy, destination, and handler therefore remain separate facts; only execution or post-upload activity evidence supports marking an asset compromised.
6 Live evidence turns an update into incident response
Finding a vulnerable version and public upload surface makes this more than an update task. Both records entered KEV because exploitation was known. JoomliC says automated iCagenda exploitation began at 08:00 UTC on June 15; the Balbooa investigation began July 8 with a hosting-provider abuse notice and raw access log. Those clocks require containment and preservation before package replacement and recovery.
6.1 Request sequences need filesystem, process, and provider context
The iCagenda report describes a sequence with session and token acquisition context, a public event-submission request, and a later request for the newly stored attachment. It also records the user agent icagenda-batch/1.0. That string is useful pivot context because it can help recover nearby requests in retained logs, but it is fully controlled by the requester and cannot be treated as a canonical indicator. A match may be spoofed, and a different string does not make the same behavior benign. The defensible analytic unit is the sequence: acquisition of form state, upload-bearing submission, creation under the iCagenda frontend attachment tree, retrieval of the resulting object, and any process or network activity that follows.
The Balbooa report begins from a different surviving artifact: a provider saw abusive behavior and returned a notice plus raw access evidence. For a local investigation, the meaningful chain joins a frontend upload request to subsequent requests below images/baforms/uploads/form-<id>/, then asks whether the web worker spawned a child process, opened an outbound connection, changed application or server configuration, or wrote elsewhere. A request for an unusual file under that tree is a lead, not self-proving execution. The file may be inert, the request may have failed, the handler may not exist, or the timestamps may reflect a later administrative operation. Conversely, a missing access-log line cannot clear a host if logs rolled over, an upstream proxy retained the request instead, or the attacker invoked an already placed file through another path.
Time normalization is part of the case. Preserve original time zone and precision for provider notices, proxy and origin logs, PHP or application logs, operating-system events, database changes, and file metadata; record conversions while retaining the original values. Account for buffering, clock skew, deployment resets, and archive timestamps. Hash suspicious files before moving them, capture ownership and mode, and record both the logical Joomla path and resolved filesystem path. Correlation can then join submission, file creation, and worker egress without pretending one row proves the chain.
Expand scope along three axes: search adjacent time windows for the behavior without narrowing the query to one user agent or filename; inspect other writable web trees, extension or template code, scheduled execution, administrative state, database content, and server configuration; and examine sibling sites or hosting accounts that share workers, credentials, document-root parents, or deployment identity. Neither report establishes a common actor, victim count, or shared infrastructure, so correlation must come from the environment's evidence.
6.2 Isolation and preservation precede package mutation
If evidence suggests upload, retrieval, execution, or unexplained post-exploitation, isolate the affected workload from public ingress and unnecessary egress while retaining a controlled responder path. On a disposable instance behind a load balancer, that may mean removing it from rotation and snapshotting the relevant disks and runtime metadata. On shared hosting, it may require provider coordination to prevent collateral impact and to obtain logs unavailable to the tenant. The containment record should state exactly what changed—routing, firewall policy, service state, credentials, or account suspension—and when, because the response itself changes later observations.
Before using Joomla's updater, deleting a suspicious attachment, reinstalling an extension, clearing caches, or restarting PHP, preserve the evidence those actions can overwrite. At minimum, collect the available reverse-proxy and origin logs, application and PHP logs, current process and network state where the platform exposes them, relevant document-root and configuration metadata, extension manifests, installed-version records, scheduled execution points, administrative-account state, and cryptographic hashes of suspicious or changed files. Preserve the provider's original notice and raw log as received. Document gaps honestly: a shared host may not expose process memory, a CDN may hold only sampled requests, and a backup may have run after the suspected event.
Only after that preservation point should package mutation begin. A trusted reinstall or rebuild is preferable to hand-deleting the visible upload because the public paths allow code execution and therefore allow changes outside the original storage directory. Obtain packages through the vendor's authenticated distribution path, retain their source URL, release identifier, download time, and digest, and compare the installed state against a known-good release or rebuild from known-good infrastructure. Joomla's extension updater may deliver a valid vendor release, but its success banner proves only that the update transaction reported success; it does not prove that every old file was removed, that an overridden update source was trustworthy, that the PHP runtime loaded the new code, or that prior compromise was absent.
Recovery rotates the authority the affected runtime could reach: administrator credentials, sessions, database and hosting credentials, deployment keys, and reusable API tokens. Establish a trusted administration channel and rebuild or clean the environment before introducing replacements. If the site shared credentials or a hosting identity with sibling properties, include them in credential scope even without a matching upload path.
7 Repair is complete only when package and storage controls both answer
A repaired file on disk is only one plane of truth. The operator must select the intended vendor release; Joomla must report and execute it; the new decisions must run; storage must remain non-executable; and benign tests must show allowed use succeeds while a forbidden type is rejected before durable commit. No single plane stands in for the whole repair.
7.1 Verify the trusted package, installed state, runtime state, and current release
Start with release intent. For supported iCagenda installations on Joomla 4–6, 4.0.8 is the first security fix and the current 4.x line has reached 4.0.11 from July 18; 3.9.15 carries the repair for legacy Joomla 3. Balbooa Forms was first fixed in 2.4.1 and its current line has reached 2.4.2 from July 16. Record the branch choice together with Joomla and PHP compatibility, extension dependencies, and vendor support state. If production cannot yet accept the current release, document the exact first-fixed fallback and compensating controls as a time-bounded exception rather than silently treating an old release as current.
Then verify distribution. Preserve the authoritative vendor page or update-source URL, package version, retrieval time, and digest; verify any signature or authenticated channel provided. Link an internal mirror's artifact to the reviewed vendor object; a filename such as 4.0.11.zip is not provenance. A digest from the same system that supplied the package detects corruption but does not independently establish vendor provenance. Do not use third-party repackaged bundles for recovery.
Compare installed truth with package truth: check Joomla's manifest records, deployed extension files, and stale files no longer owned by the package. Confirm iCagenda's audience/menu enforcement and two media-validation boundaries, or Balbooa's field-derived extension policy, optional MIME handling when configured, randomized naming, and session-token check. This checks control presence without reconstructing an exploit. For opcode caches, immutable images, multiple PHP pools, or clusters, replace instances in a controlled way and prove every serving node loaded the repaired artifact.
7.2 Benign tests check rejection, commit order, and inert delivery
Validation belongs on an owned staging environment or an explicitly authorized production maintenance path, using non-executable fixtures. Begin with a positive control: submit a small business-appropriate file type that the field policy allows, verify the intended access and workflow, and record the returned application state, server-side stored name, destination, and delivery headers. This confirms that the security update did not merely disable the feature. The test must follow the site's real audience configuration: an iCagenda public-submission test should be public only when that audience is intentionally configured, while an authenticated test should use an identity with the expected authorized view level and the actual submit-view menu.
For the negative control, use an inert file whose extension or declared media type is outside the configured policy and whose content cannot execute. Verify that the application rejects it, that no durable object appears in the upload tree or temporary publish location, that the database does not commit a misleading attachment reference, and that the rejection is logged at an actionable level without exposing sensitive paths to the requester. A renamed benign text fixture can test policy disagreement safely; an executable marker, command payload, or live web shell is unnecessary and creates its own incident. Do not probe third-party sites, and do not present an HTTP request body that turns validation into a reusable exploit recipe.
The commit order is part of the result. In iCagenda 4.0.8, the outer MediaHelper::canUpload() check protects the event-submission transaction before it calls the writer, while the inner check protects the reusable frontendFileUpload() boundary. A negative test should therefore look for both absence of the file and a consistent event record; a rejected response alongside a partially committed object is a failure. In Balbooa 2.4.1, validate the extension rule derived from the field, an optional MIME restriction only when configured, the non-client-controlled stored name, and the session-token check as independent observations. The token result is not proof of identity or permission, and passing one layer—such as random naming—does not prove that a forbidden type was rejected.
Test the web-server contract without placing code. Inspect effective Apache, nginx, IIS, PHP-FPM, container, or hosting configuration for the resolved upload directory. Use a configuration-level test or harmless non-executing staging observable to confirm inert delivery or denial. Account for aliases, per-directory overrides, nested configuration, case behavior, alternate extensions, and virtual hosts. Conclude only that the tested configuration made that destination inert at that time.
| Verification plane | Required evidence | Claim it supports |
|---|---|---|
| Provenance | Vendor source, release identity, retrieval time, digest or signature, mirror linkage. | The selected artifact is the intended vendor release. |
| Installed and runtime state | Manifest/database version, package-file comparison, node inventory, cache or instance replacement evidence. | Every serving node runs the intended repaired code. |
| Application policy | Authorized positive control and inert forbidden-type negative control, including filesystem and database observations. | Allowed work succeeds and forbidden input is rejected before durable commit. |
| Storage policy | Resolved path, effective handler configuration, non-executing staging observation. | The tested upload destination cannot transition stored content into code execution. |
| Incident state | Preserved logs/files, search scope, rebuild or cleanup record, credential rotation and monitoring results. | The organization addressed possible prior exploitation as well as future requests. |
A failed business-file positive control is not a security success, and a rejection accompanied by a written object also fails. Capture response, application and log decision, database and filesystem effects, stored-name behavior, and delivery together. This provides a reproducible acceptance record without dangerous content.
8 Fleet closure is an evidence record, not an update message
The July 13 KEV due date compressed remediation, but urgency does not change closure. A queued update or one representative scan cannot close a fleet. Closure joins inventory, exposure decisions, preservation and recovery, artifact provenance, per-node runtime verification, safe application and storage tests, credential work, and an owner for every exception.
8.1 Inventory, recover, rotate, and search beyond the upload roots
Begin with an inventory that names the site, public hostname, Joomla version, PHP/runtime and web-server handler, installed iCagenda or Balbooa version, extension source, public-form exposure, configured upload fields and allowed types, resolved storage path, execution policy, serving nodes, hosting account, and owner. Discovery must inspect deployed extension records and files, not only a configuration-management catalog that may have missed manual installations. Record “not installed,” “installed but route disabled,” “affected and reachable,” “affected but handler-inert,” “repaired and verified,” and “suspected compromise” as distinct states. The handler-inert state lowers the RCE consequence but does not erase the unauthorized-upload defect or the obligation to update.
Any site with evidence of suspicious upload, retrieval, or execution follows the incident branch, not the routine-update branch. Preserve and isolate it, rebuild from trusted packages or known-good infrastructure, compare content and configuration, remove persistence only after it has been recorded, and search outside the named extension directories. Rotate secrets and sessions reachable from the web runtime after the environment is trusted. Review sibling sites and shared control-plane accounts. Restore service from a known-good state, then monitor the reconstructed behavioral sequence—form-state acquisition, submission, storage access, process behavior, and egress—without relying on one mutable string or filename.
Every “not affected” decision needs a reason and evidence date. Examples include an authoritative inventory showing the extension absent, an installed version above the affected range with package provenance and runtime confirmation, or a permanently removed route combined with an upgrade that eliminates the vulnerable code. “No alert,” “WAF enabled,” “Joomla 5,” or “the upload folder looked empty” is not sufficient across both CVEs. The first two miss visibility and mechanism differences; the last two ignore retained access-control defects, log loss, alternate storage, and post-exploitation cleanup.
8.2 Keep the no-script contract and rollback proof alive
The durable architectural rule is simple to state and easy to lose: user-controlled storage must not execute. Enforce it at the web server or hosting layer for every resolved upload destination, including extension media, temporary processing, generated documents, and tenant-specific subdirectories. Keep allowed-type policy and optional MIME policy when configured at the application boundary, generate server-side names where the product supports it, and require the appropriate action authorization and session-token checks. These controls are complementary. A no-script rule contains the terminal RCE transition but does not authorize an upload; a session token shows only that the request supplied a value tied to the current session context, not that the requester is authenticated or authorized; filename randomization does not make a dangerous type safe; and an allowlist does not protect a directory whose handler policy later changes.
Treat that storage policy as a deployable contract. Version the Apache, nginx, IIS, container, or platform configuration; test it when a new extension creates a directory, a hosting migration changes handler inheritance, or a platform image is replaced. Monitor for new executable-handler mappings and for files appearing in user-content trees with types outside the business policy. A later iCagenda release adding media-folder no-script files is defense in depth, but centrally enforced server policy should not depend on every extension shipping the correct per-directory file or on the server honoring that file type.
Rollback protection closes the last operational gap. Configuration management and deployment tooling should reject artifacts below the documented security floor, alert when an internal mirror serves an older package, and verify the installed/runtime version after rollback or disaster recovery. Backups and golden images made before June or July can faithfully restore the vulnerable extensions; a successful restore must therefore reapply security releases and storage policy before receiving traffic. The exception register should name the owner, compensating controls, expiry, and migration plan for any legacy Joomla 3 site held at iCagenda 3.9.15 or any environment unable to take the current supported release.
The final case record links each public hostname to its applicability decision, evidence preserved before mutation, trusted package and digest, installed and runtime confirmation for every node, benign positive and negative tests, effective no-script observation, incident search and recovery, credential rotation, and monitoring owner. CISA’s July 10 action created one response deadline for two actively exploited upload records, but reliable closure still requires proving two different control graphs. The shared endpoint warrants urgency; the differences determine what must be fixed, what must be searched, and what evidence is strong enough to say the work is done.
Research record
9Evidence, objects, and sources
The material below preserves the identifiers and references used in this report.
9.1Research objects
Products, actors, techniques, affected objects, and control points discussed in the report.
iCagenda public event attachment upload vulnerability recorded by CISA as actively exploited
Balbooa Forms frontend attachment upload vulnerability recorded by CISA as actively exploited
Affected ranges; first fixed in 3.9.15 and 4.0.8, with 4.0.11 the current reviewed release
Affected range; first fixed in 2.4.1, with 2.4.2 the current reviewed release
iCagenda executable-attachment outcome boundary stated by JoomliC and the first-hand report
Mutable context observed in the iCagenda exploitation sequence, not a canonical indicator
Default iCagenda frontend attachment directory
Default Balbooa Forms upload root with per-form subdirectories
9.2Event chronology
- iCagenda exploitation and first fixes
JoomliC says automated exploitation began at 08:00 UTC on June 15; 4.0.8 shipped that day and the legacy Joomla 3 repair, 3.9.15, shipped the next day.
- CVE-2026-48939 published
The Joomla CNA published the iCagenda vulnerability record.
- CISA records proof-of-concept evidence
CISA changed its exploitation assessment for CVE-2026-48939 from no public evidence to proof-of-concept evidence.
- Balbooa incident disclosed and first fixed
A hosting-provider abuse notice triggered investigation and private disclosure on July 8; version 2.4.1 and CVE-2026-56291 followed the next day.
- Both CVEs enter CISA KEV
CISA marked both vulnerabilities actively exploited, added them to KEV, and set a July 13 remediation deadline for covered federal systems.
- Current reviewed releases published
Balbooa Forms 2.4.2 shipped July 16 and iCagenda 4.0.11 shipped July 18.
9.3Sources and material
- CISA Known Exploited Vulnerabilities cataloghttps://www.cisa.gov/known-exploited-vulnerabilities-catalog
- CISA KEV filtered record for CVE-2026-48939https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2026-48939
- CISA KEV filtered record for CVE-2026-56291https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2026-56291
- CVE.org record for CVE-2026-48939https://www.cve.org/CVERecord?id=CVE-2026-48939
- NVD record and change history for CVE-2026-48939https://nvd.nist.gov/vuln/detail/CVE-2026-48939
- CVE.org record for CVE-2026-56291https://www.cve.org/CVERecord?id=CVE-2026-56291
- NVD record and change history for CVE-2026-56291https://nvd.nist.gov/vuln/detail/CVE-2026-56291
- Joomla CNA Security Centrehttps://developer.joomla.org/security-centre.html
- JoomliC iCagenda security update bulletinhttps://www.joomlic.com/news/icagenda-security-update
- Official iCagenda release historyhttps://www.joomlic.com/download/icagenda
- Official iCagenda 4.0.7 package used for comparisonhttps://www.joomlic.com/download/icagenda/icagenda-core-4-0-7
- Official iCagenda 4.0.8 security release and packagehttps://www.joomlic.com/download/icagenda/icagenda-core-4-0-8
- Official iCagenda 4.0.9 hardening noteshttps://www.joomlic.com/download/icagenda/icagenda-core-4-0-9
- Official iCagenda 4.0.10 release noteshttps://www.joomlic.com/download/icagenda/icagenda-core-4-0-10
- Official iCagenda 4.0.11 release noteshttps://www.joomlic.com/download/icagenda/icagenda-core-4-0-11
- iCagenda 3.9.15 legacy Joomla 3 repairhttps://www.joomlic.com/download/icagenda/icagenda-core-3-9-15
- Phil Taylor first-hand iCagenda incident and package reporthttps://mysites.guru/blog/icagenda-zero-day-file-upload-rce.pdf
- Official Balbooa Forms changeloghttps://www.balbooa.com/help/joomla-forms-documentation/basics/changelog
- Official Balbooa Forms product and distribution channelhttps://www.balbooa.com/joomla-forms
- Phil Taylor first-hand Balbooa Forms incident and 2.4.1 package reporthttps://mysites.guru/blog/balbooa-forms-unauthenticated-file-upload-flaw/
- Joomla CMS MediaHelper APIhttps://api.joomla.org/cms-5/classes/Joomla-CMS-Helper-MediaHelper.html
- Joomla CMS File APIhttps://api.joomla.org/cms-5/classes/Joomla-CMS-Filesystem-File.html
- Joomla CSRF protection manualhttps://manual.joomla.org/docs/security/csrf-protection/
- Joomla access-control manualhttps://manual.joomla.org/docs/general-concepts/acl/
- Official Joomla 6.1.2 download pagehttps://downloads.joomla.org/cms/joomla6/6-1-2
- OWASP File Upload Cheat Sheet for supplementary control guidancehttps://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html