CVE-2023-46944 (TypeScript, published 2023-11-28T22:15Z)
Description: value: An issue in GitKraken GitLens before v.14.0.0 allows an attacker to execute arbitrary code via a crafted file to the Visual Studio Codes workspace trust component.
Severity: nan (CVSS v3 base score: 7.8)
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/gitkraken/vscode-gitlens
Files changed:
src/env/node/git/git.ts
src/env/node/git/localGitProvider.ts
src/git/errors.ts
src/git/gitProviderService.ts
src/webviews/apps/home/home.html
src/webviews/apps/home/home.ts
src/webviews/home/homeWebview.ts
src/webviews/home/protocol.ts
Commit message: Disables Git access in Restricted Mode (untrusted)


Vulnerable code:
import { StashPushError, StashPushErrorReason } from '../../../git/errors';
			} else {
		const { repositories } = this.state;
		const hasRepos = repositories.openCount > 0;
		const value = hasRepos ? 'true' : 'false';

		let $el = document.getElementById('no-repo');
		$el?.setAttribute('aria-hidden', value);
		if (hasRepos) {
			$el?.setAttribute('hidden', value);
		} else {
			$el?.removeAttribute('hidden');
		}
		$el = document.getElementById('no-repo-alert');
		const showUnsafe = repositories.hasUnsafe && !hasRepos;
		const $unsafeEl = document.getElementById('unsafe-repo-alert');
		if (showUnsafe) {
			$el?.setAttribute('aria-hidden', 'true');
			$el?.setAttribute('hidden', 'true');
			$unsafeEl?.setAttribute('aria-hidden', 'false');
			$unsafeEl?.removeAttribute('hidden');
		} else {
			$unsafeEl?.setAttribute('aria-hidden', 'true');
			$unsafeEl?.setAttribute('hidden', 'true');
			$el?.setAttribute('aria-hidden', value);
			if (hasRepos) {
				$el?.setAttribute('hidden', value);
			} else {
				$el?.removeAttribute('hidden');
			}
import { Disposable, window } from 'vscode';
import type { CompleteStepParams, DismissBannerParams, DismissSectionParams, State } from './protocol';
		const sub = await this.getSubscription(subscription);
			visibility: await this.getRepoVisibility(),
	private getRepositoriesState() {

Fixed code:
import { StashPushError, StashPushErrorReason, WorkspaceUntrustedError } from '../../../git/errors';
		if (!workspace.isTrusted) throw new WorkspaceUntrustedError();

		if (!workspace.isTrusted) throw new WorkspaceUntrustedError();

			if (ex instanceof WorkspaceUntrustedError) return emptyArray as [];

			} else if (safe === false) {

export class WorkspaceUntrustedError extends Error {
	constructor() {
		super('Unable to perform Git operations because the current workspace is untrusted');

		Error.captureStackTrace?.(this, WorkspaceUntrustedError);
	}
}

const emptyDisposable = Object.freeze({
	dispose: () => {
		/* noop */
	},
});

			!workspace.isTrusted
				? workspace.onDidGrantWorkspaceTrust(() => {
						if (workspace.isTrusted && workspace.workspaceFolders?.length) {
							void this.discoverRepositories(workspace.workspaceFolders, { force: true });
						}
				  })
				: emptyDisposable,
			<div id="untrusted-alert" class="alert alert--info mb-0" aria-hidden="true" hidden>
				<h1 class="alert__title">Untrusted workspace</h1>
				<div class="alert__description">
					<p>Unable to open repositories in Restricted Mode.</p>
					<p class="centered">
						<vscode-button data-action="command:workbench.trust.manage"
							>Manage Workspace Trust</vscode-button
						>
					</p>
				</div>
			</div>
		const {
			repositories: { openCount, hasUnsafe, trusted },
		} = this.state;
		if (!trusted) {
			setElementVisibility('untrusted-alert', true);
			setElementVisibility('no-repo', false);
			setElementVisibility('no-repo-alert', false);
			setElementVisibility('unsafe-repo-alert', false);

			return;

		setElementVisibility('untrusted-alert', false);

		const noRepos = openCount === 0;

		setElementVisibility('no-repo', noRepos);
		setElementVisibility('no-repo-alert', noRepos && !hasUnsafe);
		setElementVisibility('unsafe-repo-alert', hasUnsafe);
function setElementVisibility(elementOrId: string | HTMLElement | null | undefined, visible: boolean) {
	let el;
	if (typeof elementOrId === 'string') {
		el = document.getElementById(elementOrId);
	} else {
		el = elementOrId;
	}
	if (el == null) return;

	if (visible) {
		el.setAttribute('aria-hidden', 'false');
		el.removeAttribute('hidden');
	} else {
		el.setAttribute('aria-hidden', 'true');
		el?.setAttribute('hidden', 'true');
	}
}

import { Disposable, window, workspace } from 'vscode';
import { getSettledValue } from '../../system/promise';
import type {
	CompleteStepParams,
	DidChangeRepositoriesParams,
	DismissBannerParams,
	DismissSectionParams,
	State,
} from './protocol';
const emptyDisposable = Object.freeze({
	dispose: () => {
		/* noop */
	},
});

			!workspace.isTrusted
				? workspace.onDidGrantWorkspaceTrust(this.notifyDidChangeRepositories, this)
				: emptyDisposable,
		const [visibilityResult, subscriptionResult] = await Promise.allSettled([
			this.getRepoVisibility(),
			this.getSubscription(subscription),
		]);

		const sub = getSettledValue(subscriptionResult)!;
			visibility: getSettledValue(visibilityResult)!,
	private getRepositoriesState(): DidChangeRepositoriesParams {
			trusted: workspace.isTrusted,
	trusted: boolean;