ghalvera_

Security research lab // Madrid

Every check was green.
Nothing was being recorded.

Every security claim rests on a record — an audit log, a trace, a telemetry stream. Those records are assumed to be true. We cross boundaries on purpose so we know exactly what happened, then find out whether the evidence agrees.

evidence chain // live verified
records
0
head
broken at
none

01 // Open

What we are trying to find out

Questions first. Each states what would count as an answer, so it can be judged rather than admired — and retired when the evidence says no.

  1. Q-01 running

    Do npm packages that publish provenance actually rebuild?

    Provenance is supposed to make a build independently checkable. Reproducibility has been measured for npm generally, but not for the subset carrying attestations — the population where the attestation hands you the recipe.

    An answer is a rebuild rate over a stated sample, compared against an explicitly cited prior baseline, with every divergence classified by cause.

  2. Q-02 queued

    Does a container runtime name the right actor?

    A bare user namespace preserves the real host identity — we established that. Whether runc, crun, gVisor and Kata behave the same is undocumented, and they differ enormously in how they mediate syscalls.

    An answer is the same identity table across runtimes, with the exec chain shown. A runtime that loses attribution is the strongest outcome.

  3. Q-03 queued

    Can an actor forge the identity before crossing?

    Audit's login UID survives a namespace crossing, but this guest reports loginuid_immutable 0 unlocked. A process with CAP_AUDIT_CONTROL may be able to change it before crossing; that is the untested edge.

    An answer is one of forged-and-visible, forged-and-invisible, or prevented outright. A kernel that refuses is a real result and strengthens the previous finding.

  4. Q-04 queued

    Which subsystems report healthy while recording nothing?

    A default Fedora install runs the audit daemon, reports enabled and lossless, and records no syscalls at all. That cannot be the only one. Candidates: eBPF collectors dropping under load, journald rate limiting, netfilter logging, container runtime event streams.

    An answer is a survey stating, per subsystem, what it claims, what it records, and what an operator would see if it stopped.

02 // Thesis

We break in on purpose. Then we catch the log lying.

Exploitation research publishes the escape and moves on. Forensics studies logs from attacks nobody ran, and has to invent its ground truth. Running both halves means the ground truth is real — we know exactly what happened, because we did it. Which is the only way to prove a record wrong.

01

See

Did the instrument capture the event at all? The sharpest case is a subsystem that is configured, running, reporting healthy — and recording nothing. Every dashboard green, no evidence produced.

02

Attribute

Does the record name the right actor? Namespaces, sudo, container runtimes, delegation chains. The failure mode is the outermost process wearing the innermost one's name — and it is invisible unless you already know what really ran.

03

Retrieve

Can the record be recovered whole? A record that cannot be retrieved is a record that does not exist — and retrieval fails quietly far more often than it fails loudly. What the record missed tells us where to look next.

03 // Findings

Studies and findings, with their limits stated

Every study names one question, one substrate, and what it failed to establish. Nothing here targets a system we do not own.

refquestionrepositorystate
S-001 Security decision invariance Protocol and evidence-availability work asks whether an attribution remains defensible when a transient link is withheld. One Fedora 44 ARM64 probe found the mechanism credible; physical calibration is not authorized and no empirical finding is claimed. security-decision-invariance privateRead → active
R-001 Range — reproducible target environment A guest defined as code that starts from a known state, receives exactly one change, and reverses every modification on every exit path. A failed teardown marks the guest unknown rather than continuing quietly. ghalvera/range private built
R-002 ausearch reads stdin, not the audit log The canonical invocation returns “no matches” and exits 0; --input-logs returned 186 parsed matches while a raw grep found 192 keyed lines in the same file. Limit: audit 4.1.4, one guest, one kernel. ghalvera/range privateRead → solved
R-002-02 Fedora ships syscall auditing disabled while reporting healthy Fedora 44 Cloud loads -a task,never. Removing that one rule restored capture in two runs; adding audit=1 did not. Limit: one ARM64 cloud image; the documented task-filter mechanism was not independently isolated. ghalvera/range private solved
R-003-01 The real actor survives an unprivileged user namespace crossing auid=501 remained stable while the process saw itself as uid 0; the namespaced uid never appeared in evidence. Limit: bare unshare -Ur, one host, two runs; login UID tampering remains untested. ghalvera/range private held
R-004-01 npm provenance names the source, never the environment All 12 sampled attestations named repository, commit and workflow; none named runner image, Node or npm version. Limit: a deliberately biased convenience sample; no population or rebuild-rate claim. ghalvera/tools/provenance private solved
R-004-02 Provenance verifiability expires outside the attestation Build environment detail survived only in Actions logs: available in 5/5 testable rows under 88 days and absent in 4/4 over 150 days across seven publishers. Limit: the retention boundary itself was not measured. ghalvera/tools/provenance private solved
S-002 Container boundary under one misconfiguration Which isolation guarantees survive a specific named misconfiguration — and would standard telemetry have shown the crossing? The second half is the part nobody publishes. proposed
S-003 Fuzzing campaign provenance What can you ask across campaigns that nobody asks within one? Immutable inputs, recorded provenance, visible loss, longitudinal comparison. proposed

04 // Found

The tool said there was no evidence.
It was reading stdin.

ausearch -k <key> — the canonical documented invocation — returns “no matches” and exits 0. The same configured log yielded 186 parsed matches through --input-logs and 192 keyed raw lines through grep. The bare invocation is not reading that log; it is reading stdin, hitting EOF, and reporting an absence of matches rather than an absence of input.

invocationrecords
ausearch -k <key>0 — “no matches”, exit 0
ausearch -m SYSCALL0
aureport --summarytime range 1970 – 1970
ausearch --input-logs -k <key>186 parsed matches
grep for the key in the same raw log192 raw keyed lines
ausearch -if <log> -m SYSCALL771
aureport --input-logs08/15 – 08/17/2026

why it matters

No error. No warning. Exit status 0. Meanwhile auditctl -s reports enabled 1 and lost 0 — the subsystem genuinely is healthy, which corroborates the wrong conclusion.

An investigator concluding no execve was recorded, therefore no process ran would be wrong, with every available diagnostic agreeing. This is the difference between absence of evidence and absence of retrieval, and the tool does not distinguish them for you.

Scope: one Fedora 44 guest, kernel 6.19.10 aarch64, two runs. Nothing here is claimed for x86-64, other releases, or bare metal.

the mechanism

From man ausearch: “--input-logs — Use the log file location from auditd.conf as input”, and “can also take input from stdin”. Reading the configured log is opt-in.

Three hypotheses were eliminated first — the distribution's -a task,never rule, a missing audit=1, the arch filter — plus clock skew, time windows and rotation. The control that cracked it was the one that should have come first: does the tool find anything?

ausearch -m SYSCALL        0   not key-specific
aureport time range     1970   not ausearch-specific
with --input-logs        771   the log was always readable

05 // Software

Products and instruments, with their limits

Research can end in a finding, an instrument, or software useful beyond the experiment. Maturity is stated plainly; a clean report is never presented as proof of safety.

Products

alpha public · Apache-2.0

trace-npm

See what an npm lifecycle script actually did: files touched, child processes spawned, network endpoints contacted and suspicious credential paths read.

$ npx trace-npm report \
  --trace-file postinstall.strace

Does not: sandbox a package, judge intent, assign reputation, or prove a clean package is safe. Live capture currently requires Linux and strace.

Research infrastructure

research private

provenance

Extracts the rebuild recipe an npm SLSA attestation actually contains and records missing source, workflow and environment fields without silently filtering malformed packages.

$ provenance inspect package@version
source named       yes
environment named  no

Does not: rebuild the package, establish ecosystem rates, or recover expired build logs. It is scoped to the provenance questions that produced R-004-01 and R-004-02.

ledger

A tamper-evident append-only log. Every record commits to its predecessor, so editing, deleting or reordering anything in the middle of the chain invalidates everything after it. Appending to an already-broken ledger is refused — otherwise corruption gets buried under valid records and starts to look like history.

$ ledger append '{"event":"guest booted"}'
0	d25a985333997b97…
$ ledger verify
OK    3 records, head 6e42047d0860…

Does not: detect truncation from the end, or a wholesale rewrite by someone with write access. Both need an external anchor — a head hash published where the adversary cannot reach it. 19 tests, including observed proofs of each detection and each limit.

range

A scenario runner for owned guests. Stages a scenario, applies exactly one change, captures evidence, and reverses everything — on every exit path, including failure. Actions are recorded to a ledger on the host, not by the system under observation, so the record survives the thing it is watching.

$ range/scenario.sh scenarios/audit-visibility
run      range/runs/20260817T…-audit-visibility
head     a7f3c19b04e2…

Does not: sandbox the host, verify the guest image's provenance, or make any claim about systems it did not run on. A teardown that fails marks the guest state unknown and fails the run.

06 // Field notes

The lesson, downstream of the evidence

Field Notes explain mechanisms discovered in completed work. They name their source, reproduce every command they teach, and state what the lesson does not establish.