lacs-project / lacs-project/sysknife

audit export publishes request_hash, an unsalted hash over unredacted params, with no statement of its sensitivity

Open
#268 8 comments 0 reactions 0 assignees View on GitHub
bug help wanted medium
Dominant language
Rust
Stars
12
Forks
19
Avg merge
18h 57m
Merged PRs (30d)
116

Description

`request_hash` is a column of every signed chain row, and `sysknife audit export` (#260) now serialises it. The hash commits to the **unredacted** request:

```
crates/sysknife-daemon/src/dispatcher.rs:2001 let request_hash = compute_request_hash(action_name, params);
crates/sysknife-daemon/src/dispatcher.rs:2041 let redacted_params = redact_params(action_name, params);
```

Redaction runs 40 lines after the hash, and `compute_request_hash` is one unsalted round:

```rust
hasher.update(action_name.as_bytes());
hasher.update(b"\x00");
hasher.update(canonical.as_bytes());
```

## Why it matters

For `ConfigureWifi` the credential params are `password` and `ssid`. The SSID is broadcast, so the only unknown in the preimage is the passphrase, and a single unsalted SHA-256 is the cheapest thing a GPU cracks. The daemon keeps the database 0600 inside a 0700 directory precisely so this content does not travel; an export moves it across that boundary by design, into a SIEM, a ticket, or an auditor's laptop.

High-entropy credentials such as `ProAttach` tokens are unaffected. The problem is the low-entropy human-chosen ones.

The column cannot simply be dropped: `request_hash` is part of `ChainContent::canonical_bytes` (`crates/sysknife-daemon/src/audit_chain.rs:508`), so an offline verifier needs it to rebuild the signed bytes.

## Scope

Two parts, and the first is the one that matters today:

1. Say plainly in `docs/cli.md` and `docs/the-audit-chain.md` that an export inherits the database's confidentiality class and is not a redacted artifact. The docs currently enumerate what export omits (`argv`, `outcome`, a separate `signature`) and say nothing about what it carries.
2. Consider replacing the bare hash with an HMAC keyed by the audit key. That keeps the binding an offline verifier needs while removing the offline-crackable commitment, at the cost of a `chain_version` bump and a verifier that has the key.

## Tests first

For part 1 the check is the claim guard: the export section has to state the confidentiality class. For part 2, a round-trip test that an HMAC-bound row still verifies, plus a migration test across `chain_version`.

## Difficulty

`medium` for the documentation half alone; `hard` if the HMAC change is taken, because it touches the signed encoding.

## Getting started

[CONTRIBUTING.md](https://github.com/lacs-project/sysknife/blob/main/CONTRIBUTING.md) has the build and test commands, and [docs/developer-guide.md](https://github.com/lacs-project/sysknife/blob/main/docs/developer-guide.md) covers the setup steps and how to reproduce each required check locally. No CLA and no copyright waiver. The project is MIT.

Contributor guide

Open the contributing guide

Research direction

Start with the export sections in docs/cli.md and docs/the-audit-chain.md, then read compute_request_hash and ChainContent::canonical_bytes in crates/sysknife-daemon/src/dispatcher.rs and crates/sysknife-daemon/src/audit_chain.rs. For the documentation scope, done means the export confidentiality claim is explicit; if the HMAC scope is taken, add round-trip and chain_version migration coverage showing verification still works.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cryptography, documentation, security
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.