| Version | Status |
|---|---|
| 0.8.x | Current — supported with security fixes |
| 0.7.x | Security fixes only while 0.8.x is the current series |
| < 0.7 | Not supported |
Do NOT open a public issue for security vulnerabilities.
To report a vulnerability, use one of these private channels:
- Email:
security@turbolang.dev - GitHub: Private vulnerability reporting
Please include:
- A clear description of the issue and its impact
- A minimal reproducer (a
.tbsource file is ideal) - The affected version (
turbolang --version) - Your assessment of severity, if you have one
- Acknowledgment: within 48 hours of receipt
- Critical fixes: target 7 days from acknowledgment
- Non-critical fixes: rolled into the next scheduled release
You will be kept informed of progress and credited (unless you request anonymity) once a fix ships.
In scope:
- The Turbo compiler (
turbo-cli,turbo-parser,turbo-sema,turbo-codegen-cranelift) - The C runtime (
turbo/crates/turbo-codegen-cranelift/runtime/turbo_rt.c) - The LSP server (
turbo-lsp) - The install script and Homebrew formula
- Any feature documented as stable in
README.mdordocs/
Out of scope:
- Experimental features explicitly flagged in
CHANGELOG.mdas unstable or experimental (currently: the WASM target and the LLVM backend). Agent/tool language primitives are not shipped — and are not planned for the core — so they are out of scope by omission, not by experiment - Crashes triggered only by
@unsafecode or raw pointer arithmetic — by design these bypass safety checks - Issues in third-party dependencies (please report upstream)
turbolang run compiles source code and executes it in-process with
full OS permissions. There is no sandboxing, no capability restriction,
and no isolation between the Turbo program and the host system.
Treat .tb files like executables. Do not run untrusted .tb
source files. A malicious .tb file can read, write, or delete any
file accessible to the user, make network requests, and execute
arbitrary commands (via the exec built-in).
The playground starts a local HTTP server on localhost with CSRF
protection (origin checking) and random session tokens (128-bit OS
randomness). Source files are written via exclusive-create temp files
to prevent TOCTOU races.
The playground is designed for single-user, local development. It is not designed for multi-tenant deployment. Do not expose the playground to untrusted networks.
The built-in HTTP server (http_server, route, http_listen) is
development-grade:
http_server(port)binds to127.0.0.1(localhost only)http_server_public(port)binds to0.0.0.0(all interfaces)- No TLS termination
- Request headers are capped at 16 KiB
- Request bodies are capped at 32 MiB via
Content-Lengthvalidation - Connection cap with 503 backpressure (tuned for development loads)
- Invalid server IDs are rejected
For production deployment, run behind a reverse proxy (nginx, Caddy, or similar) that provides TLS termination, rate limiting, request filtering, and authentication.
Binaries produced by turbolang build are native executables. They
inherit OS-level permissions of the user who runs them. Turbo provides
no built-in sandboxing, capability model, or privilege restriction.
AOT linker flags are allowlisted (alphanumeric + _.+- only) to
prevent a dependency from smuggling malicious flags through the build.
The @unsafe extern "C" block allows calling arbitrary C functions.
These calls bypass all of Turbo's safety checks. A C function accessed
via FFI can corrupt memory, dereference arbitrary pointers, or perform
any operation the C ABI permits.
Within @unsafe blocks, the deref and store builtins allow
reading from and writing to arbitrary memory addresses.
read_file, write_file, try_read_file, and try_write_file
operate on any path the OS user has access to. There is no path
sanitization, no chroot, and no allowlist of accessible directories.
As of v0.8.0, exec and shell_exec reject commands containing shell
metacharacters (;, |, &, $, backticks, parentheses, <, >,
newlines, backslashes). Commands are tokenized on whitespace and
executed directly via execvp with a 64-argument cap -- no shell is
involved.
This prevents shell injection attacks (e.g., exec("echo hi; rm -rf /")
is rejected). However, the underlying command still runs with the full
OS permissions of the Turbo process.
The following are documented limitations rather than vulnerabilities;
fixing them is tracked in CHANGELOG.md and TODO.md:
- HTTP server primitives are development-grade. See Security Model section 3 above for details. Always put a reverse proxy (nginx, Caddy) in front of a public deployment.
- JIT string arena is not individually freed. The runtime uses a thread-local string arena that is freed after each JIT execution. Long-running AOT servers should be monitored for memory usage. Proper ARC-based string deallocation is planned for a future release.
- Compiled binaries run with full system privileges. Turbo has no
capability/sandbox model. Treat compiled
.tbprograms the same way you would any compiled C program.
Every release tarball is published alongside a checksums.txt file
listing SHA-256 hashes for each platform artifact. Stable releases also
ship a detached GPG signature for that manifest (checksums.txt.sig).
The manifest is signed by the official Turbo release key, published at:
- Release key URL:
https://turbolang.dev/keys/release.asc
The release automation that builds, signs, and publishes those artifacts is pinned to immutable GitHub Action SHAs in:
.github/workflows/ci.yml.github/workflows/release.yml.github/workflows/nightly.yml
This reduces supply-chain drift in CI itself: action upgrades are now explicit code changes instead of silent tag movement.
To verify a download manually:
# 1. Import the public release key (one-time setup).
curl -sSL https://turbolang.dev/keys/release.asc | gpg --import
# 2. Verify the manifest signature.
gpg --verify checksums.txt.sig checksums.txt
# Expect: "Good signature from Turbo Language Releases <release@turbolang.dev>"
# 3. Verify the tarball you downloaded matches the signed manifest.
sha256sum --check --ignore-missing checksums.txtIf gpg --verify reports anything other than Good signature, stop
and report it to security@turbolang.dev — do not install the binary.
The release private key lives only in GitHub Actions secrets
(RELEASE_GPG_PRIVATE_KEY + RELEASE_GPG_PASSPHRASE) and is used by
.github/workflows/release.yml. If the key is rotated, the new public
key replaces the file at https://turbolang.dev/keys/release.asc and a
release advisory is published to announce the rotation.
distribution/install.sh --verify now performs the same signed-manifest
flow automatically:
- Download the requested tarball,
checksums.txt, andchecksums.txt.sigfrom the GitHub release. - Download the release public key from
https://turbolang.dev/keys/release.ascinto a temporary GnuPG home. - Verify that
checksums.txt.sigmatcheschecksums.txt. - Verify that the tarball hash matches the signed manifest entry.
This is materially stronger than checksum-only verification because a modified tarball now also needs a forged manifest signature.
The convenience installer still has one unavoidable bootstrap
assumption: on first use it trusts HTTPS/DNS for turbolang.dev when it
retrieves the public release key. That is better than pulling the key
from the same GitHub release channel as the tarball, but it is still a
network trust dependency.
If you want the strongest assurance available today:
- Import the release key yourself ahead of time from a channel you trust.
- Run the manual
gpg --verifyflow above before extracting the tarball. - Prefer vendoring the release key in internal build/install systems instead of fetching it at install time.
We follow coordinated disclosure. Once a fix is released, we publish a brief advisory describing the issue, affected versions, the fix, and credit to the reporter (unless anonymity was requested).