# Risk map — astral-sh/ruff

> Canonical page: https://codevetter.com/unpack/ruff/risk-map

# Risk map — astral-sh/ruff

Scanned commit c131cbad5a0f858ef2ba207e0260d76bb33069b1 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

The repository's own threat model treats project source and config as attacker-controlled and forbids analysis from executing that code. The sharp edges that do cross a process or network boundary are ty's uv subprocess, fix/format writes, cache files, stdio LSP, and the unauthenticated playground share API. Internally, the rule table in `codes.rs`, Salsa cancellation, and the unstable linter API are the maintenance blast radii.
- The CLI threat model states analysis must not execute user-supplied code; `--isolated` must ignore config files; reading files reached via imports, config extensions, or symlinks is expected; fixes, format, ignore insertion, and cache cleanup may change only the operation's selected targets; `ruff format --check` must not write source. — [agents/references/cli-threat-model.md#L15-L39](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/agents/references/cli-threat-model.md#L15-L39) [agents/references/threat-models.md#L1-L13](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/agents/references/threat-models.md#L1-L13)
- ty's uv integration is off unless `TY_UV` is `1`, `true` (`UseUv::On`), or `scripts` (`UseUv::Scripts`). When on, `Uv::execute` runs the `UV` env var or `PATH`'s `uv`. Script metadata uses `workspace metadata --sync --script`, which the threat model says may install dependencies. — [crates/ty_project/src/uv.rs#L33-L63](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty_project/src/uv.rs#L33-L63) [crates/ty_project/src/uv/command.rs#L43-L66](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty_project/src/uv/command.rs#L43-L66) [agents/references/cli-threat-model.md#L31-L34](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/agents/references/cli-threat-model.md#L31-L34)
- `--fix` and format `Write` mode replace file contents via `File::create` and a full write of the transformed source. A failed fix falls back to `lint_only` on the original. `--add-noqa` also rewrites files. These are the intentional mutation paths. — [crates/ruff/src/diagnostics.rs#L228-L336](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/diagnostics.rs#L228-L336) [crates/ruff/src/lib.rs#L345-L351](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/lib.rs#L345-L351) [crates/ruff/src/commands/format.rs#L48-L67](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/commands/format.rs#L48-L67)
- Cache files are written outside the source tree only in the sense that `.ruff_cache` (or `cache-dir`) sits in the project and is excluded from linting by default. Persistence is atomic rename, but a mismatched package root silently clears `package.files`, and unreadable cache files are replaced with an empty cache after a warning. — [crates/ruff/src/cache.rs#L100-L131](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/cache.rs#L100-L131) [crates/ruff/src/cache.rs#L157-L194](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/cache.rs#L157-L194) [crates/ruff_workspace/src/settings.rs#L132](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_workspace/src/settings.rs#L132)
- The playground share Worker stores the entire POST body in KV with a random UUID and no authentication, size check, or content-type check in `fetch`. GET returns the stored text to any caller who has the id. Production CORS is an allowlist, not an auth scheme. Dev mode sets `Access-Control-Allow-Origin: *`. — [playground/api/src/index.ts#L23-L38](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/playground/api/src/index.ts#L23-L38) [playground/api/src/index.ts#L57-L102](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/playground/api/src/index.ts#L57-L102)
- Both language servers read editor documents over stdio and trust the client connection. Ruff publishes diagnostics from in-memory snapshots (`snapshot.query()`), so a hostile document is linted with the server's filesystem rights. ty's server additionally requires a Unicode cwd and keeps an `OsSystem` fallback for files not in the index. — [crates/ruff_server/src/lib.rs#L51-L55](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_server/src/lib.rs#L51-L55) [crates/ruff_server/src/server/api/diagnostics.rs#L8-L21](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_server/src/server/api/diagnostics.rs#L8-L21) [crates/ty_server/src/lib.rs#L29-L54](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty_server/src/lib.rs#L29-L54)
- Python launcher risk is local binary lookup: `find_ruff_bin` returns the first `ruff` executable on a fixed list of script directories and `__main__` `execvp`s it. A planted binary earlier in that search list would run with the user's privileges. On Windows the launcher uses `subprocess.run` and maps `KeyboardInterrupt` to exit 2. — [python/ruff/_find_ruff.py#L11-L55](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/python/ruff/_find_ruff.py#L11-L55) [python/ruff/__main__.py#L9-L23](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/python/ruff/__main__.py#L9-L23)
- Lint panics are isolated per file with `catch_unwind` and reported as diagnostics, but `Cache::open` and the Windows color setup still use `unwrap`/`assert` on paths that are not panic-isolated (`SystemTime::UNIX_EPOCH.elapsed().unwrap()`, `set_virtual_terminal` assert). ty's check thread uses `salsa::Cancelled::catch` and drops stale revisions. — [crates/ruff/src/commands/check.rs#L193-L213](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/commands/check.rs#L193-L213) [crates/ruff/src/cache.rs#L144-L152](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/cache.rs#L144-L152) [crates/ruff/src/main.rs#L31-L33](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/main.rs#L31-L33) [crates/ty/src/lib.rs#L383-L412](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty/src/lib.rs#L383-L412)
- `codes.rs` `code_to_rule` is a single macro-expanded match from every rule code to a rule type. A new rule that is not added there is unreachable from `--select` and noqa codes. `Rule::from_code` searches `Linter::all_rules` by noqa suffix. — [crates/ruff_linter/src/codes.rs#L1-L7](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/codes.rs#L1-L7) [crates/ruff_linter/src/codes.rs#L237-L249](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/codes.rs#L237-L249) [crates/ruff_linter/src/registry.rs#L16-L25](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/registry.rs#L16-L25)
- ty one-shot checks `freeze` the database and then `std::mem::forget(db)` so destructors do not run. `system_mut` documents that it cancels other handles and can deadlock if the refcount is not 1. Watch mode, fix modes, and memory reports must not freeze. — [crates/ty/src/lib.rs#L187-L236](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty/src/lib.rs#L187-L236) [crates/ty_project/src/db.rs#L252-L260](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty_project/src/db.rs#L252-L260)
- The linter library is explicitly unstable. WASM, the CLI, and the language server all call into `check_path` / settings types, so a signature change in `ruff_linter` fans out across `crates/ruff`, `ruff_server`, and `ruff_wasm`. — [crates/ruff_linter/src/lib.rs#L1-L6](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/lib.rs#L1-L6) [crates/ruff_wasm/src/lib.rs#L15-L16](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_wasm/src/lib.rs#L15-L16) [crates/ruff/src/diagnostics.rs#L288-L301](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/diagnostics.rs#L288-L301)
- Docker build fetches rustup with `curl | sh` and compiles a musl binary. That is a release-supply-chain path, not a runtime path for users of the scratch image. cargo-dist comments that CI customizes cargo-dist install specifically to avoid `curl | sh` for the dist tool itself. — [Dockerfile#L19-L31](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/Dockerfile#L19-L31) [dist-workspace.toml#L6-L10](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/dist-workspace.toml#L6-L10)
- Debug Ruff builds warn when the cache is left on, because `--no-cache` is what developers expect while iterating. Shipping a debug binary to users would both warn and serve potentially stale-looking cache behavior relative to source edits. — [crates/ruff/src/lib.rs#L316-L321](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/lib.rs#L316-L321) [crates/ruff/src/commands/format.rs#L105-L113](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/commands/format.rs#L105-L113)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
