Until now, MDL Shield reviewed code after the fact: a release on the
Marketplace, or a branch you pointed us at. Pull request reviews move the
review to the moment the code is actually decided. Install the MDL Shield
GitHub App on a repository and every pull request gets a security review
before it merges, with the results posted straight to the PR and to your
dashboard.
The reviewer is the same one behind every MDL Shield review: an AI Moodle
security specialist that reads your change the way a human reviewer would,
understanding what the code does and how it fits into Moodle, not just
pattern-matching lines. It is not a linter and it does not replace
moodle-plugin-ci.
Pull request reviews are in free preview, and we'd love your help
putting them through their paces. Open the
Pull Requests tab in your dashboard and hit
Request access.
On the pull request
Three things land on the PR:
A check called MDL Shield review that passes or fails according to
the severity you choose to block on.
One summary comment that always shows the current state: every
finding, its severity, and its status.
An inline comment on the exact line for each finding, with the
description up front and the depth (context, risk assessment, suggested
fix) folded away until you want it.
mdlshieldBotcommented 2 hours ago • edited
MDL Shield security review
1 open finding (1 high) as of 9f3ab12.
SeverityFindingStatus
🟠 HIGHSort column from the request is concatenated into the report queryopen
🔵 LOWThe returnurl parameter reaches redirect() without a local-URL checkaccepted risk
▶Commands
Open the dashboard for full details and history.
All checks have failed
1 failing check
MDL Shield review Failing after 4m — Review complete — 1 open finding (1 high)
No conflicts with base branch
Merging can be performed automatically.
Merge pull requestYou can also merge this with the command line. View command line instructions.
The summary comment carries the current state; the check carries the verdict
Sort column from the request is concatenated into the report query
The sort request parameter is read as PARAM_RAW and interpolated straight into the ORDER BY clause, so whatever a user puts in it becomes part of the SQL that $DB->get_records_sql() executes.
Every enrolled user can open this report, so any student can steer the query.
▶Context
▶Risk assessment
▼Suggested fix
Accept only the columns the report can sort by and fall back to the default; read the parameter as PARAM_ALPHA.
Triage: reply !mdlshield dismiss, !mdlshield accept, or !mdlshield confirm.
AReply...
Resolve conversation
Each finding is an inline comment on the exact line, with the depth folded away
Findings in pre-existing code that your change interacts with are reported
too. On public repositories those never appear on the PR, only in your
dashboard, so a review can't hand a bystander a map of unfixed code.
Findings follow the code
Every push is reviewed, and findings are never re-reported push after push:
a finding stays open until a commit actually fixes it, and when one does, the
review resolves it and names the commit. If a later commit turns a latent risk
into a real one, the finding escalates, with the evidence.
classes/report/table.phpOutdated
55+ WHERE courseid = :courseid
56+ ORDER BY $sort";
mdlshieldBot2 hours ago • edited
🟠 [HIGH] · SQL injection
Sort column from the request is concatenated into the report query
▶Context
▶Risk assessment
▶Suggested fix
✅ Addressed in commit 7d1c0e2.
Triage: reply !mdlshield dismiss, !mdlshield accept, or !mdlshield confirm.
AReply...
Resolve conversation
alexc added 1 commit just now
AWhitelist the sortable columnsVerified7d1c0e2
mdlshieldBot reviewed just now
View reviewed changes
mdlshieldBotleft a comment
Reviewed 9f3ab12..7d1c0e2 (incremental) — no new findings; 1 resolved.
Resolved by this pass:
• 🟠 HIGH Sort column from the request is concatenated into the report query (classes/report/table.php:56) — addressed in 7d1c0e2
▶Review details
All checks have passed
1 successful check
MDL Shield review Successful after 2m — Review complete — no open findings
No conflicts with base branch
Merging can be performed automatically.
Merge pull requestYou can also merge this with the command line. View command line instructions.
Push the fix: the next review resolves the finding and credits the commit
Triage from the PR
Every finding's inline thread takes commands from the repository owner and
the users you trust. Reply on the finding to triage it, with a reason if you
have one:
!mdlshield accept Only course managers can reach the export page
dismiss, accept, confirm and resolve are the verbs. The bot
acknowledges with a thumbs up, appends the decision to the finding (who, and
why), and the check recomputes. !mdlshield review on the PR forces a
re-review, and so does the Re-run button on the check.
Settings in the repository, or on the site
A .mdlshield/config.yml on your default branch controls which pull requests
are reviewed and how: branch, label, author and path filters, the severity
that fails the check, what the check does when a review errors, who may issue
commands, and the Moodle version to review against.
fail_on:severity:high# the check fails on high and criticalon-error:open# an errored review never blocks a mergemoodle:versions: ["5.0"]
trusted_users: ["alexc"]
include:branches: ["main", "MOODLE_*_STABLE"]
exclude:paths: ["lang/**", "vendor/**"]
authors: ["dependabot[bot]"]
The same settings exist on the site, as account defaults and per-repository
settings, so you don't need a file at all. When there is one, it wins, key by
key. You can also give the reviewer private context about your plugin (what
it is for, who can reach it, known trust boundaries) that guides every review
and is never committed to your repository.
Your dashboard
The new Pull Requests tab lists every PR across your repositories with
its open findings and check state at a glance.
Pull requestFindingsCheckUpdated
Upgrade step for the new stats table
acme/moodle-report_example#43 by priya-m
—
just now
Add sortable course activity report
acme/moodle-report_example#42 by alexc · 2 reviews
—
3m ago
Bulk export of course notes as CSV
acme/moodle-report_example#41 by priya-m · 1 review
12
1d ago
Settings page for default block visibility
acme/moodle-block_example#17 by alexc · 1 review
1
2d ago
Fix capability check on the block config form
acme/moodle-block_example#16 by alexc · 3 reviews
—
4d ago
Experiment with cached report queries
acme/moodle-report_example#38 by alexc
—
9d ago
The Pull Requests tab: every PR across your repositories, open findings and check state at a glance
Every pull request gets a page in your dashboard with the full history of
review passes, every finding in full depth, and triage buttons that twin the
commands. This is the only place a finding's proof of concept ever appears:
it is never posted to GitHub. You can also authorise other people to view and
triage without giving them settings or billing.
Add sortable course activity report
Open
acme/moodle-report_example#42 · opened by alexc · 2 days ago
Check passedReviewed head 7d1c0e2 · 3m ago2nd review on this pull request
Findings (1)
Low Risk accepted
The returnurl parameter reaches redirect() without a local-URL check
View finding ›
classes/report/export.php:31
@@ -28,2 +28,5 @@ public function download(int $courseid): void
2828 public function download(int $courseid): void {
▸ Files reviewed (2)Moodle 5.0 · configuration from repository configuration file + account defaults · run 3f8c1a2b9e4d
3m ago
Reviewed 4e1d7aa..9f3ab12
Full review when the pull request opened · 6 files · 2 new findings
2d ago
Every pull request gets a page in your dashboard: findings in full depth, and the review history
Pull request reviews are in free preview, and we'd love your help
putting them through their paces. Open the
Pull Requests tab in your dashboard and hit
Request access.
Moodle has launched the Moodle Marketplace, the new home for every plugin
that used to live in the moodle.org plugins directory. It's a big step for the
ecosystem: one place to find, buy, and install plugins, with proper support for
commercial vendors for the first time.
We think that's worth celebrating. A healthier plugin economy means more
plugins, more maintainers who can afford to keep maintaining, and more code
running inside your Moodle sites. Which is exactly why we exist: a marketplace
tells you what a plugin does. An independent security review tells you what
its code actually does. MDL Shield tracks every plugin on the Marketplace,
reviews the code line by line, and puts the result on a public grade badge, so
"is it safe?" has an answer that doesn't depend on taking anyone's word for it.
Here's what the transition changes for you.
Free community reviews: unchanged
Non-commercial plugins listed on the Marketplace keep their free monthly
reviews. Verify you're the maintainer, run reviews, publish them, embed the
badge. Nothing about that flow changes.
Paid plugins: release reviews make way for Repository reviews
The Marketplace doesn't let us download paid plugins' released packages, so
release reviews of paid plugins are no longer possible. We detect this
automatically and tell you up front instead of failing halfway.
Any review that does get caught out by a Marketplace
download refusal is cancelled and the charge refunded automatically.
If you maintain a paid plugin, your path is a Repository review: connect
your Git repository (public or private, read-only deploy key) and we review the
code directly. In many ways it's the stronger option, since you can review
before you release, not after.
New: paid plugins can publish Repository reviews
Until now, publisher publication was reserved for plugins outside the
directory. That rule made no sense once paid Marketplace plugins lost their
release-review path, so we've changed it: if the Marketplace won't give us your
released package, you can become a verified publisher and take your
Repository reviews public, grade badge included. The published page states
plainly that the review covers your source repository rather than the
Marketplace package, so buyers know exactly what was reviewed.
You choose the disclosure level per review, which matters when your plugin is
closed source:
Full report: the complete review, findings and all.
Grade summary: just the grade and a plain verdict. No findings, no code
snippets, and for private repositories no repository location, branch, or
commit either. Your code and your repo stay yours; only the grade goes
public.
The small print
Your plugin page now shows whether the Marketplace lets us download your
releases, with a one-click re-check if you think we've got it wrong.
Every link, page, and email now says Moodle Marketplace, and plugin links
point at your plugin's Marketplace page. The directory served the community
well for a long time; its name is retired with honours.
If you run into anything the migration broke that we haven't caught, tell us
and we'll chase it.
Repository reviews have always been private to you, and by default they still
are. But if your plugin lives outside the moodle.org directory (internal,
closed source, or simply unlisted), there was no way to show anyone what your
review found. Now there is: become a verified publisher and publish those
reviews on a public page, under a publisher name you choose, whether that is
you, your team, or your company.
Verified identity, per-plugin approval
Publication is a trust feature, so it is gated twice. First we verify who
you are: request publication from any repository review, we check your
details by hand, and you receive a public publisher handle. Then each
repository and plugin combination needs a one-time publication approval;
once granted, you can publish any review of that plugin, current and future,
without asking again. Both gates exist to protect plugin authors: nobody can
stand up public reviews of code they don't control, and everything that goes
public is backed by an identity we have verified.
Full report, or just the grade
Every publication picks a disclosure level. Full report publishes the
whole review, findings and fix guidance included, just like a community
review. Summary publishes only the grade and whether any security issues
were found, and nothing else: all findings stay private to you. That is the option for closed-source
plugins that want credible proof of a security review without exposing any
internals.
Publish review
Choose what the public page shows.
Full report
The complete review: summary, findings, locations, and fix guidance. For open-source plugins that want full transparency.
Summary
Just the grade and whether any security issues were found. All findings stay private to you. For closed-source plugins that want a badge without exposing code or details.
Publishing makes the page and badge publicly visible at /reviews/publisher/lmscloud/local_example. You can unpublish at any time.
Every publication picks its disclosure level
For public repositories, a summary still pins down exactly which code the
review covered: branch or tag, commit, the commit's date, and the scope in
files and lines, so a grade can never quietly refer to different code.
Private repositories disclose even less: the reviewed-code details are left
off the summary entirely, revealing nothing about your repository, branches,
or commits.
No security issues were identified in this version.
L
LMSCloud
View publisher profile →
Identity verified by MDL Shield
Reviewed code
MOODLE_405_STABLE · 3fa9c21 · 2026-05-02
github.com/lmscloud/moodle-local_example
Scope
38 files · 6,214 lines
Release
2.4.1 (2026042900)
Reviewed
2026-07-09
Moodle version
4.5
A public summary: the grade goes public, the findings stay yours
A page and a badge for every plugin
Every verified publisher gets a public page listing their published plugins,
and every published plugin gets its own page with the full history of
published reviews. The security badge always shows the grade of your
latest published review, ready to embed in your README, your website, or your
sales page.
local_example
MDL ShieldAmoodle4.5+
The badge tracks your latest published review
Publishing stays a deliberate act: nothing goes public without you clicking
Publish, each new review is published on its own, and you can unpublish
at any time.
To get started, open any repository review in your dashboard and hit
Request publication. Plugins listed on moodle.org keep their existing
community flow (verify ownership, publish free), and pre-release reviews
remain private, always.
One more nicety shipping alongside: repository and pre-release reviews now
show your plugin's real display name, read from its language strings at
review time, instead of only the frankenstyle.
Every completed review in your dashboard now has an Export menu. Copy the
full report as clean Markdown or download it as a .md file, ready for your
issue tracker, wiki, or release notes.
Each finding card carries the same menu scoped to just that finding, so every
action below works for a single issue too, handy for lifting one finding into
a ticket or a chat.
For AI help there are two routes. Copy AI prompt wraps the report in
instructions to work through each issue, ready to paste into any AI assistant
you like. And if you use Claude or Cursor, Open in skips
the paste entirely and hands the report over in one click (those two can fetch
it directly by link).
Export this review
Copy as Markdown
Download .md
Copy AI prompt
Open in
Claude
Cursor
Export the whole review
Finding #3
Copy as Markdown
Copy AI prompt
Open in
Claude
Cursor
Copy a single finding from its card
Export lives on your reviews in the dashboard. You won't find it on
public published review pages: your plugin's report is yours to export and
hand to an AI, not anyone else's.
A batch of improvements for anyone buying reviews on a company card:
Your saved business details (company name and tax ID) now show on the
purchase page, with a link to update them. Once entered, the checkout
itself never displays these again, so the purchase page is now the place to
confirm they're right before you buy.
Want your billing address on the invoice? Tick Add my billing address to
the invoice and the checkout will prompt for it. We remember whether you
want that prompt; the address itself can't be pre-filled by the checkout yet,
so it does need re-entering each time.
Purchase history now offers a proper invoice PDF download alongside the
receipt.
You can now connect your plugin's Git repository and run reviews directly
against it, no moodle.org release required. That unlocks two different things,
depending on where your plugin lives:
Pre-release reviews
For plugins listed on the moodle.org plugins directory. Point us at a
branch or tag and review the code before you publish the release, so what
lands in the directory has already been audited. Free reviews apply to
non-commercial community plugins, same as always.
Repository reviews
For plugins that are not in the directory: unlisted, internal, or closed
source. Connect the repository and review any branch or tag on demand. These
use a paid review credit.
Branch / tag
Moodle version
5.0
Path (repository root, or a subdirectory in a monorepo)
Detected block_example
3 credits available
Pick a branch, we detect the plugin, run the review
Both work with private repositories (via read-only deploy keys) and
monorepos (point the connection at the directory that holds your plugin),
and every repository card shows its latest review grade at a glance.
github.com/acme/moodle-block_exampleConnected
public repository · Latest:A3 days ago
git.acme.dev/lms/local_exampleConnected
private repository · Latest:B+yesterday
Your connected repositories, latest grade at a glance
Review results from repositories stay private to you.
Just uploaded a new version to moodle.org? Hit Refresh releases on your
plugin's page in the dashboard and we pull its latest versions immediately, no
waiting for the background sync. Freshly pulled versions are marked with a
NEW badge so they are easy to spot.
MDL Shield now has a public changelog. New features, improvements, and fixes
are announced as they ship. Bookmark the changelog or subscribe
to the RSS feed.