GSoC 2026 Proposal Draft – Idea 6: Strengthen the security of the plugin ecosystem
– Ehtesham-Zahid
Links
- Project Idea: Idea 6: Strengthen the security of the plugin ecosystem
- GitHub Profile: Ehtesham-Zahid
- Gerrit Profile: ehteshamzahid313 (Chromium Contributions)
- Forum Introduction: Welcome to GSoC 2026 with Joplin
Joplin Contributions:
- PR #14689 (Merged): Fix race condition in handleAppFailure
- PR #14780 (Merged): Improve note list header icons & accessibility
- PR #14773 (Open): Implement global settings search for desktop app
Chromium Contributions:
- PR #1 (Merged): Dependency injection for ManifestHandlerRegistry
- PR #2 (Merged): Refactor RequestFileSourceResponse to use ErrorFileSource
- PR #3 (Merged): Extract metrics and user actions to shared metrics_util.ts
- PR #4 (Merged): Improve event listener lifecycle in ExtensionsDropOverlay
1. Introduction
My name is Ehtesham Zahid, a 4th semester Computer Science student at the University of Lahore, Pakistan. I have been working with TypeScript, React, Node.js, and the MERN stack for the past two years, building full-stack web applications both for clients and personal projects.
My open source experience includes:
-
Chromium (4 Merged PRs): Contributing to the Chromium project gave me hands-on experience navigating massive, complex codebases and adhering to strict, enterprise-level code review and security cultures.
-
Joplin PR #14689 (Merged): Fixed a race condition in
handleAppFailurethat caused aTypeError: Object has been destroyedduring renderer crash recovery on Windows. -
Joplin PR #14780 (Merged): Improved note list header icons by replacing inconsistent Unicode symbols with FontAwesome icons and adding accessibility labels for screen readers.
-
Joplin PR #14773 (Open): Implementing a global settings search feature for the desktop app (currently under review).
For this proposal specifically, I spent significant time reading through the plugin-repo-cli source code, the joplin/plugins workflow file, and RFC #9582 to understand the problem at a code level before proposing a solution. This included discovering how _publish_commit stores source commits in branch:hash format, identifying plugins with missing repository_url, and running POC implementations against real plugin data, including finding 71 vulnerabilities in a single plugin's dependencies. I have also been actively engaging with mentors on the forum to refine the approach.
2. Project Summary
What problem it solves:
Joplin's current plugin pipeline has no security review process. A developer writes a plugin, publishes it to npm, and it gets automatically fetched by plugin-repo-cli and made available to all users within 30 minutes, without any human involvement. The .jpl file is built on the developer's own machine with no guarantee it matches the source code, and some plugins don't even have a public repository, making independent verification impossible. A malicious plugin could silently access a user's notes, steal credentials, or send data to external servers, and nothing in the current pipeline would catch it.
Why it matters to users:
Joplin users trust the plugin ecosystem. Many plugins have access to sensitive data like notes, attachments, and sync credentials. A single malicious plugin reaching users could compromise that trust permanently. As the plugin ecosystem grows, the attack surface grows with it. Currently the only signal of trustworthiness is the "recommended" tag, which is limited to a small set of plugins from known developers. The vast majority of plugins, many of which are genuinely useful and widely used, have no verification signal at all. A structured review process changes this: it gives every plugin a clear, verifiable status that users can rely on, not just a small recommended subset.
What will be implemented:
At a high level, the proposed system replaces the fully automated npm-based pipeline with a review-gated workflow. Today, any developer can publish a plugin to npm and it is made available to all Joplin users within 30 minutes with zero human involvement. The system I propose changes this fundamentally. No plugin reaches users without explicit human approval and a verified source build.
The new workflow works as follows:
-
Developer pushes source code to a public git repository and opens a review request PR in
joplin/pluginswith the repository URL and commit hash -
PR Author comments “Review Plugin“ under PR and automation scans starts. Semgrep scans the source code for dangerous patterns (eval(), dynamic require(), external network calls) and socket.dev scans dependencies for supply chain risks and known vulnerabilities. The PR is blocked until both scans pass
-
After Both Scans, an AI model via GitHub Models will review the code and give code report in a PR comment to make the review process fast for reviewer
-
A Joplin reviewer examines the AI report, source code and approves the specific commit hash. If changes are requested, the developer pushes fixes and again runs the automated scans
-
Only after human approval does Joplin's trusted GitHub Actions runner clone the source at the exact reviewed commit, build the
.jplfrom scratch, and add it to the repository -
Plugins are clearly labelled as
reviewed,unreviewed, orsuspendedin both the repository and the plugin browser, giving users a clear trust signal for every plugin they install
Expected outcome:
Every new plugin reaching users will have been built from reviewed source code on a trusted server. Existing plugins remain available but clearly labelled as unreviewed, and authors can request a review at any time to upgrade their plugin's status. The result is a plugin ecosystem that stays open and developer-friendly while giving users meaningful, verifiable trust signals for every plugin they install.
3. Technical Approach
3.1 Architecture:
Current Architecture:
Problems with the current approach:
1. Unverifiable binary: While researching how plugins are delivered, I noticed we’re essentially taking the developer's word for it. They show us clean code in their public repository, but the actual .jpl file users download is built on the developer's own machine and uploaded to npm. I have no way to verify that the original source code matches the binary on npm, which creates a significant trust gap.
2. Fully automated, zero human involvement: Looking at searchPlugins.ts, I saw that it automatically pulls in any package tagged joplin-plugin every half hour. I feel this is a major risk because a malicious plugin could be live for all Joplin users in minutes without a single human ever seeing the code or even knowing the plugin was submitted.
3. No review of updates: I also realized that once a plugin is in the system, updates just flow through automatically. There’s no gatekeeper to check what changed between version 1.0 and 1.1. I’m concerned that a plugin could start out clean and then introduce malicious behavior later through an unreviewed update.
4. Write access during plugin code execution: One of the bigger security holes I found is that the entire workflow runs with contents: write permissions. Since we run npm install on third-party code during the build, I realized that a malicious script hidden in a plugin could potentially steal our GitHub token and push unauthorized changes directly to the Joplin repository.
5. Unpinned CLI dependency: Finally, I noticed that we install @joplin/plugin-repo-cli from npm without pinning it to a specific version. I think this is a supply chain risk; if that CLI tool’s npm account were ever compromised, our own pipeline would automatically start running the compromised version with full write access to our repo.
My Proposed Architecture:
To solve the trust and security gaps I identified, I am proposing a system that replaces the fully automated npm-based pipeline with a review-gated workflow. My plan is built around the following core components:
1. PR-based submission: Instead of Joplin’s bot searching npm, I want authors to submit for review by opening a PR in joplin/plugins. I’m designing this to require just two things: the public repository URL and the exact commit hash. I chose this approach specifically because it’s "forge-agnostic"; it doesn't matter if a developer uses GitHub, GitLab, or Codeberg. As long as the repository is public, my system can clone and verify the source. I’ll also provide a PR template to make this as easy as possible for first-time contributors.
2. Automated scanning pipeline: I noticed that running security scans on every single "Work in Progress" commit would be a waste of resources, so I’m implementing a "Review Plugin" comment trigger. When an author is ready, they just comment on the PR, and the automation kicks in. To prevent the DoS spam I mentioned earlier, I’ve included an authorization check so the workflow only triggers for the author or a maintainer. Once started, I’ll have the system run two specific scanners:
-
Semgrep: To find dangerous patterns like
eval()or unauthorized network calls. -
Socket.dev: To catch the supply chain risks and typosquatting I'm concerned about in dependencies.
After these pass, I’m using GitHub Models to generate an AI report. I want this to summarize what the plugin actually does so the human reviewer doesn't have to start from scratch.
3. Trusted build pipeline: To fix the "Write Access" hole I discovered, I’m splitting the build process into two separate jobs with different permission scopes:
-
The Build Job (
contents: readonly): This is where the untrusted plugin code is actually compiled. Even if a malicious script tries to steal the token, I’ve ensured it only has "Read" access, so it can't push changes to our repo. -
The Commit Job (
contents: write): This job only starts after the build is finished. It takes the safe, compiled artifact and adds it to the repository. Since this job never executes the plugin's code, the "Write" permission is finally safe to use. I’m also pinning@joplin/plugin-repo-clito a specific version to eliminate that unpinned dependency risk I found.
4. Update flow: I realized that if we have 277+ plugins, maintainers will be overwhelmed if they have to re-review every line of code for every small update. I want to solve the "Maintainer Fatigue" problem by making the review process as frictionless as possible.
To do this, I am implementing a "One-Click Review Link" generator. My script will automatically construct a comparison URL by grabbing the last reviewed hash from manifests.json and the new hash from the PR. I’m designing this to be forge-agnostic. The utility will detect if the repository is on GitHub, GitLab, or a Gitea-based forge like Codeberg and generate the correct URL structure (handling the /-/ difference in GitLab, for example).
When a maintainer opens a PR for an update, they will see a direct link (e.g., .../compare/old_hash...new_hash) along with an AI-generated "Plain English Diff" that summarizes the changes. This means instead of hunting through external repositories, a reviewer can click one link, verify the specific changes in seconds, and move on. I believe this is the only way to keep the security gate sustainable as the ecosystem grows.
3.1.1 Proof of Concept Validation
Before building the full system, I wanted to ensure these tools could actually catch Joplin-specific risks:
POC — Custom Semgrep Rules I created a custom Semgrep ruleset and ran it against a test plugin I loaded with intentionally dangerous code (like hidden eval() calls and unauthorized network requests). I was pleased to see that Semgrep detected all 4 security issues automatically and marked them as blocking. This gave me confidence that the automation will catch the "obvious" red flags before a human even has to look at the code.
[POC — Custom Semgrep Rules File Link]
3.1.2 System Threat Model
I’ve engineered this pipeline to specifically target the most common supply-chain vectors. A security architecture is only as strong as the attacks it prevents, so I focused on these four risks:
1. The "Bait-and-Switch" (The NPM Middleman)
-
The Threat: Joplin’s current pipeline pulls
.jplfiles from npm without source verification. I noticed this creates a major blind spot: a developer can host clean code in a public repo but publish a malicious binary to npm. Without a verified link between the two, Joplin has no way to detect the discrepancy. -
My Mitigation: I researched a mentor's suggestion of using NPM Trusted Publishing to secure this link, but I realized that still leaves npm as an unnecessary middleman. It would require routing code from a repository → npm → back to our GitHub runner just to build the binary. I am eliminating npm as a source for the build process. By building the
.jpldirectly from the verified git commit on our own trusted runner, I am eliminating the possibility of a "Bait-and-Switch." The code a reviewer sees is exactly the code that gets compiled for the user, making the source repository the single, verifiable source of truth.
2. The Malicious Update
-
The Threat: A developer could publish a clean v1.0.0 to gain user trust, then slip credential-stealing code into v1.1.0 six months later.
-
My Mitigation: Because my pipeline requires human approval for every update (which I’ve accelerated using AI diff summaries and one-click compare links), I effectively eliminate the automated publishing window that allows malicious updates to slip through unnoticed.
3. CI Environment Poisoning
-
The Threat: Running
npm installon untrusted code is dangerous. A malicious post-install script or webpack config could execute during the build to steal theGITHUB_TOKENand push unauthorized changes directly to the Joplin repository. -
My Mitigation: I’ve enforced strict CI job separation. My build step runs in a completely isolated job with
contents: readpermissions only. This makes it physically impossible for untrusted code to "write" back to the repository, even if it manages to execute during the build.
4. Lockfile Poisoning & Typosquatting
-
The Threat: An attacker could manipulate the
package-lock.jsonfile to redirect a dependency download to a malicious server. Standard tools likenpm auditoften miss this because they only look at package names, not registry URLs. -
My Mitigation: Instead of deleting the lockfile (which breaks deterministic builds), I chose to integrate
socket.dev. It natively scans lockfiles for these exact unexpected registry URLs and supply chain attacks right on the cloned source before the build even begins.
3.2 Design Decisions & Alternatives Considered:
| Architectural Decision | Alternative Considered | Why I Chose This Approach |
|---|---|---|
| Direct Git-to-CI Pipeline (Bypassing NPM) | Publishing source code to NPM via Trusted Publishing. | A mentor suggested using NPM Trusted Publishing, but I realized it makes npm an unnecessary middleman. By integrating socket.dev directly into our CI to scan the cloned repo, we get the same security benefits without the sync complexities. This keeps the source repository as the single source of truth for all forges (GitHub, GitLab, Codeberg). |
| Semgrep + socket.dev | ESLint + npm audit |
I initially considered standard tools like ESLint, but it's primarily a linter. I chose Semgrep for its deep, cross-file semantic analysis. For dependencies, npm audit only catches known CVEs; I chose socket.dev because it proactively catches supply-chain attacks and malicious install scripts before the build even begins. |
| Separated CI Jobs (Read vs. Write) | A single CI Build-and-Publish Workflow | Running npm install on untrusted code is dangerous. If a malicious script tries to steal the repository token, my separated Build Job (contents: read) physically cannot push changes. The Commit Job only picks up the safe, compiled artifact, ensuring the "Master Key" is never exposed to untrusted code. |
| Immutable Commit Hash Target | Git Release Tags | I’m requiring authors to submit an exact commit hash rather than a release tag. I made this choice because tags are mutable, they can be moved or manipulated after a review is finished. A commit hash is mathematically immutable, giving us absolute certainty that we are building the exact code that was approved. |
| AI-Assisted Reviews & One-Click Links | Purely Manual Code Reviews | I knew that reviewing updates for 277+ plugins manually would create a massive bottleneck. I added AI summaries and automated 'Compare' links to act as an accelerator. By instantly showing exactly what changed since the last reviewed commit, I can drastically reduce the cognitive load on maintainers and keep update cycles fast. |
3.3 Changes to the Joplin Codebase:
To implement this architecture, I have identified the specific components of the Joplin codebase that need to be modified or removed. My research into the existing scripts and my subsequent POC testing guided these decisions:
1. Modifications to manifests.json
I’m adding two new fields to each plugin entry to track security status: _reviewed (can be unreviewed, reviewed, or suspended) and _review_date. This ensures the Joplin app can distinguish between legacy plugins and those that have passed my new security gate.
POC VERIFICATION: Manifest Migration
Status: Successfully tested against the livejoplin/pluginsrepository.Result: All 277 existing plugins were migrated to
unreviewedstatus without breaking the manifest structure, ensuring a smooth transition to the new system.
2. Deep Refactoring of plugin-repo-cli
I am replacing the current "binary-only" extraction logic with three focused, security-hardened commands. I’m moving away from trusting npm-built files and instead building directly from the verified source:
-
scan: Clones the source at the submitted hash and runs my
Semgrepandsocket.devsuite. -
build-from-source: Creates a clean, isolated environment to compile the
.jplusingnpm install --ignore-scripts. This prevents malicious post-install scripts from executing during the build. -
commit-plugin: A "write-only" command that updates the repo once the build is verified. It is strictly isolated so it never touches untrusted third-party code.
POC VERIFICATION: Source-to-Binary Build
Status: Tested against a real Joplin plugin at a specific reviewed commit.Key Finding: During the test build, I discovered 71 vulnerabilities in the plugin’s dependencies. This confirmed that automated scanning is not just an "extra feature," but a mandatory requirement for user safety.
3. Removing searchPlugins.ts
I’ve decided to remove the npm-discovery script entirely. Since plugins will now only enter the system through a reviewed PR process, we no longer need a cron job to "hunt" for packages. This effectively closes the "30-minute automated window" where malicious code could slip in unnoticed.
4. Redesigning update-repo.yml (The Security Orchestrator)
I’m rewriting the main workflow to enforce the job separation (contents: read vs contents: write) described in my threat model. This is the heart of the Security-First design:
- Authorization Shield: I'm implementing a check that ensures the "Review Plugin" trigger only executes if the commenter is the PR author or a maintainer, preventing CI abuse.
- Physical Isolation: The Build job runs with "Read-Only" permissions. Even if a plugin has a malicious
webpack.config.js, it cannot touch the repository. The Commit job only starts after the build is safe.
POC VERIFICATION: Hardened Workflow Implementation
Status: Complete working implementation available.Features: Demonstrates the comment-trigger logic, automated PR reports, job isolation, and pinned
@joplin/plugin-repo-cliversions to prevent supply-chain attacks on our own tools.
5. Updates to validateUntrustedManifest.ts
I’ll update this utility to handle the new fields and, more importantly, protect them. I’m specifically designing this to ensure that plugin authors cannot "self-approve" their submissions by manually editing the _reviewed field in their own PRs.
6. Changes to the yo joplin Generator
To ensure all future plugins are "Review-Ready," I’m making the repository_url field mandatory during plugin creation. This sets the standard for the new workflow from the very first line of code a developer writes.
7. Enhancing the Plugin Browser UI
I want to make the security status transparent. I am proposing three clear labels in the Joplin Desktop app: Reviewed, Unreviewed, and Suspended. While the labels are Desktop-only for now, the Suspended status will ensure the plugin is hidden from the browser for all users on all platforms.
- Instant Safety: If a maintainer marks a plugin as suspended in the repo, it will be immediately hidden from the global plugin browser for all users. We no longer have to wait for a full app update to protect users from a discovered threat.
3.4 Libraries or Technologies
To build a hardened and verifiable review system, I’ve selected a suite of tools that prioritize deep analysis and environmental isolation over basic linting:
-
Semgrep: My primary source code scanner. I chose it over ESLint because of its semantic analysis capabilities. It allows me to write custom rules that understand the intent of the code (like detecting hidden
evalcalls or unauthorizedfsaccess) which is significantly harder to bypass than simple pattern matching. -
Socket.dev: This handles all dependency and lockfile scanning. Unlike
npm audit, which only reports known CVEs,socket.devproactively catches supply chain attacks, typosquatting, and registry redirects before they can compromise our build environment. -
GitHub Actions: The "Orchestrator." I am using it not just for automation, but as a trusted execution environment. Its native support for granular, permission-scoped CI (the
contents: read/writesplit) is the technical foundation of my entire pipeline. -
GitHub Models (AI): I’m integrating GitHub’s AI infrastructure to provide human-readable review summaries. It will analyze the automated scan results and the "Forge-Agnostic" diffs to generate a structured report for the maintainer, drastically reducing the cognitive load of a manual review.
-
TypeScript / Node.js: The core environment for all my custom scripts within
plugin-repo-cli. I’ll be using these to build the "Migration Script," the "Link Generator," and the corebuild-from-sourcelogic.
3.5 Potential Challenges
I don't expect this migration to be perfectly linear. Dealing with 277+ diverse plugins means running into "edge cases" that a clean local POC can't always predict. Here is how I’m planning to handle the friction points:
1. Build environment consistency: Different plugins may target different Node.js versions, and just pinning a single version in the workflow doesn't fully solve this. My plan is to implement logic to parse the engines.node field in package.json to select the runner's Node version dynamically.
2. The "Human Bottleneck" (Maintainer Fatigue): This is the biggest risk to the project's success. If the new review process is too slow, authors will get frustrated and the ecosystem will stall. I’m addressing this by making the automation do 90% of the heavy lifting. My goal is to turn a 30-minute deep-dive audit into a 5-minute "sanity check."
3. Handling "Repo-less" and Legacy Plugins: During my triage of the 277 existing plugins, I found a small minority that simply don't have a repository_url. My migration script marks them as unreviewed permanently. I’ve designed the system so that the "path to safety" is clear: if an author wants that Reviewed badge, they must provide a public repository.
4. Plugins with native dependencies: This is the "messiest" technical part. Not every plugin uses the same Node.js version, and some use native C++ dependencies that require specific build tools. My plan is to use the Community Bonding period to audit these specific plugins with the mentors. I’d rather build a rock-solid pipeline for the 95% of standard plugins first, then work with the team to decide if we need a "multi-platform build matrix" for the outliers.
3.6 Testing Strategy
Since this pipeline handles untrusted code, my testing strategy is split between verifying the core logic and trying to "exploit" the security boundaries I’ve set up.
1. Unit Testing: The Building Blocks
I’ll use Vitest (consistent with the Joplin codebase) to ensure my core utilities are bulletproof:
-
buildPluginFromSource(): I’ll verify that it rejects any attempt to build from a branch name instead of a specific commit hash. I’ll also test that it correctly stamps the_reviewedand_review_datefields only when the build is 100% successful. -
The Migration Script: I’ve already run this against a copy of the 277-plugin manifest. My test suite will ensure that zero plugins are missed and that no existing fields (like
descriptionorversion) are accidentally corrupted during the shift. -
validateUntrustedManifest.ts: This is a critical test. I will write "Negative Tests" where a fake plugin author tries to manually set their own status toreviewed. My code must detect and strip these unauthorized fields immediately.
2. Integration Testing: The End-to-End Pipeline
I’ll set up a staging repository to simulate the entire PR lifecycle:
-
The Full Loop: I’ll open a PR, trigger the "Review Plugin" comment, and verify that the automated report (
Semgrep+Socket.dev+ AI) appears as a comment. -
Forge-Agnostic Check: I’ll run test submissions using repositories hosted on GitHub, GitLab, and Codeberg to ensure my "Link Generator" and "Cloning Utility" handle the different URL structures perfectly.
3.7 Documentation & Onboarding Plan
A new security pipeline is only useful if developers and maintainers know how to interact with it. I will provide four specific sets of documentation:
1. Contributor Documentation (Plugin Authors)
This guide explains the new PR-based submission process so authors can get their plugins reviewed quickly. It will cover:
-
How to format the submission PR using the new template.
-
How to trigger scans using the
Review Plugincomment. -
Interpreting Results: A guide on reading Semgrep and Socket.dev reports so authors can fix vulnerabilities before requesting a human review.
2. Maintainer Workflow (Reviewer Guide)
This is a technical reference for the Joplin core team to help them manage the 277+ plugin backlog and new submissions. It covers:
-
Using the AI-generated diff summaries to focus on high-risk code changes.
-
Using the "One-Click Compare" links for GitHub, GitLab, and Codeberg.
-
The specific criteria for moving a plugin from
unreviewedtoreviewed.
3. Vulnerability Response Protocol
A clear set of instructions for handling security flaws discovered after a plugin has been approved:
-
The "Kill Switch": Steps to manually set a plugin to
suspendedin the manifest for immediate removal from the browser. -
The Recovery Path: The process for an author to submit a fix and re-verify the plugin through the pipeline.
4. Repository Infrastructure (README & Templates)
I will update the joplin/plugins README to reflect the new workflow and implement GitHub PR Templates. These templates will force-prompt authors for the repository_url and commit_hash at the moment of creation, ensuring the automation has the data it needs to start.
3.8 Security Vulnerability Response Plan
Moving to a gated review process means I have to ensure security patches don't get stuck in a standard queue. I’ve designed the following workflow to handle critical issues without the overhead of a standard feature PR.
1. Instant De-listing via "Suspended" Status
If a live plugin is found to have a critical exploit or malicious code, the priority is to remove it from the store immediately.
-
My implementation: I’ve included the
suspendedstatus in the_reviewedfield of the manifest. -
The process: A maintainer can update this field in the repository in seconds. Since the Joplin app reads the manifest on every sync, the plugin is hidden from the browser for all users immediately. This removes the threat while the developer works on a fix.
2. Coordinated Disclosure for Critical Exploits
For severe vulnerabilities, a public PR is risky because it effectively discloses the exploit before a patch is live.
-
The challenge: Managing a "private" review process (via email or private repos) adds significant logistical overhead and extra steps for both the author and the maintainer.
-
My plan: I recognize that this is a sensitive area that needs to align with Joplin’s existing security culture. I intend to use the Community Bonding period to discuss the exact protocol with mentors. Whether we use private GitHub Security Advisories or a dedicated security contact, I want to ensure the final workflow is as frictionless as possible for the team.
3. Priority Handling for Routine Security Updates
Not every security update is a zero-day; often it’s just a dependency bump to patch a known CVE.
-
The shortcut: I’m adding a "Security Fix" label to the PR template. I will configure the workflow to prioritize these PRs at the top of the review list.
-
The speed: Using the AI-generated diff reports I’m building, a maintainer can verify a simple version bump almost instantly. This ensures routine security maintenance is shipped in hours rather than days.
3.9 Migration & Developer Experience (DX) Strategy
Transitioning 277+ existing plugins is the biggest hurdle. My core philosophy here is that security should not be a blocker. I’ve designed the migration so that the _reviewed: "unreviewed" status is purely informational; it won't hide or break a single plugin.
1. The Baseline Migration
My first action will be running the migration script I’ve already prototyped. It stamps all 277 existing plugins with _reviewed: "unreviewed" and _review_date: null.
- Impact: Nothing breaks. Every plugin stays available in the browser, just now with an "Unreviewed" badge.
2. Automated Triage and Classification
After auditing the current manifests.json, I realized that not all plugins are in the same state. I’ve categorized them into four cases that my script will automatically identify:
-
Case 1 (Ready to Go): Plugins with both a
repository_urland a_publish_commit. I can pull these into the review pipeline immediately with zero author effort. -
Case 2 (Need Author Input): Plugins with a repo URL but no commit hash. I’ll open the PR, but I’ll need the author to confirm which commit they want to be "The Source of Truth."
-
Case 3 (No Repository): Plugins with a commit but no repo link. These stay
unreviewedpermanently unless the author provides a public URL. -
Case 4 (Fully Blocked): Neither field exists. These are legacy cases that require manual outreach.
3. An Impact-First Priority Queue
I don’t want to waste maintainer time on abandoned plugins with 5 users. I’m taking a data-driven approach by querying the npm downloads API: https://api.npmjs.org/downloads/point/last-month/``<_npm_package_name>
By sorting the 277 plugins by monthly downloads, I can identify the Top 20–30 plugins that have the most real-world exposure.
-
My GSoC Goal: I will personally open review PRs for the Top 20–30 plugins that fall into Case 1. I’ll trigger the scans, verify the results, and work with the maintainers to get the most popular plugins genuinely "Reviewed" by the end of the summer.
-
For Case 2 Top Plugins: I’ll open the PR and tag the author, asking for the commit hash. Once they reply, I’ll handle the rest of the verification.
4. Protecting Maintainer Bandwidth
I am being realistic about the fact that maintainers are busy. My automation handles the heavy lifting so that the human review is just a final "sanity check."
-
If Semgrep and Socket.dev pass and the AI report is positive, a maintainer should be able to approve a plugin in minutes.
-
For the hundreds of other plugins, I am leaving the door open for an "organic" migration. Authors can opt-in whenever they want. I’m not forcing a massive manual audit on the core team; I'm building the engine that makes the audit easy.
3.10 Project Out of Scope
To keep the focus on the core security architecture and ensure the pipeline is production-ready within 12 weeks, I am defining the following as out of scope. These represent significant technical hurdles that would detract from the primary goal of establishing a verified build process.
1. Multi-Platform Build Matrix for Native Modules
Some plugins use native C++ components (via node-gyp). Automating these across Windows, macOS, and Linux runners is a massive rabbit hole of environment-specific debugging. I am focusing on the 95% of plugins that are pure JS/TS. Native modules will remain a manual review process for the initial rollout.
2. Security UI Implementation for Joplin Mobile
I am limiting the UI labels (Reviewed/Unreviewed/Suspended) to the Joplin Desktop App. Adding these to the React Native mobile codebase would require a separate cycle of cross-platform testing and UI work that would distract from the core security-first infrastructure.
3. Manual Audit of the Full Plugin Backlog
While this project establishes the infrastructure for a secure ecosystem, completing a full manual audit of the entire 277+ plugin backlog is outside the 12-week scope. I will, however, kickstart the process by personally guiding the top 20–30 most downloaded plugins through the new pipeline. The rest of the backlog will be reviewed organically as authors opt-in.
4. Implementation Plan
Project Duration: 350 hours (Large Project)
Estimated Commitment: 35–40 hours per week
Availability Note: I am fully committed to this project for the entire 12-week period. As suggested by mentor, I have scheduled a one-week buffer in early June to account for my university exams. I will compensate for this by extending my contributions into late August and September to ensure the project is fully polished.
Community Bonding (May 1 – May 24)
I will use this period to talk with mentors to agree on the final technical details so there are no surprises once coding starts.
- Finalize the Semgrep ruleset and severity levels with mentors.
- I’ll set up a private "practice" repository. This lets me test the automated triggers and the new security permissions safely without touching the real Joplin files.
- Run a final triage of the 277 plugins to ensure the "Case 1–4" list is current.
- Deliverable: A final project blueprint and a working practice repository for safe testing.
Week 1–2 (May 25 – June 7)
I will start by updating the core data structures.
- Add
_reviewedand_review_datefields to themanifests.jsonschema. - Execute the Baseline Migration (marking all 277 plugins as unreviewed).
- Refactor
validateUntrustedManifest.tsto protect these fields from unauthorized PR edits. - Update the
yo joplingenerator to makerepository_urla mandatory field. - Deliverable: Successful schema migration and a baseline-secured manifest.
Week 3 (June 8 – June 14)
- UNIVERSITY EXAMS: I will be taking this week off to focus on my exams. I have front-loaded the foundation work in Weeks 1–2 to ensure no momentum is lost.
Week 4–5 (June 15 – June 28)
I’ll focus on the "Source-to-Binary" engine. This is where I solve the trust gap between GitHub and npm.
- Implement
buildPluginFromSource()to clone at a specific hash and compile in an isolated environment (npm install --ignore-scripts). - Overhaul
update-repo.ymlto enforce job separation: a Read-Only build job and a Write-Access commit job. - Create the PR template for
joplin/pluginsthat requires the repository URL and commit hash. - Deliverable: A hardened build pipeline with physical permission separation.
Week 6–7 (June 29 – July 12)
I will integrate the security scanners and the authorization logic.
- Implement the
scancommand (Semgrep+Socket.dev) and wire it into the GitHub Actions "Scan Job." - Build the authenticated comment-trigger logic (restricting triggers to authors/maintainers).
- Midterm Evaluation (July 6-10): I will demonstrate the full end-to-end flow from PR submission to automated security report.
- Deliverable: Fully automated, authenticated security scanning on PRs.
Week 8–9 (July 13 – July 26)
I will focus on the "Human-in-the-Loop" accelerators and the Desktop UI labels.
- Integrate GitHub Models to generate "Plain English" diff summaries and capability reports.
- Implement the Reviewed, Unreviewed, and Suspended labels in the Joplin Desktop plugin browser.
- Build the logic that hides
suspendedplugins from the UI immediately upon manifest sync. - Deliverable: AI-assisted review reports and a transparent security UI in the Desktop app.
Week 10–11 (July 27 – August 9)
I’ll put the infrastructure to work by securing the most popular plugins in the ecosystem.
- I will manually guide the Top 20–30 plugins through the review pipeline.
- I’ll contact the authors of popular "Case 2" plugins to confirm their commit hashes so I can pull them into the "Reviewed" state.
- I will perform final end-to-end testing of the entire workflow, from PR submission and automated scanning to the final manifest update, using a staging repository.
- Deliverable: Verified "Reviewed" status for the top 30 plugins and a production-ready, integrated pipeline.
Week 12 (August 10 – August 24)
FINAL SUBMISSION WEEK: I’ll focus on documentation and final handover.
- Write the Author, Reviewer, and Security Response guides.
- Final bug fixes and README updates for the
joplin/pluginsrepository. - Final Work Product Submission (August 17-24): Submit code and the final project report.
- Deliverable: Completed, documented system and final project report.
Extended Period (August 24 – September)
I have specifically opted into the extended timeline to compensate for my university exam week in June, ensuring that the project receives my full 350-hour commitment. Beyond this formal compensation period, I am completely free and available throughout September should the project require further polish, bug fixes, or extended support.
- Directly assisting plugin authors with repository-linking and troubleshooting build-from-source errors.
- Identifying and fixing technical edge cases as the volume of real-world submissions increases.
- Ensuring the Joplin core team has a seamless, well-documented system for long-term maintenance.
5. Deliverables
By the end of GSoC 2026, I will have delivered the following production-ready components:
Code & Infrastructure
-
A Migration script to stamp all 277+ existing plugins as
unreviewedand a classification tool to prioritize the "Top 20–30" highest-impact plugins -
Hardened
plugin-repo-cliwith three new commands (scan,build-from-source,commit-plugin) and a Forge-agnostic link generator for one-click code comparisons (GitHub/GitLab/Codeberg). -
Overhaul of
update-repo.ymlwith physical job separation (contents: readfor builds vscontents: writefor commits) and authenticated comment triggers to prevent CI abuse. -
Integration of GitHub Models (AI) to post automated "Plain English" diff summaries and capability reports directly on PRs
-
manifests.jsonschema update and UI status labels implemented for the Joplin Desktop plugin browser -
Updated
yo joplingenerator with a mandatoryrepository_urlfield
Testing Suite
-
Unit Tests (Vitest) for the migration script,
buildPluginFromSource(), and manifest validation logic -
Integration Tests for end-to-end pipeline, forge-agnostic cloning, and job separation security guarantee
Documentation
-
Clear, step-by-step guides for plugin authors and the Joplin core team.
-
A technical incident response protocol for handling post-release vulnerabilities.
-
A fully updated README for the
joplin/pluginsrepository.
6. Availability & Communication
I am based in the PKT timezone (UTC+5) and will shift my working hours to ensure a 3–4 hour daily overlap with my mentors for meetings and real-time collaboration. GSoC will be my primary focus this summer, and I am committing 35–40 hours per week to the project.
As noted in my timeline, I will be taking a break from June 8–14 to focus on my university exams. I have front-loaded the foundation work in the weeks prior to ensure no momentum is lost. I will explicitly compensate for this exam week by working through the Extended Timeline period starting August 24. Since I am fully free throughout September, I will remain available to handle any final polish, support plugin authors during the migration, and ensure a perfect handover to the Joplin team.
I believe proactive communication is the foundation of a successful remote project. I will provide:
-
Weekly structured progress reports on the Joplin forum and a detailed "Dev Log" in a public GitHub repository.
-
Consistent check-ins with my mentors to demonstrate new features and discuss any technical blockers.
-
Constant availability via Discord, GitHub, and Email.
Having worked on freelance projects with remote clients, I am highly comfortable managing my own schedule and hitting deadlines independently. Finally, I want to emphasize that I am not applying to any other GSoC organizations. Joplin is my sole focus for 2026 because I am fully invested in solving this specific security challenge for the plugin ecosystem.
AI Disclosure
AI was used to correct grammatical mistakes, improve clarity and wording. This is disclosed in accordance with Joplin's AI assistance policy.






