From 6121eff28f248cf1b0aca6e649160e8e6e3a422f Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 25 Aug 2026 10:20:52 -0700 Subject: [PATCH 01/13] Add security skill --- .github/skills/security-report-check/SKILL.md | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 .github/skills/security-report-check/SKILL.md diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md new file mode 100644 index 0000000000000..24907c35eae33 --- /dev/null +++ b/.github/skills/security-report-check/SKILL.md @@ -0,0 +1,94 @@ +--- +name: security-report-check +description: > + Are you doing security research on this repo? + This document covers what guarantees and non-guarantees are provided. + Consult this document before reporting a security issue or conducting security research. +--- + +# Security Properties of `tsc` + +## Overview + +The TypeScript compiler (`tsc`) is a **build tool**, not a sandbox. +It transforms TypeScript source files into JavaScript output files. +This document describes what `tsc` guarantees and does not guarantee when invoked on untrusted input. + +## Security Guarantees + +**No arbitrary code execution.** +Running `tsc` on a malicious `.ts` or `tsconfig.json` file will never cause the input code to be executed. +The compiler parses, type-checks, and emits; it does not evaluate the programs it compiles. +There is no `eval`-at-compile-time, no macro system, and no plugin mechanism that runs author-supplied code during compilation. +This is the core security property of `tsc`. + +*Exception*: If content mappers are enabled, this *does* enable execution of third-party code. +Only pass the `--runExternalCode` flag if you have validated which content mappers are available and that you are OK with running them. + +**Deterministic side effects.** +The only side effect of a successful `tsc` invocation is writing output files (`.js`, `.d.ts`, `.map`, `.tsbuildinfo`) to disk. +It does not make HTTP requests, spawn child processes (except via content mappers, see above), or interact with the system beyond file I/O. + +**Safe exit.** +Certain adversarial inputs may cause crashes, but these crashes will unwind the process normally, and will not be a source of buffer overrun or other memory safety exploit vectors. + +## Non-Guarantees + +**Arbitrary file writes.** +`tsc` writes compiler output to paths derived from its configuration (`outDir`, `outFile`, `declarationDir`, etc.) and the structure of the input project. +A malicious `tsconfig.json` can direct output to any path writable by the calling user. +This is by design: writing files to disk *is the point* of a compiler. +Callers who need to constrain output locations must do so externally (e.g., filesystem permissions, containers, sandboxing). +Similarly, running `tsc --build --clean` may delete files from disk; crafted `.tsbuildinfo` or `tsconfig.json`s may cause any file to be deleted. + +**Input code is output code.** +If an attacker has control of an input TS file, they can of course control the contents of the output JS file. +Attacks that depend on control of the input file and execution of the output file are not considered compiler security issues, because the attacker already has control of the input file. + +**File read sandboxing.** +`tsc` will read files from paths specified in input files, and transitive references from there, including import paths and reference directives. +An attacker in control of these files may therefore cause a *read* of any file path the `tsc` process has privileges to read, and `tsc` may reprint certain file contents in its output messages. +In other words, for example, it is not generally safe to run `tsc` on untrusted code and print back the error message contents to an untrusted party, as this could expose local filesystem contents to the attacker. +Use of standard sandboxing strategies is recommended to secure scenarios similar to this. + +**Resource consumption.** +TypeScript's type system is Turing-complete. +A crafted input file can cause `tsc` to consume unbounded CPU time or memory during type-checking, and in fact small type constructs that can consume a large amount of time are common and intentional. +Routine compilations of normal code can legitimately take multiple minutes and gigabytes of memory, so there is no reliable way to distinguish between a "normal" long-running compilation and an adversarially-constructed one. + +Callers operating on untrusted input should enforce resource limits externally (e.g., `ulimit`, cgroups, process timeouts). +You should not assume that an adverserially-constructed program will successfully typecheck in any bounded amount of time. +"Local DOS" is thus not a *security* report; if you encounter a performance problem, you can report this through the normal issue tracker. + +**Crashes** +`tsc` may gracefully crash, hang, or produce unexpected diagnostics when given adversarial input. +While crashes in "normal" code are treated as bugs and fixed when reported, the compiler does *not* guarantee non-crashing in the presence of all possible malformed inputs (e.g. an unbounded series of `f(f(f(f(...`). + +**tsbuildinfo** +The `.tsbuildinfo` file is a cache of compiler state that is used to speed up incremental compilation. +If this file is modified, it can cause `tsc` to e.g. fail to build a file because it thinks the file is up-to-date, or to recompile a file that has not changed. +tsbuildinfo files should be considered as sensitive as tsconfig.json files in terms of security; an attacker who can modify them can cause arbitrary file reads and writes. + +## Language Service + +The TypeScript Language Service (LS) only executes in the context of a [trusted workspace (VS Code)](https://code.visualstudio.com/docs/editing/workspaces/workspace-trust) or [trusted folder (VS)](https://learn.microsoft.com/en-us/visualstudio/ide/trust-settings?view=visualstudio). +Similar to tsc, there are no guaranteed resource caps in the LS, and "hangs" may occur in the presence of adversarial inputs. + +## Examples + +### Hypothetically Valid Security Reports + +- Running `tsc malicious.ts` executes top-level code from `malicious.ts`, even though `--runExternalCode` was not passed. +- A specially crafted source file causes `tsc` to launch an attacker-chosen executable, even though `--runExternalCode` was not passed. +- A malformed input exploits a memory-safety flaw to execute arbitrary native code rather than merely causing the `tsc` process to exit. + +### Hypothetically Invalid Security Reports + +- A recursive conditional type causes the reporter's local `tsc` process to use all available CPU or memory, hang, or terminate with a stack overflow. +- A malicious `tsconfig.json` directs emitted JavaScript or declarations to an unexpected path that is writable by the user running `tsc`. +- A project causes `tsc --build --clean` to delete a file that the invoking user has permission to delete. +- An import or reference directive causes `tsc` to read a local file, and a diagnostic reveals some of that file's contents to the caller. +- Attacker-controlled TypeScript produces attacker-controlled JavaScript that performs a malicious action when executed. +- A malformed source file crashes `tsc` without escaping the process or causing memory corruption. +- A content mapper executes code after the caller explicitly enables content mappers with `--runExternalCode`. + From c289ead223e7e0b78148fb9f5a8e43082ec8a8d0 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 10 Sep 2026 14:07:57 -0700 Subject: [PATCH 02/13] Clarify side effects and external code execution Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/skills/security-report-check/SKILL.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md index 24907c35eae33..c2c7afba982eb 100644 --- a/.github/skills/security-report-check/SKILL.md +++ b/.github/skills/security-report-check/SKILL.md @@ -25,9 +25,9 @@ This is the core security property of `tsc`. *Exception*: If content mappers are enabled, this *does* enable execution of third-party code. Only pass the `--runExternalCode` flag if you have validated which content mappers are available and that you are OK with running them. -**Deterministic side effects.** -The only side effect of a successful `tsc` invocation is writing output files (`.js`, `.d.ts`, `.map`, `.tsbuildinfo`) to disk. -It does not make HTTP requests, spawn child processes (except via content mappers, see above), or interact with the system beyond file I/O. +**Limited default side effects.** +Outside of explicitly enabled external code, compiler invocations interact with the system through file-system operations and process I/O. Depending on the options, `tsc` may write compiler, build-info, trace, or profile files, update output timestamps, or delete build outputs (for example, with `--build --clean`). +The compiler does not make HTTP requests or spawn child processes except through content mappers. **Safe exit.** Certain adversarial inputs may cause crashes, but these crashes will unwind the process normally, and will not be a source of buffer overrun or other memory safety exploit vectors. From 82e46750f504c699a5f55969001e3329915ad73d Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 10 Sep 2026 14:09:20 -0700 Subject: [PATCH 03/13] Update .github/skills/security-report-check/SKILL.md Co-authored-by: Daniel Rosenwasser --- .github/skills/security-report-check/SKILL.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md index c2c7afba982eb..ae4fcdc31c4c5 100644 --- a/.github/skills/security-report-check/SKILL.md +++ b/.github/skills/security-report-check/SKILL.md @@ -11,7 +11,7 @@ description: > ## Overview The TypeScript compiler (`tsc`) is a **build tool**, not a sandbox. -It transforms TypeScript source files into JavaScript output files. +It transforms TypeScript source files into JavaScript output files and reports potential errors. This document describes what `tsc` guarantees and does not guarantee when invoked on untrusted input. ## Security Guarantees @@ -25,9 +25,12 @@ This is the core security property of `tsc`. *Exception*: If content mappers are enabled, this *does* enable execution of third-party code. Only pass the `--runExternalCode` flag if you have validated which content mappers are available and that you are OK with running them. -**Limited default side effects.** -Outside of explicitly enabled external code, compiler invocations interact with the system through file-system operations and process I/O. Depending on the options, `tsc` may write compiler, build-info, trace, or profile files, update output timestamps, or delete build outputs (for example, with `--build --clean`). -The compiler does not make HTTP requests or spawn child processes except through content mappers. +**Limited default side effects.** + +Outside of explicitly enabled external code, compiler invocations interact with the system through file-system operations and process I/O. Depending on the options, `tsc` may write compiler, build-info, trace, or profile files, update output timestamps, or delete build outputs (for example, with `--build --clean`). + +The compiler does not make HTTP requests or spawn child processes except through content mappers. + **Safe exit.** Certain adversarial inputs may cause crashes, but these crashes will unwind the process normally, and will not be a source of buffer overrun or other memory safety exploit vectors. From 8fc143f561acb5f080e3cf20973af67c7d5fb96b Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 10 Sep 2026 14:09:38 -0700 Subject: [PATCH 04/13] Update .github/skills/security-report-check/SKILL.md Co-authored-by: Daniel Rosenwasser --- .github/skills/security-report-check/SKILL.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md index ae4fcdc31c4c5..574351d920191 100644 --- a/.github/skills/security-report-check/SKILL.md +++ b/.github/skills/security-report-check/SKILL.md @@ -16,7 +16,8 @@ This document describes what `tsc` guarantees and does not guarantee when invoke ## Security Guarantees -**No arbitrary code execution.** +### No arbitrary code execution + Running `tsc` on a malicious `.ts` or `tsconfig.json` file will never cause the input code to be executed. The compiler parses, type-checks, and emits; it does not evaluate the programs it compiles. There is no `eval`-at-compile-time, no macro system, and no plugin mechanism that runs author-supplied code during compilation. From e5f78c00482a1e194a8729c37b9b86954c13774e Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 10 Sep 2026 14:10:01 -0700 Subject: [PATCH 05/13] Update .github/skills/security-report-check/SKILL.md Co-authored-by: Daniel Rosenwasser --- .github/skills/security-report-check/SKILL.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md index 574351d920191..46154e048204a 100644 --- a/.github/skills/security-report-check/SKILL.md +++ b/.github/skills/security-report-check/SKILL.md @@ -38,7 +38,8 @@ Certain adversarial inputs may cause crashes, but these crashes will unwind the ## Non-Guarantees -**Arbitrary file writes.** +### Arbitrary file writes + `tsc` writes compiler output to paths derived from its configuration (`outDir`, `outFile`, `declarationDir`, etc.) and the structure of the input project. A malicious `tsconfig.json` can direct output to any path writable by the calling user. This is by design: writing files to disk *is the point* of a compiler. From 648bea5bc2aa4dff8a69948c68c9a722be78fea0 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 10 Sep 2026 14:10:28 -0700 Subject: [PATCH 06/13] Update .github/skills/security-report-check/SKILL.md Co-authored-by: Daniel Rosenwasser --- .github/skills/security-report-check/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md index 46154e048204a..1c8f70230c05f 100644 --- a/.github/skills/security-report-check/SKILL.md +++ b/.github/skills/security-report-check/SKILL.md @@ -41,7 +41,7 @@ Certain adversarial inputs may cause crashes, but these crashes will unwind the ### Arbitrary file writes `tsc` writes compiler output to paths derived from its configuration (`outDir`, `outFile`, `declarationDir`, etc.) and the structure of the input project. -A malicious `tsconfig.json` can direct output to any path writable by the calling user. +It is **expected** that a given `tsconfig.json` can direct output to any path writable by the calling user. This is by design: writing files to disk *is the point* of a compiler. Callers who need to constrain output locations must do so externally (e.g., filesystem permissions, containers, sandboxing). Similarly, running `tsc --build --clean` may delete files from disk; crafted `.tsbuildinfo` or `tsconfig.json`s may cause any file to be deleted. From 62f2cc6d406f9a902b055294f60a5b3e0e004d9c Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 10 Sep 2026 14:11:00 -0700 Subject: [PATCH 07/13] Update .github/skills/security-report-check/SKILL.md Co-authored-by: Daniel Rosenwasser --- .github/skills/security-report-check/SKILL.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md index 1c8f70230c05f..2f9a27bd56771 100644 --- a/.github/skills/security-report-check/SKILL.md +++ b/.github/skills/security-report-check/SKILL.md @@ -56,7 +56,8 @@ An attacker in control of these files may therefore cause a *read* of any file p In other words, for example, it is not generally safe to run `tsc` on untrusted code and print back the error message contents to an untrusted party, as this could expose local filesystem contents to the attacker. Use of standard sandboxing strategies is recommended to secure scenarios similar to this. -**Resource consumption.** +### Resource consumption + TypeScript's type system is Turing-complete. A crafted input file can cause `tsc` to consume unbounded CPU time or memory during type-checking, and in fact small type constructs that can consume a large amount of time are common and intentional. Routine compilations of normal code can legitimately take multiple minutes and gigabytes of memory, so there is no reliable way to distinguish between a "normal" long-running compilation and an adversarially-constructed one. From 60014a5a82c59e2ae4c95493643d6d078a6ba1f1 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 10 Sep 2026 14:11:17 -0700 Subject: [PATCH 08/13] Update .github/skills/security-report-check/SKILL.md Co-authored-by: Daniel Rosenwasser --- .github/skills/security-report-check/SKILL.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md index 2f9a27bd56771..950e192564f48 100644 --- a/.github/skills/security-report-check/SKILL.md +++ b/.github/skills/security-report-check/SKILL.md @@ -46,7 +46,8 @@ This is by design: writing files to disk *is the point* of a compiler. Callers who need to constrain output locations must do so externally (e.g., filesystem permissions, containers, sandboxing). Similarly, running `tsc --build --clean` may delete files from disk; crafted `.tsbuildinfo` or `tsconfig.json`s may cause any file to be deleted. -**Input code is output code.** +### Input code is output code + If an attacker has control of an input TS file, they can of course control the contents of the output JS file. Attacks that depend on control of the input file and execution of the output file are not considered compiler security issues, because the attacker already has control of the input file. From dd3241627ca5d8f65cd3d16895450591c642cbd2 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 10 Sep 2026 14:11:34 -0700 Subject: [PATCH 09/13] Update .github/skills/security-report-check/SKILL.md Co-authored-by: Daniel Rosenwasser --- .github/skills/security-report-check/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md index 950e192564f48..83b23960ce737 100644 --- a/.github/skills/security-report-check/SKILL.md +++ b/.github/skills/security-report-check/SKILL.md @@ -65,7 +65,7 @@ Routine compilations of normal code can legitimately take multiple minutes and g Callers operating on untrusted input should enforce resource limits externally (e.g., `ulimit`, cgroups, process timeouts). You should not assume that an adverserially-constructed program will successfully typecheck in any bounded amount of time. -"Local DOS" is thus not a *security* report; if you encounter a performance problem, you can report this through the normal issue tracker. +"Local Denial of Service (DoS)" is thus not a *security* report; if you encounter a performance problem, you can report this through the normal issue tracker. **Crashes** `tsc` may gracefully crash, hang, or produce unexpected diagnostics when given adversarial input. From 610dccf1340fde0d0589f0663a1a6f29ab9ea468 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 10 Sep 2026 14:11:48 -0700 Subject: [PATCH 10/13] Update .github/skills/security-report-check/SKILL.md Co-authored-by: Daniel Rosenwasser --- .github/skills/security-report-check/SKILL.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md index 83b23960ce737..255b8ee31a812 100644 --- a/.github/skills/security-report-check/SKILL.md +++ b/.github/skills/security-report-check/SKILL.md @@ -67,7 +67,8 @@ Callers operating on untrusted input should enforce resource limits externally ( You should not assume that an adverserially-constructed program will successfully typecheck in any bounded amount of time. "Local Denial of Service (DoS)" is thus not a *security* report; if you encounter a performance problem, you can report this through the normal issue tracker. -**Crashes** +### Crashes + `tsc` may gracefully crash, hang, or produce unexpected diagnostics when given adversarial input. While crashes in "normal" code are treated as bugs and fixed when reported, the compiler does *not* guarantee non-crashing in the presence of all possible malformed inputs (e.g. an unbounded series of `f(f(f(f(...`). From 3be4e7e7fbc1b0045d5e2a9841e1693e694e5a04 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 10 Sep 2026 14:12:19 -0700 Subject: [PATCH 11/13] Update .github/skills/security-report-check/SKILL.md Co-authored-by: Daniel Rosenwasser --- .github/skills/security-report-check/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md index 255b8ee31a812..3cebd7d729af2 100644 --- a/.github/skills/security-report-check/SKILL.md +++ b/.github/skills/security-report-check/SKILL.md @@ -75,7 +75,7 @@ While crashes in "normal" code are treated as bugs and fixed when reported, the **tsbuildinfo** The `.tsbuildinfo` file is a cache of compiler state that is used to speed up incremental compilation. If this file is modified, it can cause `tsc` to e.g. fail to build a file because it thinks the file is up-to-date, or to recompile a file that has not changed. -tsbuildinfo files should be considered as sensitive as tsconfig.json files in terms of security; an attacker who can modify them can cause arbitrary file reads and writes. +.`tsbuildinfo` files should be considered as sensitive as `tsconfig.json` files in terms of security; an attacker who can modify them can cause arbitrary file reads and writes. ## Language Service From 5af642a5e6213c704a48d5006376cc57321371de Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 10 Sep 2026 14:12:34 -0700 Subject: [PATCH 12/13] Update .github/skills/security-report-check/SKILL.md Co-authored-by: Daniel Rosenwasser --- .github/skills/security-report-check/SKILL.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md index 3cebd7d729af2..2419a685b0dd8 100644 --- a/.github/skills/security-report-check/SKILL.md +++ b/.github/skills/security-report-check/SKILL.md @@ -72,7 +72,8 @@ You should not assume that an adverserially-constructed program will successfull `tsc` may gracefully crash, hang, or produce unexpected diagnostics when given adversarial input. While crashes in "normal" code are treated as bugs and fixed when reported, the compiler does *not* guarantee non-crashing in the presence of all possible malformed inputs (e.g. an unbounded series of `f(f(f(f(...`). -**tsbuildinfo** +### tsbuildinfo + The `.tsbuildinfo` file is a cache of compiler state that is used to speed up incremental compilation. If this file is modified, it can cause `tsc` to e.g. fail to build a file because it thinks the file is up-to-date, or to recompile a file that has not changed. .`tsbuildinfo` files should be considered as sensitive as `tsconfig.json` files in terms of security; an attacker who can modify them can cause arbitrary file reads and writes. From 17421c08e59731e2d62218a2f87809db6b822a12 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 10 Sep 2026 14:13:30 -0700 Subject: [PATCH 13/13] Update .github/skills/security-report-check/SKILL.md Co-authored-by: Daniel Rosenwasser --- .github/skills/security-report-check/SKILL.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/skills/security-report-check/SKILL.md b/.github/skills/security-report-check/SKILL.md index 2419a685b0dd8..5fadf0f34ca53 100644 --- a/.github/skills/security-report-check/SKILL.md +++ b/.github/skills/security-report-check/SKILL.md @@ -51,7 +51,8 @@ Similarly, running `tsc --build --clean` may delete files from disk; crafted `.t If an attacker has control of an input TS file, they can of course control the contents of the output JS file. Attacks that depend on control of the input file and execution of the output file are not considered compiler security issues, because the attacker already has control of the input file. -**File read sandboxing.** +### File read sandboxing + `tsc` will read files from paths specified in input files, and transitive references from there, including import paths and reference directives. An attacker in control of these files may therefore cause a *read* of any file path the `tsc` process has privileges to read, and `tsc` may reprint certain file contents in its output messages. In other words, for example, it is not generally safe to run `tsc` on untrusted code and print back the error message contents to an untrusted party, as this could expose local filesystem contents to the attacker.