Skip to content

RFC: Rustc lint plugin for ambient authority detection #43

@bordumb

Description

@bordumb

Problem

capsec currently detects ambient authority via AST-level pattern matching (cargo capsec audit). This misses cases where type information is needed — specifically, it cannot check whether a function calling std::fs::read() has a Has<FsRead> bound that makes the call authorized.

The goal: a lint that flags std::fs/std::net/std::env/std::process calls in functions that don't have Has<P> bounds, producing clippy-quality diagnostics with fix suggestions.

Desired UX

error: ambient authority: `std::fs::read` called without capability token
  --> src/data.rs:12:5
   |
12 |     std::fs::read(path)
   |     ^^^^^^^^^^^^^^^^^^^ this performs filesystem I/O
   |
   = help: add a capability parameter: `cap: &impl Has<FsRead>`
   = note: `#[deny(capsec::ambient_authority)]` on by default

Three options

Option A: Raw rustc_private lint plugin (nightly only)

Write a custom lint pass using rustc_private internals — the same approach clippy uses internally.

Pros:

  • Full HIR access — can inspect function signatures for Has<P> bounds
  • Can provide rich fix suggestions (#[rustfix]-compatible)
  • Can resolve types, check trait bounds, follow impl blocks
  • Maximum diagnostic quality

Cons:

  • Requires nightly Rustrustc_private is unstable
  • Breaks across Rust versions — internal APIs change without warning
  • Ongoing maintenance burden: must track rustc releases
  • Users must run via a custom driver binary (like cargo-clippy itself)

Effort: High initial, high ongoing maintenance

Option B: dylint framework (nightly, but managed)

Use dylint (Trail of Bits) — a framework for writing and distributing third-party rustc lints.

Pros:

  • Same HIR access as Option A (full type information)
  • dylint handles toolchain management and lint distribution
  • Lints are distributed as dynamic libraries — users install via cargo install cargo-dylint
  • Active maintainer (Trail of Bits), used by production projects
  • Can produce the same rich diagnostics as Option A

Cons:

  • Still requires nightly for rustc_private under the hood
  • Adds a dependency on the dylint ecosystem
  • Less control over the driver than a fully custom approach
  • dylint's own stability depends on Trail of Bits continuing to maintain it

Effort: Medium initial (dylint handles boilerplate), medium ongoing

Option C: clippy.toml + cargo capsec audit (stable Rust)

Use clippy's built-in disallowed-methods configuration to flag raw std::fs/std::net calls, combined with cargo capsec audit for deeper analysis.

Pros:

  • Works on stable Rust — no nightly required
  • Zero new code — clippy already supports disallowed-methods and disallowed-types
  • Users add a clippy.toml to their project (capsec could generate it)
  • Integrates with existing CI pipelines that already run cargo clippy

Cons:

  • No type information — cannot check for Has<P> bounds
  • Can only say "this method is disallowed" — no smart suggestions
  • Cannot distinguish authorized calls (function has Has<FsRead>) from unauthorized calls
  • Essentially a blocklist, not an authority analysis
  • The ambient-authority crate already documents this exact approach

Effort: Low initial, low ongoing

Recommendation

Option B (dylint) as the primary path, with Option C shipped immediately as a stable-Rust stopgap.

  • Ship a capsec clippy-config command that generates a clippy.toml with all ambient authority methods disallowed (Option C — available today, stable Rust)
  • Build a dylint lint crate (capsec-lint) that uses HIR to check for Has<P> bounds on functions calling ambient authority APIs (Option B — nightly, but production-quality diagnostics)
  • The dylint lint becomes the recommended path for teams that can use nightly; the clippy.toml approach serves teams that require stable

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions