# Security Implications of --disable-file-downloads and --disable-file-uploads in code-server

> Secure your code-server by understanding the security implications of --disable-file-downloads and --disable-file-uploads. Learn how to block these attack vectors.

- Repository: [Coder/code-server](https://github.com/coder/code-server)
- Tags: security
- Published: 2026-03-01

---

**Disabling file transfers with `--disable-file-downloads` and `--disable-file-uploads` eliminates two primary attack vectors in code-server by removing UI elements and blocking APIs that would otherwise allow data exfiltration or malicious file injection into remote workspaces.**

The `coder/code-server` project runs a full VS Code instance inside a remote browser, exposing the underlying file system through the editor's interface. When deploying in security-sensitive environments, administrators must control how data flows between the remote host and client machines. This article examines the specific security mechanisms behind these CLI flags, tracing their implementation from [`src/node/cli.ts`](https://github.com/coder/code-server/blob/main/src/node/cli.ts) through to the frontend context keys that gate user actions.

## Architecture of File Transfer Controls

The security model relies on a propagation chain: CLI flags populate the environment service, which publishes **context keys** that the UI layer consumes to hide elements and reject API calls.

### CLI Flag Definition and Injection

The flags are defined in [`src/node/cli.ts`](https://github.com/coder/code-server/blob/main/src/node/cli.ts) at lines 182–191, where the argument parser registers both options and injects them into the process environment. When present, these boolean values flow into the `args` object that the entire application consumes.

- **`--disable-file-downloads`**: Stored at lines 182–186, this flag controls whether users can export files from the remote workspace to their local machine.
- **`--disable-file-uploads`**: Defined at lines 187–191, this flag governs the ability to import files from the client into the remote environment.

### Context Key Propagation to the Frontend

The bridge between the backend configuration and frontend enforcement occurs in `patches/getting-started.diff` (lines 206–228). This patch injects two readonly properties into the browser's environment service:

- `isEnabledFileDownloads` → published as the context key `IsEnabledFileDownloads`
- `isEnabledFileUploads` → published as the context key `IsEnabledFileUploads`

As implemented in `patches/external-file-actions.diff`, the UI layer checks these context keys before rendering the "Show Local" download button, enabling drag-and-drop handlers, or executing transfer commands. When a flag is set to `false`, the associated UI elements are removed from the DOM and the underlying API returns errors to any extension attempting to invoke transfers.

## Security Threats Mitigated by Disabling Transfers

Enabling these flags (setting them to `true` to disable the features) reduces the attack surface by closing specific data channels. The security consequences differ significantly from the default permissive state.

### Preventing Data Exfiltration

By default, code-server renders a **"Show Local"** button in the file tree that allows users to download any file they have permission to read. In environments containing sensitive source code, credentials, or configuration files, this creates a straightforward exfiltration channel. When `--disable-file-downloads` is active, the button is hidden and the download command handler rejects all requests, ensuring that even a compromised user session cannot easily leak files through the browser interface.

### Blocking Malware and Payload Injection

The upload mechanism provides a direct path for attackers to introduce binaries, scripts, or malicious payloads into the remote workspace. An adversary who gains access to a running VS Code session could drag-and-drop or programmatically upload executable files that run on the host. The `--disable-file-uploads` flag removes the upload area from the file-tree UI and blocks the upload API, preventing injection even if the session is compromised.

### Reducing Extension Attack Surface

Extensions frequently use the file transfer APIs to fetch dependencies or resources. While legitimate extensions use this for language servers and linters, malicious or compromised extensions can abuse these channels to pull in additional payloads or exfiltrate data. Disabling transfers causes such extensions to fail during initialization or execution, breaking functionality but preventing abuse. This is verified in the end-to-end tests located in [`test/e2e/downloads.test.ts`](https://github.com/coder/code-server/blob/main/test/e2e/downloads.test.ts) and [`test/e2e/uploads.test.ts`](https://github.com/coder/code-server/blob/main/test/e2e/uploads.test.ts), which confirm that API calls return errors when the flags are enabled.

## Configuration and Verification Examples

### Launching with Security Flags

Apply these flags at startup to enforce transfer restrictions immediately:

```bash

# Disable both upload and download capabilities

code-server --disable-file-downloads --disable-file-uploads

# Alternative: Environment variables for containerized deployments

CS_DISABLE_FILE_DOWNLOADS=1 CS_DISABLE_FILE_UPLOADS=1 code-server

```

The CLI parser in [`src/node/cli.ts`](https://github.com/coder/code-server/blob/main/src/node/cli.ts) processes these arguments and stores them in the global `args` configuration object, which the environment service reads during initialization.

### Verifying Flags Within Extensions

Extension developers or security auditors can check these permissions programmatically through the context key service:

```typescript
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IsEnabledFileDownloads, IsEnabledFileUploads } from 'vs/platform/contextkey/common/contextkey';

function auditTransferPermissions(accessor: ServicesAccessor): void {
    const contextKeyService = accessor.get(IContextKeyService);
    
    const downloadsAllowed = contextKeyService.getValue(IsEnabledFileDownloads.key);
    const uploadsAllowed = contextKeyService.getValue(IsEnabledFileUploads.key);
    
    console.log('File downloads enabled:', downloadsAllowed);
    console.log('File uploads enabled:', uploadsAllowed);
}

```

When the server runs with flags set, these context keys resolve to `false`, causing any conditional UI rendering or command execution to bypass the transfer functionality.

### Frontend Error Handling

The frontend code explicitly checks the environment service before initiating transfers, as shown in the typing definitions from `patches/external-file-actions.diff`:

```typescript
import { IFileService } from 'vs/platform/files/common/fileService';

async function safeDownloadFile(fileService: IFileService, uri: URI): Promise<void> {
    if (!environmentService.isEnabledFileDownloads) {
        throw new Error('File downloads are disabled by the server configuration.');
    }
    // Proceed with standard download workflow...
}

```

This ensures that even if a user circumvents the UI hiding mechanisms, the underlying service layer still enforces the security policy.

## Summary

- **`--disable-file-downloads`** removes the "Show Local" button and download commands from the UI, preventing users from exporting files through the browser and blocking extensions from using the download API.
- **`--disable-file-uploads`** disables drag-and-drop import functionality and upload areas, stopping both manual and programmatic file injection into the workspace.
- The enforcement mechanism flows from [`src/node/cli.ts`](https://github.com/coder/code-server/blob/main/src/node/cli.ts) through environment services and context keys (`IsEnabledFileDownloads`, `IsEnabledFileUploads`) to UI gating, as implemented in `patches/getting-started.diff`.
- End-to-end tests in [`test/e2e/downloads.test.ts`](https://github.com/coder/code-server/blob/main/test/e2e/downloads.test.ts) and [`test/e2e/uploads.test.ts`](https://github.com/coder/code-server/blob/main/test/e2e/uploads.test.ts) validate that these flags correctly block transfer APIs.
- The trade-off requires users to rely on external tools like `scp`, `rsync`, or Git for legitimate file transfers, but significantly reduces risks of data exfiltration and malware injection.

## Frequently Asked Questions

### Can users bypass these flags using VS Code extensions?

No. The flags propagate to **context keys** that the entire frontend ecosystem respects, including the extension host. When `IsEnabledFileDownloads` or `IsEnabledFileUploads` resolve to `false`, the underlying service layers return errors to any API caller, including extensions. Malicious extensions attempting to exfiltrate data or upload payloads will fail at the API boundary, as confirmed by the test suites in [`test/e2e/downloads.test.ts`](https://github.com/coder/code-server/blob/main/test/e2e/downloads.test.ts) and [`test/e2e/uploads.test.ts`](https://github.com/coder/code-server/blob/main/test/e2e/uploads.test.ts).

### Do these flags affect Git operations or terminal-based file transfers?

No. These flags only disable the **UI-driven and API-driven** transfer mechanisms built into code-server's browser interface. Git fetch/pull/push operations, terminal-based `scp` commands, and other external transfer tools operate outside the VS Code extension API and remain unaffected. Users must resort to these external methods when the flags are enabled.

### What happens if I only disable one flag but not the other?

Each flag operates independently. Disabling only `--disable-file-downloads` allows users to upload files while preventing downloads, creating a one-way data flow suitable for ingestion-only workflows. Conversely, disabling only `--disable-file-uploads` permits data export while blocking imports. The context keys `IsEnabledFileDownloads` and `IsEnabledFileUploads` are evaluated separately throughout the codebase.

### Are these flags available in all versions of code-server?

These flags were introduced through specific patches including `patches/getting-started.diff` and `patches/external-file-actions.diff`. Administrators should verify their installation includes these patches by checking the version release notes or inspecting [`src/node/cli.ts`](https://github.com/coder/code-server/blob/main/src/node/cli.ts) for the flag definitions at lines 182–191. The end-to-end test coverage in `test/e2e/` confirms the functionality is active in builds that include these files.