rtk-ai / rtk-ai/rtk

Coverage disclosure for the external audit behind the recent issues — what was NOT checked, and the specific reason for each

Open
#3,399 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

invalid needs-info needs-triage priority:low question
Dominant language
Rust
Stars
81.1k
Forks
5.1k
Avg merge
4d 11h
Merged PRs (30d)
40

Description

Over the last day I filed a number of issues and advisories from an external audit of v0.44.2 (700bdde). Several of them carry a "not checked" note. This issue collects all of those in one place, with the reason for each, so the gaps are legible rather than scattered across a dozen threads.

The reason for posting this: an audit that reports only what it found invites the reading that everything else was examined and was fine. That is not true here. Below is what I could not examine, and why. "Not checked" means no evidence either way — not "clean".

Provenance: AI-assisted source audit, human-directed. The auditing environment was a single Windows 11 machine with Rust 1.97.1, Node 24, .NET 10 and Git. Nothing else in the list below was installed, for reasons given.

A. Not checked because the tool was not installed — and installing it would not have helped

For these, rtk's filter parses the tool's real output. I used fixtures and shims, which prove the parser's behaviour on the input I supplied but say nothing about what the tool actually emits today. Installing the binary alone would not have closed the gap, because each of these needs credentials, a cluster, a daemon, or a database that I do not have and should not have:

tool why the binary alone proves nothing
aws needs live credentials + a real account; output shape varies by service and CLI version
kubectl needs a cluster
docker needs a daemon and images
psql / mysql needs a running database
gcloud, az needs an authenticated cloud project
sops, vault, age needs real key material — I was not going to generate live secrets to test a filter
terraform, ansible needs real infrastructure state to produce representative output
mvn, gradle, sbt needs a JVM toolchain and real multi-module projects; fixture output was used instead
black, prettier, ruff, eslint not installed; their filters are source-read only
gh, glab, gt gh was installed, but exercising the filters needs live API responses from a repo with the right state (failing checks, truncated lists)

Concretely, this means: every claim I made about an aws, kubectl, psql, docker, terraform, ansible, or sops filter is a claim about rtk's parsing code, not about how that filter behaves against the real tool. Where I said a filter drops a field or mis-parses a format, I verified it in rtk's source and against a fixture I wrote. A maintainer with the real tool can confirm or refute in one run.

B. Not checked because I was on the wrong OS

The audit machine is Windows 11. Not examined:

  • #[cfg(unix)] code paths — including the file-permission hardening (set_owner_only is a no-op on non-unix), signal handling, SIGPIPE behaviour, process-group semantics, and orphan reparenting. Several findings I filed reason about Unix behaviour from source; none of it was observed.
  • macOS specifics — the Apple Silicon startup-overhead numbers in #1375 are someone else's; my own timings are Windows, where the bare process-spawn floor is ~35 ms, so absolute values are not comparable.
  • Linux release artifacts — the musl/gnu split, the .deb/.rpm packages, and the install script's behaviour were read, not run.
C. Not checked because it needs another vendor's product

rtk integrates with several agent harnesses by writing hook configs and emitting JSON they consume. I could not verify the receiving end for:

  • GitHub Copilot CLI — whether it honours permissionDecision as rtk supplies it. (Your own #3037 answered part of this; I have no independent view.)
  • Gemini CLI, Cursor, Cline/Roo, Windsurf, OpenCode, Droid, JetBrains Copilot plugin — the schemas in hook_cmd.rs are documented in comments and I read them, but I never ran any of these products. If a vendor changed their hook schema, I would not know.
  • Claude Code itself — I exercised rtk hook claude directly by piping JSON, which tests rtk's side. I did not run it inside a real Claude Code session.
D. Not checked because it lives outside the repository
  • Branch protection and required status checks. Issue #3394 argues two CI steps cannot fail. Whether those jobs are even required for a merge is a GitHub repository setting, not a file in the tree — I cannot see it. If they are not required, the finding is larger than I stated; if some other gate compensates, smaller.
  • The telemetry server. Retention, deletion, IP handling, and what the /erasure endpoint actually does are all server-side. Advisory GHSA-q584 reports what the client sends; I make no claim about what happens after.
  • crates.io / release-artifact provenance. I did not download and inspect your published binaries (including not running strings on them to look for a compiled-in token — that felt inappropriate for a report you had not yet triaged).
E. Not checked because I chose not to run it

Stated so it is not mistaken for an oversight:

  • rtk init and its uninstall paths — these write into the real home directory. I read the code and never executed it.
  • rtk cc-economics — it invokes npx --yes and reads real spend data.
  • rtk telemetry forget — it deletes the real local database and fires a network request. GHSA-q584 is therefore a code-property report, not an executed one.
  • Anything that would have required generating live credentials to make a realistic test case.
F. Read but not audited in depth

Large surfaces I opened enough to navigate, but did not review line by line:

  • src/hooks/init.rs (~280 KB) — grepped, not read in full.
  • src/discover/registry.rs (~155 KB) — the 178 rewrite rules were counted and the RegexSet path traced; the individual rules were not each validated.
  • src/filters/*.toml — 63 declarative filter definitions. At the time I filed the sops advisory I had opened exactly one of them.
  • src/openclaw/, src/cmds/php/, most of src/cmds/js/ and src/cmds/dotnet/ beyond the specific files cited in my reports.
  • The test suite: I ran it (2520 tests, all passing) but only examined tests adjacent to findings.
What I would ask

If any finding of mine matters to you, the fastest way to settle it is usually the one thing I could not do: run it against the real tool. Where that is the case I said so in the report. I would rather you close something as "works fine against real kubectl" than have it sit open on my say-so.

And if you would find it useful, I am happy to re-check anything on this list against a fixture you consider representative — a captured output file is enough for most of category A.


Per-report ledger: what is still unverified in each thing I filed

The categories above are the reasons. This is the mapping — for every post I made, what specifically remains unverified in it. Read this as: if you are triaging one of these, here is the part you should not take on my word.

Legend: ✅ RAN = I executed it and observed the result · ⚠️ PARTIAL = the mechanism was executed but one step was not · 📖 SOURCE = read from code only, never executed.

# what I filed status what remains unverified in it
#2281 go vet can report "No issues found" on a broken module 📖 SOURCE I never ran go vet against a module with a go.mod error. The claim is from go_cmd.rs:117,703,715 plus the f69ad6e commit. Category A (no Go toolchain configured for a broken-module fixture).
#2001 savings baseline, threshold contradiction, grep memory ⚠️ PARTIAL The memory/wall-clock numbers were measured. I did not reproduce @vpovarna's 41-command benchmark, so nothing I said explains their end-to-end token result — only the mechanism.
PR #2401 a 4th unguarded filter path; FilterMode::Buffered may be test-only ⚠️ PARTIAL The unwind-vs-abort proof was compiled and run. I did not build your branch. The claim that FilterMode::Buffered has no production constructor is a grep result — if I missed a constructor, that half is wrong.
PR #3295 3 open PRs for one bug; cargo precedent at 39a4d28 📖 SOURCE Neither PR was built or tested. This is a git log + diff-reading observation only.
#2954 the gain.rs panics look fixed; 2 sibling sites are not ⚠️ PARTIAL The two new panic sites were reproduced with verbatim extracts. I did not run rtk gain --history with a CJK/Cyrillic history, so "the original is fixed" is "the unsafe slice is gone from the code", not "I confirmed the crash no longer happens".
PR #3368 3 sibling structs have the same defect; 6 dead keys ⚠️ PARTIAL The deserialization failures were reproduced on a replica of your struct attributes (serde 1 + toml 0.8), not on your binary. The dead-key list is a grep.
PR #2581 strip_ansi cannot match \x1b[?25l; the PHP copy fails differently 📖 SOURCE I did not run either stripper against a live spinner. The CONTROL_RE claim in particular is read from its character range — worth confirming against the actual constant before acting on it.
PR #1693 24 rustdoc examples can never compile ✅ RAN cargo test --docerror: no library targets found. Little left unverified here.
#2317 verified inventory replacing the "(likely)" list 📖 SOURCE I did not run every filter. Each row is a code-path claim. The gradlew row is from an exhibited input, not a live Gradle run — Category A (no Android/Gradle setup).
#1375 the 178-regex COMPILED tax explains the 20 ms gap ⚠️ PARTIAL Measured on Windows, where process-spawn alone is ~35 ms. I have not profiled on Apple Silicon, so I cannot say what fraction of your 56 ms this is there — the deltas are meaningful, the absolutes are not comparable.
#3392 rtk grep 31× memory / 4.9× wall-clock ✅ RAN Measured on Windows only; Linux/macOS allocator behaviour may differ.
#3393 db never shrinks; gain slows on large history ✅ RAN Measured. The query-plan claims are from EXPLAIN QUERY PLAN on a synthetic 500k-row database, not your users' real distribution.
#3394 two CI steps cannot fail; no slicing lint; semgrep baseline ⚠️ PARTIAL The deny(warnings) clippy escalation was verified on a probe crate. Whether those jobs are required for a merge is a repository setting I cannot see — Category D. If they are not required, this is worse than I said; if another gate compensates, it is smaller.
#3395 psql parsed without -X, ~/.psqlrc changes the format 📖 SOURCE Entirely source-read. psql is not installed — Category A (needs a running database to produce representative output). Every failure mode I describe is predicted, not observed.
#3396 stale 0.28.2 / rtk 0.16 version checks ✅ RAN Read directly from the files; Cargo.toml says 0.44.2.
#3397 filtered clone no caller reads; triple-retained capture 📖 SOURCE Reachability traced by reading every call site. Not profiled — I did not measure the allocation cost, only argue it exists.
Reports sent through the private security channel

Those carry their own "Testing" section stating exactly what was and was not executed — the same discipline as above. I am not restating them here while they are in triage. In short: two were reproduced end-to-end on this machine, one had its mechanism reproduced but not its tool-specific step (the tool is not installed), and two are code-property reports I deliberately did not execute because running them would have fired a real network request or deleted real local data.

The honest summary

Of the 16 public posts above: 5 were executed and observed, 6 had part of the claim executed, and 5 are source-reading only. The five source-only ones are the ones I would most want you to check before acting — they are also, not coincidentally, the ones covering tools I could not install.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the per-report ledger in this issue and the cited entry points, including hook_cmd.rs, src/hooks/init.rs, src/discover/registry.rs, and the relevant filter definitions. Select a specific unverified claim and compare the source-reading evidence with a representative real-tool run or fixture. Done means the selected gap is confirmed or refuted and the result is recorded against the corresponding report.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
documentation, security
Issue type
Documentation
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.