Skip to content

test(security): the token-squat guard asserts nothing under root and prints ok — CI containers commonly run as root #355

Description

@MichaelTaylor3d

Task

foreign_owned_token_file_is_regenerated_not_trusted asserts NOTHING when run as root, and prints
ok.
crates/dig-node-service/src/control.rs:4329.

Every assertion sits inside if !running_as_root { … }. Under root the test creates the fixture, calls
load_or_create_token_at, checks nothing, cleans up, and reports success.

Why this one matters more than an ordinary skipped test

It guards a token-squat attack, in its own words:

a pre-existing control-token file that is NOT owned by a trusted principal … MUST be DELETED and
REGENERATED — never returned — so a planted/squatted token can never become the trusted one (which
would hand an attacker full local node control)
.

And CI containers commonly run as root. So this may have been reporting ok without ever exercising
the guard — on the one test standing between a planted token and full local node control. Determine
whether the CI leg that runs it is root
; if it is, this guard has never fired and its ok is
meaningless.

A silently-skipping test is worse than a missing one: a missing test is visible in coverage and in a
reviewer's head, while this one reads as a passing security guard.

The fix, which the sibling crate already demonstrates

Assert the complementary observable in the root branch rather than skipping. dig-keystore hit exactly
this pattern and fixed it that way (PR #17) — under root, mode is legitimately not the discriminator,
but something is still true and assertable.

Here the root branch should assert what root-owned actually implies: that a root-owned file IS
legitimately trusted and is therefore returned as-is
— the stated reason for the carve-out. That turns
the branch into a real second case rather than a hole, and it would catch a regression that started
regenerating trusted tokens.

Do not simply #[ignore] it under root. An ignored test is at least honest, but it leaves the root
path — the one CI actually takes — unguarded.

Scope

crates/dig-node-service/src/control.rs. dig-node has live lanes (a #3128 producer lane and a
#2790 NC-12 lane) — work in your own worktree off origin/main, one cargo process at a time, never
the shared checkout.

Grep for the same shape while you are here. Any if !running_as_root { …asserts… },
if uid != 0 { … }, or silent early-return inside a #[cfg(unix)] security test has this defect.

Evidence

  • Prove the negative first: run the test as root with the guard deliberately broken (return the
    planted token) and show it still passes. That is the defect, and it is what the fix must change.
  • Then show the fixed test failing under root against that same broken guard.
  • Read passed-counts, never ok — and note this ticket is precisely a case where ok meant nothing.
  • Any mutation asserts its patch applied; parse the test result: line, never stderr.

Provenance

The pattern was identified by the dig-keystore lane on eco#1502, which found it in its own suite and
suggested an ecosystem grep. That grep found this instance. The dig-keystore occurrence is already
fixed in its PR #17; this one is not.

Release hazard: dig-node's cron cuts a stable tag at midnight UTC unattended, so main reaches
real users without a human. The merge gate is the last line of defence.

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