Aelira Core v0.11.0: four fixes in the Microsoft 365 integration and review pages
Aelira Core v0.11.0 fixes four security issues, one of them high severity, in the Microsoft 365 integration and the LMS review pages. Self-hosters who connect Microsoft 365 should upgrade and create their Microsoft webhook subscriptions again.
Aelira Core v0.11.0 fixes four security issues. One is high severity: a user of a department with a connected Microsoft 365 account could have that department's Microsoft access token sent to a server of their choosing. The other three are low severity, and each of the four has a published advisory.
If you self-host Aelira Core and connect Microsoft 365, upgrade. If you don't use the Microsoft 365 integration, only the review-page fix applies to you. The release adds one database migration, and Microsoft webhook subscriptions created before it must be created again. The steps are below.
A page token that was really a URL
When Aelira lists the files in a OneDrive folder, Microsoft returns them a page at a time, with a link to the next page. Our API handed that link to the dashboard as a page token, and when the dashboard asked for the next page, the API requested whatever URL the token contained. Every one of those requests carried the department's Microsoft Graph access token.
Nothing checked where the URL pointed. An authenticated user of the department could replace the token with the address of their own server and receive the access token, which opens the department's connected OneDrive or SharePoint content until it expires. Deployments with no connected Microsoft 365 account had no token to expose.
In v0.11.0, paging and delta links are followed only when they are https URLs on graph.microsoft.com under /v1.0/, with no other port, no user information, no fragment and no dot segments. Anything else is refused before a request is sent, and the route answers 400 Invalid page token.
Advisory: GHSA-cxmg-mrg8-j7r6 (high).
Three lower-severity fixes
Graph request paths (GHSA-cpcw-3584-j8q4). Requests to Microsoft Graph were built from item, folder, drive, site and subscription IDs, folder paths and file names exactly as given. An ID containing /, .., ?, # or % could change which Graph resource was requested. Those requests still used the connected account and stayed within its permissions. Now an ID must be a single Graph ID, folder paths refuse dot segments and control characters, and every path segment, file name and search term is encoded.
Webhook notifications (GHSA-5prr-c8m5-63r7). When Aelira creates a Microsoft subscription, it gives Microsoft a value to send back with every change notification, so the API can tell real notifications from forged ones. We had used the department's ID, which isn't a secret. Someone who knew a department ID and a subscription ID could make the API queue unwanted sync work. Each subscription now gets its own random secret. The API stores only a hash of it and compares in constant time.
LMS review pane (GHSA-724p-6r8m-h85x). The Canvas and Brightspace review pages cleaned the original course HTML with DOMPurify, then parsed and rebuilt it once more to add a notice to images with no alt text. That second pass meant the markup shown was not the markup DOMPurify had checked. No working attack is known. The notice is now added inside DOMPurify's own pass, and its output is shown exactly as returned.
What operators need to do
The full procedure is in the release notes. In short:
- Before upgrading, record your Microsoft webhook subscriptions. For each department that connects Microsoft 365, call
GET /microsoft/subscriptionsand note eachresource. Microsoft can't change the secret on an existing subscription, so the old ones stop being accepted after the upgrade. - Back up, then upgrade. Take a coordinated backup, run
alembic upgrade headwith the new API image, confirm the head is20261028_webhook_secret, and deploy the API, worker and dashboard together. The migration adds one nullable column and drops nothing. - Check
PUBLIC_API_URL. Notifications now always go to that address followed by/webhooks/microsoft, so it must be the public https address Microsoft can reach. - Create each subscription again with
POST /microsoft/subscriptionsand the body{"resource": "<recorded resource>"}. Until you do, Microsoft changes in that drive don't trigger a sync.
Two API changes may affect scripts. POST /microsoft/subscriptions no longer needs notification_url and refuses any address other than the API's own receiver. Microsoft sync folders must be added by their Graph item ID.
Why this is 0.11.0
We follow semantic versioning strictly from v0.10.0 on. This release changes API behaviour and adds a database migration, so it is a minor release, even though most of it is security fixes.
Builds that survive an upstream outage
Two changes make our own CI and release builds harder to knock over. Every pinned download in the API image build now goes through one verifier with bounded retries, and CI reads those files from a cache keyed by their SHA-256, checking each file exactly as it would a download (#687). The native LaTeXML jobs depend on snapshot.ubuntu.com. When it refuses all three attempts as unavailable, they now build from a cached input that is checked against a reviewed lock and its signed package index (#840). Integrity and TLS failures never fall back to the cache.
Caught at the release gate
The first release run for v0.11.0 stopped before anything was published. The dashboard image inherits curl from its pinned nginx:alpine base, and a fix for CVE-2026-92392 (high) had become available in Alpine. Our normal CI scans only the API image, so the release workflow's scan of the dashboard image was the first to see it. We added the fix (#846), and the release was built again from the corrected commit.
What remains open
The open items disclosed with v0.10.0 are unchanged, and the release notes list each one with its issue. The Microsoft fixes are covered by unit and route tests with Graph mocked, and the migration by a test against PostgreSQL. We have not tested this release against a live Microsoft 365 tenant, and the release notes say so.
The whole self-hosted product remains free and open source. The release, its signed images and the CLI are on GitHub and npm.

RD (Reg) Crampton
•Founder & CEOFounder, CEO & lead developer of Aelira. Building beta tools to help faculty and accessibility teams check materials and evaluate suggested fixes, with human review required.
Related Articles
Aelira Core v0.10.0: a second reading for every printed equation
Aelira Core v0.10.0 reads every printed equation twice, blind, and fixes a review gap we found hours after publishing v0.9.13. It also explains why the release took five days.
Aelira Core v0.9.12: publishing the security record with the release
Aelira Core v0.9.12 fixes a LaTeX file-access vulnerability, publishes three security advisories, discloses every unfixed image advisory and adds reviewed PDF working files.
I applied for GitHub's security fund. Then CodeQL found 42 alerts.
We applied for GitHub's security fund, then CodeQL raised 42 alerts. Here's what we changed, deployed and still need to review.