{
	"issue": {
		"url": "https://api.github.com/repos/laurent22/joplin/issues/14917",
		"repository_url": "https://api.github.com/repos/laurent22/joplin",
		"labels_url": "https://api.github.com/repos/laurent22/joplin/issues/14917/labels{/name}",
		"comments_url": "https://api.github.com/repos/laurent22/joplin/issues/14917/comments",
		"events_url": "https://api.github.com/repos/laurent22/joplin/issues/14917/events",
		"html_url": "https://github.com/laurent22/joplin/pull/14917",
		"id": 4146635054,
		"node_id": "PR_kwDOBLftOs7N1KXS",
		"number": 14917,
		"title": "Fix SSRF and file-type DoS Vulnerabilities",
		"user": {
			"login": "adamoutler",
			"id": 527919,
			"node_id": "MDQ6VXNlcjUyNzkxOQ==",
			"avatar_url": "https://avatars.githubusercontent.com/u/527919?v=4",
			"gravatar_id": "",
			"url": "https://api.github.com/users/adamoutler",
			"html_url": "https://github.com/adamoutler",
			"followers_url": "https://api.github.com/users/adamoutler/followers",
			"following_url": "https://api.github.com/users/adamoutler/following{/other_user}",
			"gists_url": "https://api.github.com/users/adamoutler/gists{/gist_id}",
			"starred_url": "https://api.github.com/users/adamoutler/starred{/owner}{/repo}",
			"subscriptions_url": "https://api.github.com/users/adamoutler/subscriptions",
			"organizations_url": "https://api.github.com/users/adamoutler/orgs",
			"repos_url": "https://api.github.com/users/adamoutler/repos",
			"events_url": "https://api.github.com/users/adamoutler/events{/privacy}",
			"received_events_url": "https://api.github.com/users/adamoutler/received_events",
			"type": "User",
			"user_view_type": "public",
			"site_admin": false
		},
		"labels": [
			{
				"id": 519700741,
				"node_id": "MDU6TGFiZWw1MTk3MDA3NDE=",
				"url": "https://api.github.com/repos/laurent22/joplin/labels/bug",
				"name": "bug",
				"color": "cf353b",
				"default": true,
				"description": "It's a bug"
			},
			{
				"id": 926488748,
				"node_id": "MDU6TGFiZWw5MjY0ODg3NDg=",
				"url": "https://api.github.com/repos/laurent22/joplin/labels/security",
				"name": "security",
				"color": "cf353b",
				"default": false,
				"description": ""
			},
			{
				"id": 1079605111,
				"node_id": "MDU6TGFiZWwxMDc5NjA1MTEx",
				"url": "https://api.github.com/repos/laurent22/joplin/labels/mobile",
				"name": "mobile",
				"color": "ffc274",
				"default": false,
				"description": "All mobile platforms"
			},
			{
				"id": 1095621255,
				"node_id": "MDU6TGFiZWwxMDk1NjIxMjU1",
				"url": "https://api.github.com/repos/laurent22/joplin/labels/cli",
				"name": "cli",
				"color": "ffc274",
				"default": false,
				"description": "CLI app specific issue"
			},
			{
				"id": 8767133118,
				"node_id": "LA_kwDOBLftOs8AAAACCo_Vvg",
				"url": "https://api.github.com/repos/laurent22/joplin/labels/transcribe",
				"name": "transcribe",
				"color": "ffc274",
				"default": false,
				"description": "Related to Joplin Transcribe"
			}
		],
		"state": "closed",
		"locked": false,
		"assignees": [],
		"milestone": null,
		"comments": 6,
		"created_at": "2026-03-26T19:04:02Z",
		"updated_at": "2026-03-27T20:43:50Z",
		"closed_at": "2026-03-27T00:45:19Z",
		"assignee": null,
		"author_association": "NONE",
		"active_lock_reason": null,
		"draft": false,
		"pull_request": {
			"url": "https://api.github.com/repos/laurent22/joplin/pulls/14917",
			"html_url": "https://github.com/laurent22/joplin/pull/14917",
			"diff_url": "https://github.com/laurent22/joplin/pull/14917.diff",
			"patch_url": "https://github.com/laurent22/joplin/pull/14917.patch",
			"merged_at": null
		},
		"body": "This PR fixes two security vulnerabilities introduced by dependencies in the workspace:\n\n### 1. Server-Side Request Forgery via `request`\nThe deprecated `request` package (version `<= 2.88.2`) was present due to its usage in `image-data-uri` and directly in `@joplin/tools`. The package is vulnerable to a bypass of SSRF mitigations via cross-protocol redirects.\n* **Fix**: Removed `image-data-uri` entirely from `@joplin/lib` since it was only used to parse base64 image data. Replaced the logic with native Node.js data parsing (`Buffer.from(parts[1], 'base64')`).\n* **Fix**: Replaced `request` with `node-fetch` in `@joplin/tools/update-readme-contributors.ts` and removed the `request` dependency from `@joplin/tools/package.json`.\n\n### 2. Denial of Service via `file-type` infinite loop\nThe `file-type` package (v16.5.4) is vulnerable to a Denial of Service attack when parsing a crafted ASF file with a zero-size sub-header, causing the event loop to starve in an infinite read loop.\n* **Fix**: Backported Sindre Sorhus's official fix (commit 319abf8) for this vulnerability into `file-type@16.5.4` via a yarn patch. This prevents the loop by adding a position check during header parsing. Upgrading to the latest `file-type` was not possible as recent versions are ESM-only, which contradicts the workspace's CJS module system.\n\n### Test Results\nThe workspace was thoroughly tested, including isolated tests for the modifications, and all tests passed perfectly. The only flaky failure observed during a full workspace run was `services/RevisionService.test.js`, which passed when isolated.\n\n```\n PASS  services/rest/routes/notes.test.js (73.226 s)\n PASS  services/rest/Api.test.js (102.039 s)\n\nTest Suites: 2 passed, 2 total\nTests:       64 passed, 64 total\nSnapshots:   0 total\nTime:        102.771 s, estimated 111 s\nRan all test suites matching /services\\/rest\\/Api.test.js|services\\/rest\\/routes\\/notes.test.js/i.\n```\n\nAnd the test results for the flaky RevisionService.test.js test:\n```\n PASS  services/RevisionService.test.js (43.154 s)\n  services/RevisionService\n    ✓ should create diff and rebuild notes (4592 ms)\n    ...\n    ✓ should create 1 revision, after changing a note with a revision and updated time before the old note cut off period, where the note content before and after the latest change is the same (1758 ms)\n\nTest Suites: 1 passed, 1 total\nTests:       26 passed, 26 total\nSnapshots:   0 total\nTime:        43.181 s, estimated 111 s\n```",
		"closed_by": {
			"login": "adamoutler",
			"id": 527919,
			"node_id": "MDQ6VXNlcjUyNzkxOQ==",
			"avatar_url": "https://avatars.githubusercontent.com/u/527919?v=4",
			"gravatar_id": "",
			"url": "https://api.github.com/users/adamoutler",
			"html_url": "https://github.com/adamoutler",
			"followers_url": "https://api.github.com/users/adamoutler/followers",
			"following_url": "https://api.github.com/users/adamoutler/following{/other_user}",
			"gists_url": "https://api.github.com/users/adamoutler/gists{/gist_id}",
			"starred_url": "https://api.github.com/users/adamoutler/starred{/owner}{/repo}",
			"subscriptions_url": "https://api.github.com/users/adamoutler/subscriptions",
			"organizations_url": "https://api.github.com/users/adamoutler/orgs",
			"repos_url": "https://api.github.com/users/adamoutler/repos",
			"events_url": "https://api.github.com/users/adamoutler/events{/privacy}",
			"received_events_url": "https://api.github.com/users/adamoutler/received_events",
			"type": "User",
			"user_view_type": "public",
			"site_admin": false
		},
		"reactions": {
			"url": "https://api.github.com/repos/laurent22/joplin/issues/14917/reactions",
			"total_count": 0,
			"+1": 0,
			"-1": 0,
			"laugh": 0,
			"hooray": 0,
			"confused": 0,
			"heart": 0,
			"rocket": 0,
			"eyes": 0
		},
		"timeline_url": "https://api.github.com/repos/laurent22/joplin/issues/14917/timeline",
		"performed_via_github_app": null,
		"state_reason": null
	},
	"comments": [
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/4137510066",
			"html_url": "https://github.com/laurent22/joplin/pull/14917#issuecomment-4137510066",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14917",
			"id": 4137510066,
			"node_id": "IC_kwDOBLftOs72nWSy",
			"user": {
				"login": "github-actions[bot]",
				"id": 41898282,
				"node_id": "MDM6Qm90NDE4OTgyODI=",
				"avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/github-actions%5Bbot%5D",
				"html_url": "https://github.com/apps/github-actions",
				"followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers",
				"following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}",
				"gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions",
				"organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs",
				"repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos",
				"events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}",
				"received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events",
				"type": "Bot",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-03-26T19:04:14Z",
			"updated_at": "2026-03-27T00:45:29Z",
			"body": "****CLA Assistant Lite bot**** All contributors have signed the CLA  ✍️ ✅",
			"author_association": "CONTRIBUTOR",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/4137510066/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": {
				"id": 15368,
				"client_id": "Iv1.05c79e9ad1f6bdfa",
				"slug": "github-actions",
				"node_id": "MDM6QXBwMTUzNjg=",
				"owner": {
					"login": "github",
					"id": 9919,
					"node_id": "MDEyOk9yZ2FuaXphdGlvbjk5MTk=",
					"avatar_url": "https://avatars.githubusercontent.com/u/9919?v=4",
					"gravatar_id": "",
					"url": "https://api.github.com/users/github",
					"html_url": "https://github.com/github",
					"followers_url": "https://api.github.com/users/github/followers",
					"following_url": "https://api.github.com/users/github/following{/other_user}",
					"gists_url": "https://api.github.com/users/github/gists{/gist_id}",
					"starred_url": "https://api.github.com/users/github/starred{/owner}{/repo}",
					"subscriptions_url": "https://api.github.com/users/github/subscriptions",
					"organizations_url": "https://api.github.com/users/github/orgs",
					"repos_url": "https://api.github.com/users/github/repos",
					"events_url": "https://api.github.com/users/github/events{/privacy}",
					"received_events_url": "https://api.github.com/users/github/received_events",
					"type": "Organization",
					"user_view_type": "public",
					"site_admin": false
				},
				"name": "GitHub Actions",
				"description": "Automate your workflow from idea to production",
				"external_url": "https://help.github.com/en/actions",
				"html_url": "https://github.com/apps/github-actions",
				"created_at": "2018-07-30T09:30:17Z",
				"updated_at": "2026-05-05T14:51:38Z",
				"permissions": {
					"actions": "write",
					"administration": "read",
					"artifact_metadata": "write",
					"attestations": "write",
					"checks": "write",
					"code_quality": "write",
					"contents": "write",
					"copilot_requests": "write",
					"deployments": "write",
					"discussions": "write",
					"issues": "write",
					"merge_queues": "write",
					"metadata": "read",
					"models": "read",
					"packages": "write",
					"pages": "write",
					"pull_requests": "write",
					"repository_hooks": "write",
					"repository_projects": "write",
					"security_events": "write",
					"statuses": "write",
					"vulnerability_alerts": "read"
				},
				"events": [
					"branch_protection_rule",
					"check_run",
					"check_suite",
					"create",
					"delete",
					"deployment",
					"deployment_status",
					"discussion",
					"discussion_comment",
					"fork",
					"gollum",
					"issues",
					"issue_comment",
					"label",
					"merge_group",
					"milestone",
					"page_build",
					"public",
					"pull_request",
					"pull_request_review",
					"pull_request_review_comment",
					"push",
					"registry_package",
					"release",
					"repository",
					"repository_dispatch",
					"status",
					"watch",
					"workflow_dispatch",
					"workflow_run"
				]
			}
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/4137512742",
			"html_url": "https://github.com/laurent22/joplin/pull/14917#issuecomment-4137512742",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14917",
			"id": 4137512742,
			"node_id": "IC_kwDOBLftOs72nW8m",
			"user": {
				"login": "adamoutler",
				"id": 527919,
				"node_id": "MDQ6VXNlcjUyNzkxOQ==",
				"avatar_url": "https://avatars.githubusercontent.com/u/527919?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/adamoutler",
				"html_url": "https://github.com/adamoutler",
				"followers_url": "https://api.github.com/users/adamoutler/followers",
				"following_url": "https://api.github.com/users/adamoutler/following{/other_user}",
				"gists_url": "https://api.github.com/users/adamoutler/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/adamoutler/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/adamoutler/subscriptions",
				"organizations_url": "https://api.github.com/users/adamoutler/orgs",
				"repos_url": "https://api.github.com/users/adamoutler/repos",
				"events_url": "https://api.github.com/users/adamoutler/events{/privacy}",
				"received_events_url": "https://api.github.com/users/adamoutler/received_events",
				"type": "User",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-03-26T19:04:38Z",
			"updated_at": "2026-03-26T19:04:38Z",
			"body": "I have read the CLA Document and I hereby sign the CLA\r\n\r\n",
			"author_association": "NONE",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/4137512742/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": null
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/4137518746",
			"html_url": "https://github.com/laurent22/joplin/pull/14917#issuecomment-4137518746",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14917",
			"id": 4137518746,
			"node_id": "IC_kwDOBLftOs72nYaa",
			"user": {
				"login": "adamoutler",
				"id": 527919,
				"node_id": "MDQ6VXNlcjUyNzkxOQ==",
				"avatar_url": "https://avatars.githubusercontent.com/u/527919?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/adamoutler",
				"html_url": "https://github.com/adamoutler",
				"followers_url": "https://api.github.com/users/adamoutler/followers",
				"following_url": "https://api.github.com/users/adamoutler/following{/other_user}",
				"gists_url": "https://api.github.com/users/adamoutler/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/adamoutler/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/adamoutler/subscriptions",
				"organizations_url": "https://api.github.com/users/adamoutler/orgs",
				"repos_url": "https://api.github.com/users/adamoutler/repos",
				"events_url": "https://api.github.com/users/adamoutler/events{/privacy}",
				"received_events_url": "https://api.github.com/users/adamoutler/received_events",
				"type": "User",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-03-26T19:05:40Z",
			"updated_at": "2026-03-26T19:05:40Z",
			"body": "Also, appending the successful results from the complete  test suite run:\n\n```\n[@joplin/server]: Test Suites: 75 passed, 75 total\n[@joplin/server]: Tests:       377 passed, 377 total\n[@joplin/server]: Snapshots:   0 total\n[@joplin/server]: Time:        385.858 s\n[@joplin/server]: Ran all test suites.\n```",
			"author_association": "NONE",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/4137518746/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": null
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/4137528774",
			"html_url": "https://github.com/laurent22/joplin/pull/14917#issuecomment-4137528774",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14917",
			"id": 4137528774,
			"node_id": "IC_kwDOBLftOs72na3G",
			"user": {
				"login": "adamoutler",
				"id": 527919,
				"node_id": "MDQ6VXNlcjUyNzkxOQ==",
				"avatar_url": "https://avatars.githubusercontent.com/u/527919?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/adamoutler",
				"html_url": "https://github.com/adamoutler",
				"followers_url": "https://api.github.com/users/adamoutler/followers",
				"following_url": "https://api.github.com/users/adamoutler/following{/other_user}",
				"gists_url": "https://api.github.com/users/adamoutler/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/adamoutler/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/adamoutler/subscriptions",
				"organizations_url": "https://api.github.com/users/adamoutler/orgs",
				"repos_url": "https://api.github.com/users/adamoutler/repos",
				"events_url": "https://api.github.com/users/adamoutler/events{/privacy}",
				"received_events_url": "https://api.github.com/users/adamoutler/received_events",
				"type": "User",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-03-26T19:07:21Z",
			"updated_at": "2026-03-26T19:07:21Z",
			"body": "I also want to confirm that a full, workspace-wide test suite (`yarn test`) was executed locally to ensure no regressions were introduced across the monorepo. \n\nAll core application test suites completed successfully. Some minor test suites showed warnings regarding asynchronous timer teardowns, but all individual tests passed. \n\nHere are the summaries from the major packages:\n\n**`@joplin/app-desktop`**\n```\nTest Suites: 33 passed, 33 total\nTests:       166 passed, 166 total\nSnapshots:   0 total\nTime:        47.884 s\nRan all test suites.\n```\n\n**`@joplin/app-mobile`**\n```\nTest Suites: 38 passed, 38 total\nTests:       177 passed, 177 total\nSnapshots:   0 total\nTime:        379.162 s\nRan all test suites.\n```\n\n**`@joplin/lib`**\n*(Note: 1 failure due to `RevisionService.test.js` flake, which passed upon isolation)*\n```\nTest Suites: 140 passed, 140 total (ignoring 1 flaky timing test)\nTests:       1263 passed, 1263 total\nSnapshots:   0 total\nTime:        276.172 s, estimated 400 s\nRan all test suites.\n```\n\n**`@joplin/utils`**\n```\nTest Suites: 11 passed, 11 total\nTests:       57 passed, 57 total\nSnapshots:   0 total\nTime:        11.121 s\nRan all test suites.\n```\n\n**`@joplin/tools`**\n```\nTest Suites: 16 passed, 16 total\nTests:       45 passed, 45 total\nSnapshots:   0 total\nTime:        7.529 s\nRan all test suites.\n```\n",
			"author_association": "NONE",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/4137528774/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": null
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/4137535905",
			"html_url": "https://github.com/laurent22/joplin/pull/14917#issuecomment-4137535905",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14917",
			"id": 4137535905,
			"node_id": "IC_kwDOBLftOs72ncmh",
			"user": {
				"login": "coderabbitai[bot]",
				"id": 136622811,
				"node_id": "BOT_kgDOCCSy2w",
				"avatar_url": "https://avatars.githubusercontent.com/in/347564?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/coderabbitai%5Bbot%5D",
				"html_url": "https://github.com/apps/coderabbitai",
				"followers_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/followers",
				"following_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/following{/other_user}",
				"gists_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/subscriptions",
				"organizations_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/orgs",
				"repos_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/repos",
				"events_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/events{/privacy}",
				"received_events_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/received_events",
				"type": "Bot",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-03-26T19:08:30Z",
			"updated_at": "2026-03-27T00:45:00Z",
			"body": "<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nUpdated several package manifests to use a Yarn-patched `file-type`, removed `request` and `image-data-uri` deps, replaced data-URL decoding with inline base64 parsing (with an added double-write), modernised a GitHub fetch to async/await with AbortController timeout, and changed mobile asset render payload and asset manifest hashes.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**file-type patching** <br> `packages/app-cli/package.json`, `packages/lib/package.json`, `packages/transcribe/package.json`|Replaced plain `file-type@16.5.4` entries with Yarn patched references (`patch:file-type@npm:16.5.4#...`).|\n|**Removed dependencies** <br> `packages/lib/package.json`, `packages/tools/package.json`|Removed `image-data-uri` from `packages/lib` and removed `request` from `packages/tools`.|\n|**Mobile plugin assets** <br> `packages/app-mobile/pluginAssets/abc/abc_render.js.base64.js`, `packages/app-mobile/pluginAssets/index.js`, `packages/app-mobile/pluginAssets/index.web.js`|Updated base64-encoded render payload to iterate `renderContainer.querySelectorAll('svg')`, parse numeric `width`/`height` and set `viewBox` when valid; updated exported asset `hash` values.|\n|**Node shim — image handling** <br> `packages/lib/shim-init-node.ts`|Replaced `image-data-uri.decode()` with manual data-URL parsing: checks for `;base64`, splits at comma, base64-decodes into a `Buffer`, throws if not base64, and writes the buffer to file (write performed twice in the diff).|\n|**HTTP fetch modernisation** <br> `packages/tools/update-readme-contributors.ts`|Replaced callback `request.get` Promise wrapper with `node-fetch` `async/await`, added `AbortController` 15s timeout and ensure timeout cleared, and switched response checks to `response.ok`/`response.status` with thrown errors on non-2xx.|\n\n## Suggested labels\n\nsecurity, mobile, cli, transcribe, bug\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n---\n\n<!-- pre_merge_checks_override_start -->\n> [!IMPORTANT]\n> ## Pre-merge checks failed\n> \n> Please resolve all errors before merging. Addressing warnings is optional.\n<!-- pre_merge_checks_override_end -->\n\n### ❌ Failed checks (1 error, 1 warning)\n\n|               Check name              | Status     | Explanation                                                                                             | Resolution                                                                                                                          |\n| :-----------------------------------: | :--------- | :------------------------------------------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------- |\n| Pr Description Must Follow Guidelines | ❌ Error    | PR description fails to provide high-level solution overview and lacks test plan or verification steps. | Revise solution section to describe overall approach without excessive technical details and add test plan with verification steps. |\n|           Docstring Coverage          | ⚠️ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.                    | Write docstrings for the functions missing them to satisfy the coverage threshold.                                                  |\n\n<details>\n<summary>✅ Passed checks (2 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                |\n| :---------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|    Title check    | ✅ Passed | The title directly and clearly summarises the main objective of the PR: fixing two critical security vulnerabilities (SSRF and DoS) in workspace dependencies.             |\n| Description check | ✅ Passed | The description comprehensively explains both vulnerabilities, the approach taken to fix each one, and provides detailed test results confirming the fixes work correctly. |\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=laurent22/joplin&utm_content=14917)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- [encoded data, 9004 characters] -->\n\n<!-- internal state end -->",
			"author_association": "CONTRIBUTOR",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/4137535905/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": {
				"id": 347564,
				"client_id": "Iv1.6aaafe4fe882736b",
				"slug": "coderabbitai",
				"node_id": "A_kwHOB96YWc4ABU2s",
				"owner": {
					"login": "coderabbitai",
					"id": 132028505,
					"node_id": "O_kgDOB96YWQ",
					"avatar_url": "https://avatars.githubusercontent.com/u/132028505?v=4",
					"gravatar_id": "",
					"url": "https://api.github.com/users/coderabbitai",
					"html_url": "https://github.com/coderabbitai",
					"followers_url": "https://api.github.com/users/coderabbitai/followers",
					"following_url": "https://api.github.com/users/coderabbitai/following{/other_user}",
					"gists_url": "https://api.github.com/users/coderabbitai/gists{/gist_id}",
					"starred_url": "https://api.github.com/users/coderabbitai/starred{/owner}{/repo}",
					"subscriptions_url": "https://api.github.com/users/coderabbitai/subscriptions",
					"organizations_url": "https://api.github.com/users/coderabbitai/orgs",
					"repos_url": "https://api.github.com/users/coderabbitai/repos",
					"events_url": "https://api.github.com/users/coderabbitai/events{/privacy}",
					"received_events_url": "https://api.github.com/users/coderabbitai/received_events",
					"type": "Organization",
					"user_view_type": "public",
					"site_admin": false
				},
				"name": "coderabbitai",
				"description": "# Transforming Code Reviews with AI\r\n\r\n## Features\r\n\r\n**Automated Reviews**: Continuous reviews of the pull requests including incremental commits. \r\n\r\n**Summarization**: Generates high-level summary and a technical walkthrough of the PR changes. \r\n\r\n**Line-by-line review**: Provides line-by-line suggestions committable with one click.\r\n\r\n**Codebase verification**:  Verifies the impact on the overall codebase and identifies missing changes.\r\n\r\n**Insights into your code**:  Ask any questions on your codebase within the pull request \r\n\r\n**Chat about your code** : Chat with the bot around your code. The more you chat, the smarter it gets.\r\n\r\n**Issue Validation**:  Validates the PR against the linked issues and identifies other related issues \r\n\r\n\r\n\r\n",
				"external_url": "https://coderabbit.ai?utm_source=cr_app&utm_medium=github",
				"html_url": "https://github.com/apps/coderabbitai",
				"created_at": "2023-06-14T15:47:27Z",
				"updated_at": "2026-03-14T07:58:44Z",
				"permissions": {
					"actions": "read",
					"checks": "write",
					"contents": "write",
					"discussions": "read",
					"issues": "write",
					"members": "read",
					"metadata": "read",
					"pull_requests": "write",
					"statuses": "write"
				},
				"events": [
					"issues",
					"issue_comment",
					"label",
					"organization",
					"pull_request",
					"pull_request_review",
					"pull_request_review_comment",
					"pull_request_review_thread",
					"release",
					"repository"
				]
			}
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/4139260798",
			"html_url": "https://github.com/laurent22/joplin/pull/14917#issuecomment-4139260798",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14917",
			"id": 4139260798,
			"node_id": "IC_kwDOBLftOs72uBt-",
			"user": {
				"login": "adamoutler",
				"id": 527919,
				"node_id": "MDQ6VXNlcjUyNzkxOQ==",
				"avatar_url": "https://avatars.githubusercontent.com/u/527919?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/adamoutler",
				"html_url": "https://github.com/adamoutler",
				"followers_url": "https://api.github.com/users/adamoutler/followers",
				"following_url": "https://api.github.com/users/adamoutler/following{/other_user}",
				"gists_url": "https://api.github.com/users/adamoutler/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/adamoutler/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/adamoutler/subscriptions",
				"organizations_url": "https://api.github.com/users/adamoutler/orgs",
				"repos_url": "https://api.github.com/users/adamoutler/repos",
				"events_url": "https://api.github.com/users/adamoutler/events{/privacy}",
				"received_events_url": "https://api.github.com/users/adamoutler/received_events",
				"type": "User",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-03-27T00:45:19Z",
			"updated_at": "2026-03-27T00:45:19Z",
			"body": "This was 100% working fine and the 2-dependencies were updated.  Code rabit is set way too high. First two kinda-not related issues. I accepted the fixes and it broke the build.  Then it piled on 4 more pretty much entirely unrelated issues.  I'll just ignore it and let you guys update your own dependencies. ",
			"author_association": "NONE",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/4139260798/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": null
		}
	]
}