No Code Attached Yet
avatar bhuvan-somisetty
bhuvan-somisetty
20 Aug 2026

Steps to reproduce the issue

In Joomla's content versioning system, Joomla\CMS\Table\ContentHistory::getSha1() is used to compute a normalized SHA-1 hash of a content item's payload to determine if meaningful changes have occurred before inserting a new version in #__history.

When an object payload with nested JSON column data (e.g. params, metadata, images, urls) is passed to ContentHistory::getSha1():

$data = (object) [
    'title'       => 'Original Article Title',
    'modified_by' => 42,
    'version'     => 3,
    'params'      => (object) [
        'title'      => 'Custom Form Header',
        'show_title' => 1,
    ],
];

$historyTable = new \Joomla\CMS\Table\ContentHistory($db);
$contentType  = new \Joomla\CMS\Table\ContentType($db);
$hash         = $historyTable->getSha1($data, $contentType);

Version

5.4-dev / 6.0-dev / 6.1-dev / 6.2-dev

Expected result

  1. $data should remain intact and immutable without losing its properties (modified_by, version, etc.).
  2. Normalization of nested properties (converting ints, bools, nulls to strings) should be applied to the nested object properties ($data->params->show_title), keeping data hierarchy intact.
  3. Top-level properties such as $data->title must not be overwritten by sub-properties of nested objects.

Actual result

  1. In-place object mutation / property stripping: Because $object = \is_object($jsonData) ? $jsonData : json_decode($jsonData); operates by reference on the caller's object without cloning, unset($object->$remove) permanently strips properties like modified_by, modified, version, and checked_out from the caller's live object in memory.
  2. Root object pollution & property overwriting: In libraries/src/Table/ContentHistory.php (line 138):
    if (\is_object($value)) {
        // Go one level down for JSON column values
        foreach ($value as $subName => $subValue) {
            $object->$subName = \is_int($subValue) || \is_bool($subValue) || $subValue === null ? (string) $subValue : $subValue;
        }
    }
    Assigning to $object->$subName flattens all nested parameters onto the root object, leaving $value un-normalized and overwriting any root properties that share the same key (e.g., if params has a title or alias, $object->title gets overwritten by the parameter value).

System Information

Joomla 5.4-dev / 6.0-dev / 6.1-dev / 6.2-dev
PHP 8.2 / 8.3 / 8.4

Additional Comments

Root Cause:

  1. In libraries/src/Table/ContentHistory.php, line 138 should target $value->$subName (or $object->$name->$subName) instead of $object->$subName.
  2. Input $jsonData should be cloned / decoupled before modifying or unsetting properties to prevent mutating the caller's live table/model instances.
avatar bhuvan-somisetty bhuvan-somisetty - open - 20 Aug 2026
avatar joomla-cms-bot joomla-cms-bot - change - 20 Aug 2026
Labels Added: No Code Attached Yet
avatar joomla-cms-bot joomla-cms-bot - labeled - 20 Aug 2026
avatar bhuvan-somisetty bhuvan-somisetty - change - 20 Aug 2026
The description was changed
avatar bhuvan-somisetty bhuvan-somisetty - edited - 20 Aug 2026

Add a Comment

Login with GitHub to post a comment