Moodle pluginQuestion bank, Moodle 4.5 and 5.0, version 1.0.43

Overview

Question Hub (qbank_questionhub) is a plugin for the Moodle question bank. You use it to find question packages on the Question Hub, import them into your course with a preview, and publish your own categories as packages that other teachers can bring into their Moodle.

The Question Hub at hub.cblum.ch is a separate service, also run by Cyril Blum. The plugin is aimed at teachers at Swiss upper secondary schools (Gymnasium) and needs Moodle 4.5 or later. It is tested with Moodle 4.5 and 5.0.

Screenshots

These are the same two images as in the Moodle plugins directory. Cyril Blum took them on 14.10.2026 on a Moodle test site, in the test course DEMO101 with the test account «Admin User». The questions shown come from his own question collection. No student data is visible.

The captures show an older plugin version. Some labels have changed since, for example the status «Synchronised» is now called «Linked». Select an image to preview it on this page and use the arrows to move between the captures.

Detailed description

Built into the question bank

The plugin adds a «Question Hub» tab to the question bank with the areas «Browse», «My library» and «My packages». The question list gets an action to export single questions, a bulk action to publish selected questions and a «Hub» column. It shows whether a question matches the linked version on the Hub, was modified since, or is new.

Finding and importing packages

Packages can be filtered by keyword, subject, course level (GF, SF, EF, FF) and canton. If the author allows it, the Hub shows a preview of the questions without model answers and feedback. Before every import you see which questions will be added, updated or skipped. Questions changed both on the Hub and in your Moodle appear as conflicts, and you decide for each question which version applies or whether to keep both. If you take the Hub version, your version stays in the question’s version history. Without a linked Hub account you can browse and import public packages.

Publishing your own categories

A question bank category is published with its subcategories as a package in Moodle XML format. You enter a title, summary, release note, tags, subject, level and canton and choose a licence (CC BY 4.0, CC BY-SA 4.0 or CC0) and the visibility. Public packages are open educational resources. Private ones are visible only to people whose access request you approve. Optionally, the Hub also commits every version to a GitHub repository.

Versions, push and pull

Version numbers follow the pattern 1.2.3 and cannot be changed. «Push» publishes local changes as a new version, «Pull» brings in a newer version from the Hub. Before a push, the plugin shows the changed questions line by line. Under «Review changes» you keep or discard local changes one by one. Older versions can be restored with a preview, and you can withdraw single versions or a whole package from the Hub. Questions already imported stay in the other Moodle sites.

Variants and change proposals

From an imported package you can create your own variant on the Hub. Your category is then linked to the variant, and you propose your changes to the original through the Hub. A variant keeps the licence of the original and names it as its source. «Switch variant» links a category to the original or another variant after a preview.

Cleaning up

The plugin finds identical duplicates and keeps the oldest question of each group. Questions with the same name but different content in one category are listed for comparison. Questions used in a quiz are never deleted.

Permissions and backup

By default, teachers may browse and export, while editing teachers and managers may also import and publish. A Moodle backup with questions includes the links to the Hub, so they survive a restore. How accounts are linked and how imports are checked is shown under Data flows and Security.

Architecture

Question Hub consists of the plugin and the Hub. The plugin is the only component installed in a school Moodle. The Hub at hub.cblum.ch is a separate web platform with an API that stores accounts and question packages in versions. Every Moodle with the plugin can publish and import packages.

Architecture: school Moodle with the plugin, the teacher’s browser, Question Hub, optional GitHub and e-mail. Arrows show who opens the connection.SCHOOLSchool MoodlePlugin qbank_questionhubQuestion banks of the coursesAccounts and grades stay hereTeacher’s browserMoodle interface,sign-in on the HubHUB.CBLUM.CHQuestion HubWebsite and APITeacher accountsPackage details, roles andaccess requestsQuestion packages as Moodle XML,immutable versionswith SHA-256 checksumGitHuboptional, per packagerepository of thepackage ownerE-mailPassword reset,access requests,change proposalsHTTPSHTTPSHTTPSHTTPSSTARTTLSArchitecture: school Moodle with the plugin, the teacher’s browser, Question Hub, optional GitHub and e-mail. Arrows show who opens the connection.Teacher’s browserSCHOOLSchool MoodlePlugin qbank_questionhubQuestion banks of the coursesHUB.CBLUM.CHQuestion HubWebsite and API, accountsPackage details and rolesQuestion packages as Moodle XML,versions with SHA-256GitHuboptional,per packageE-mailPassword reset,access requestsHTTPSHTTPSHTTPSHTTPSSTARTTLS
The arrows show who opens a connection. All connections start from the school Moodle or the teacher’s browser, and the Hub never connects to the school Moodle. Moodle therefore only needs outgoing HTTPS to hub.cblum.ch. Depending on the action, questions flow in either direction.
In the school Moodle

Plugin qbank_questionhub

«Question Hub» tab in the question bank, «Hub» column in the question list, import with preview and publishing. In its own tables it stores tokens, a log and the mapping of questions to package versions.

Separate service

Question Hub

Website and API for accounts, packages, versions, variants and change proposals. Public packages can be browsed and imported without an account. You need a Hub account to publish or to use private packages.

Optional

GitHub mirror

Whoever manages a package can link it to their own GitHub repository. The Hub then stores every new version there as an XML file and sets a version tag. The plugin itself never connects to GitHub.

Data flows

Publishing and push

  1. You choose a category or single questions and enter the package details.
  2. The plugin exports the questions as Moodle XML and checks the package first.Check in the plugin
  3. Moodle sends the package with your token to the Hub.HTTPSToken
  4. The Hub checks XML, size, question types and media and stores a new, immutable version.SHA-256
  5. If the package is linked to GitHub, the Hub also commits the version to the repository.optional

Import and pull

  1. You look for a package. Public packages are available without a linked account.
  2. Moodle downloads the chosen version from the Hub.HTTPS
  3. The plugin checks the package and removes active content if the setting is on.Check in the plugin
  4. The preview shows new, updated and skipped questions as well as conflicts.
  5. After you confirm, the questions go into the question bank. The previous version of an updated question stays in its version history.

Both sequences show where the questions go. Moodle opens the connection on import too.

Sign-in: linking a Moodle account to a Hub account

To publish, push or use private packages, each teacher links their Moodle account to their Hub account. There are two ways. The Moodle password never goes to the Hub, and the Hub password is never entered in Moodle.

Option A

OAuth 2.0 with PKCE

You choose «Connect Question Hub Account» in the plugin and sign in directly on hub.cblum.ch. Moodle receives a token that is valid for 30 days. The address of your Moodle has to be approved on the Hub. On disconnect, the Hub revokes the token.

Option B

Personal access token

You create a token on the Hub with a lifetime of your choice and paste it into the plugin. This works without approval of your Moodle. The Hub stores only a SHA-256 hash of the token. On disconnect, the plugin deletes the token in Moodle; you delete it on the Hub yourself.

Linking with OAuth 2.0 and PKCE in eight steps between school Moodle, browser and Question HubSchool MoodleBrowserQuestion Hub1 Create a secret2 Redirect with hash of the secret3 Sign in with Hub account4 One-time code back to Moodle5 Code and secret, server to server6 Token with Hub ID, name, e-mail7 Every further request uses the token8 On disconnect: revoke the token
Blue arrows are requests, orange arrows responses, dots mark the way through the browser. Only someone who also knows the secret from step 1 can redeem the one-time code from step 4 (PKCE, RFC 7636). The secret leaves the Moodle server only in step 5, directly to the Hub. The code is valid for ten minutes and only once.

The setting «Allow Teacher Account Linking» lets administrators switch linking off. Teachers can then only browse and import public packages.

Security and encryption

The cards show how the plugin and the Hub protect connections, credentials and packages. The yellow card names what is deliberately not used.

Transport

The plugin and the browser talk to the Hub over HTTPS, and the default Hub address is https://hub.cblum.ch. The Hub accepts only TLS 1.2 and 1.3, redirects HTTP to HTTPS and sends HSTS (checked on 12.11.2026).

Tokens

OAuth tokens are valid for 30 days and are revoked on the Hub on disconnect. The Hub stores personal access tokens only as a SHA-256 hash. In the Moodle database the token is stored without extra encryption, so it is as safe as the database itself.

Hub accounts

The Hub stores passwords as scrypt hashes with their own salt. Sign-in and registration need a captcha and are rate-limited per client. A password reset link is valid for one hour and only once, and only its SHA-256 hash is stored.

GitHub token

Using the GitHub mirror means storing a GitHub token on the Hub. The Hub keeps it encrypted with AES-256-GCM and uses it only for commits through the GitHub API over HTTPS.

Package versions

Published versions are immutable, and a correction gets a new version number. The Hub computes a SHA-256 checksum for every version and sends it along with the download. The plugin detects changed questions through its own SHA-256 values of the question content.

XML checks

The plugin and the Hub reject XML with DOCTYPE, ENTITY or XInclude declarations. The checks cover, among others, multiple choice, true/false, short answer, numerical, matching, embedded answers (Cloze) and essay questions, embedded images and files, size limits (50 MB per package, 10 MB per file) and scripts in SVG files.

Active content

Because anyone can publish on the Hub, the plugin removes active content such as scripts and embedded frames by default, using Moodle’s HTML cleaning. Administrators can switch on an exception for CodeRunner questions. If active content is kept, the teacher has to confirm the import explicitly. Scripts created only at run time are not detected.

Code review

A self-review on 26.10.2026 with AI support and standard tools found seven issues, fixed in version 1.0.33. Every change runs tests with Moodle 4.5 and 5.0, the Moodle coding style check and Semgrep on GitHub. There has been no independent audit or penetration test.

Limits

Not used

Packages carry no digital signature. The checksum shows whether a file was changed, but does not protect against a tampered Hub. E-mails from the Hub are encrypted only on the way to the mail server (STARTTLS), not end to end.

Installation and configuration

Install the plugin from the Moodle plugins directory or put the source from GitHub into the folder question/bank/questionhub of your Moodle site:

git clone https://github.com/CyrilBlum/moodle-qbank_questionhub.git question/bank/questionhub
php admin/cli/upgrade.php --non-interactive
php admin/cli/purge_caches.php

The settings are under Site administration, Plugins, Question bank plugins, Question Hub:

  • Hub base URL, default https://hub.cblum.ch.
  • OAuth 2.0 client ID, default moodle-plugin-client. Change it only if the Hub operator asks you to.
  • Allow teacher account linking (on). When it is off, teachers can only browse and import public packages.
  • Remove active content on import (on).
  • Keep active content in CodeRunner questions (off), an exception to the previous setting.

«Test connection» checks whether the Hub is reachable and your own linked account is valid. For teachers to link their account with OAuth, the address of your Moodle has to be approved on the Hub. Write to apps@cblum.ch for this. You create a Hub account at hub.cblum.ch.

Files

The plugin follows the usual layout of a Moodle plugin:

Basics

  • version.php: name, version and required Moodle version.
  • settings.php: settings in site administration.

Pages

  • view.php: Hub view with search, import, library and your own packages.
  • publish.php: export and publish categories and questions.
  • review.php: review local changes since the linked version.
  • variants.php: compare questions with the same name but different content.
  • oauth_callback.php and disconnect.php: link and disconnect a Hub account.
  • testconnection.php: connection test from the settings.

Program logic

  • classes/: program logic, including the Hub client (api_client.php), sign-in and tokens (auth_manager.php), export (package_exporter.php), import (package_importer.php, qformat_xml_importer.php), the import check (preflight_validator.php), version comparison and links (release_diff.php, local_changes.php, publication_tracker.php), duplicates (duplicate_manager.php), the question bank integration (plugin_feature.php, navigation.php, question_action.php, bulk_publish_action.php, question_sync_column.php) and the privacy API (privacy/provider.php).

Database and backup

  • db/: capabilities (access.php), database tables (install.xml) and upgrade steps (upgrade.php).
  • backup/moodle2/: backup and restore of the Hub links.

Interface

  • templates/: Mustache templates of the interface.
  • amd/src/ and amd/build/: JavaScript modules and their minified builds.
  • lang/en/ and lang/de/: English and German strings.
  • pix/, styles.css: icon and styling.

Tools and tests

  • cli/: command-line export, import and self-test.
  • tests/ and .github/workflows/: automated tests that run on GitHub with Moodle 4.5 and 5.0.

Privacy

In the school Moodle

Plugin tables

  • Hub access token for each linked person, with Hub user ID, email address and display name of the Hub account
  • log of imports and publications with Moodle user ID, package ID, version, action and time
  • mapping of imported questions to package versions

Moodle’s privacy API can export and delete this data.

To the Hub

What the plugin sends

  • the access token, but not the Moodle username, name or email address
  • questions and package details only when someone publishes, pushes, forks or edits a package
  • for OAuth linking, the address of the Moodle site as the redirect address
On the Hub

Separate service

  • Hub account with email address, name, school, canton and password hash
  • packages with all versions, contributors and access requests

The Hub is a separate service with its own data processing.

Important

No personal data in questions

Questions must not contain personal data, so no student names or grades, also not in images or feedback. The plugin points this out but cannot prevent it technically. The plugin never transfers quiz attempts, answers, grades or participant lists.

Use and liability

The Hub may be unavailable at times, and authors can withdraw packages. Questions already imported stay in your Moodle. You are responsible for content you publish, including copyright and the licence you choose. Back up your course or question bank before larger imports.

Use is at your own risk. To the extent permitted by law, the plugin is provided without warranty of accuracy, completeness, availability or fitness for a particular purpose. To the extent permitted by law, liability for damage from use or unavailability is excluded, in particular for data loss, lost profit and consequential damage. Mandatory statutory rights and liability remain unaffected, in particular for intent or gross negligence and where liability for personal injury cannot be excluded. The source code is licensed under the GNU General Public License v3 or later.

Feedback and development

Found a problem or have an idea for Question Hub? Open an entry in the plugin’s GitHub issues or write to apps@cblum.ch.

The issues are public and can be read without logging in. A new entry needs a GitHub account. Do not post personal data there.

Source code and links

Repository: public. The source code is licensed under the GNU General Public License v3 or later.

The source code of the Hub is in its own repository, which is also public: Moodle-Question-Hub-Marketplace.

Repository status and links checked on 12.11.2026. Published in the Moodle plugins directory on 11.11.2026. Back to the project overview

DE