Problem/Motivation
Follow-up to #3625451: Search strings are output unescaped on the Zeitgeist report page (5.x) and #3625471: Search strings are output unescaped on the Zeitgeist report page (6.x): the 7.x multicolumn report outputs recorded search strings unescaped. ReportMulticolumn::page() passes them to '#theme' => 'table', which prints cell contents verbatim, so any visitor with search content can inject markup that runs in the browser of a user with access site reports viewing the report.
Drupal 7 is unsupported, so this is handled in the public queue. This is expected to be the last Drupal 7 release, so the change also fixes every other defect found while reviewing the branch.
Other security-relevant defects:
- The inline separator of both blocks is output unfiltered. It is editable with administer search, which is not a restricted permission, and shown to every visitor.
- A search longer than 80 characters makes the search form fail with an HTTP 500 error, for any visitor: the value exceeds the
searchcolumn, and MySQL runs in strict mode under Drupal 7.
Other defects:
- The "Top searches" block ignored the "validate search strings" setting.
- The "Latest searches" block escaped search strings twice when showing their category.
rel="nofollow"was never emitted: both blocks passed it outside the link attributes.- The "Top searches" block was also cached by core, per role, which Zeitgeist does not clear when a search is recorded.
- The settings form could not be saved with its defaults: the cache durations default to 0, which their validation rejected.
- Enabling Zeitgeist together with X Autoload failed with "Call to undefined function xautoload()", and uninstalling it with X Autoload disabled failed on missing classes.
- Uninstalling left every Zeitgeist variable behind.
- Update 7001 cleared the nonexistent
bootstrapcache bin. - Quarter spans started on the wrong month from April on.
- The Views report linked to
search/[category]/..., an unreplaced token, and stripped markup from the searches in its links. - Every view on the site got a "Zeitgeist settings" contextual link.
- The default view granted access with search content.
- Without Database logging, the Zeitgeist report menu entry was broken.
- A non-numeric day count in the report path caused a
TypeErroron PHP 8. - Every recorded search rewrote a variable, flushing the bootstrap variable cache.
- The settings form rebuilt all module data on each display.
- PHP 8.1 and 8.2 deprecations: float array keys in the multicolumn report,
${}string interpolation.
Steps to reproduce
- Enable search and Zeitgeist, grant search content to anonymous users, and choose the "multicolumn" report page type.
- As an anonymous user, submit the search form with
<b>test</b>. - As an administrator, visit
admin/reports/search/zeitgeist: "test" is rendered in bold, meaning the markup was output as HTML instead of text.
Proposed resolution
- Escape search strings with
check_plain()in the multicolumn report. - Filter the block separators with
filter_xss_admin(). - Truncate recorded searches to the column lengths.
- Fix the other defects listed above.
- Views: a field handler links each search to itself, replacing the path rewrite.
- Updates: 7002 stops core from caching the "Top searches" block; 7003 points administrators to the issue about Zeitgeist's future, #3625488: Future of Zeitgeist after Drupal 7.
- Documentation: README.md and INSTALL.md updated, with the missing Views and X Autoload prerequisites.
Remaining tasks
- Review and commit to 7.x-1.x.
- Release 7.x-1.3.
User interface changes
- Cache durations of 0, meaning no caching, can be saved.
- The Zeitgeist settings and report pages show a notice pointing to #3625488: Future of Zeitgeist after Drupal 7.
- Views: the Search field gets a "Link this field to the search it records" option.
API changes
Statistics::getLatestSearches() keys are now always safe HTML. BlockInterface declares settings().
Data model changes
Updates 7002 and 7003. Searches from the search page now record the search path, like the search block does, instead of the module name; both are identical for core searches.
AI disclosure
Fixes developed with Claude Opus 5.5.
Comments
Comment #2
fgmComment #4
fgmFixed in 7.x-1.3