Arachnid Forensic

10 · Security & Threat Model

← Workflows · Home · Next: Development →

What Arachnid Core defends against, what it explicitly does not, and why the second list is written down rather than glossed over.

For the operational disclosure a SOC needs to write an allow rule, see docs/SOC-ALLOWLISTING.md.

This page is about Arachnid Core. arachnid-sanitize destroys data by design and has its own threat surface, its own safety rails and its own allowlisting decision — see Secure Erasure and SOC-ALLOWLISTING.md §4a. Allowlisting Core does not imply allowlisting Sanitize, and for most sites it should not.


Contents


The adversary

Arachnid Core assumes an attacker who:

It does not assume an attacker who controls the responder’s kit, the signing key, or the out-of-band record of the key fingerprint. Those are the trust anchors; if they fall, nothing below holds.


What it defends against

Post-collection tampering

Anyone who modifies an artifact, edits a custody record, removes a record, or plants an unlogged file is detected by verify. This is the property the container exists to provide.

Tampering Detected by
Editing an artifact its recorded SHA-256 no longer matches
Truncating or padding one its recorded size no longer matches
Deleting an artifact file missing
Planting a file present on disk, absent from the log
Editing a custody record that line’s Ed25519 signature fails
Deleting or reordering records the prev hash chain breaks

Each of these has a test in crates/arachnid-evidence/src/lib.rs. Mechanism: The Evidence Container.

Verification is deliberately implemented independently of the collection path — it re-reads and re-hashes rather than sharing writer state — so a bug in collection cannot make a broken container verify clean.

A swapped acquisition tool

The memory acquisition binary is hash-pinned and verified before execution, so a replaced avml on a compromised host is caught before it runs rather than recorded after.

--memory-tool-sha256 is required by the argument parser, not merely recommended. There is no way to ask Arachnid to run an unverified acquisition tool.

Silent partial collection

Every collector that fails records why — in warnings, in the custody log, at the top of the report, and in exit code 4.

An empty result set is never allowed to look like a clean host.

Capture gaps

Kernel and interface drop counters are recorded, surfaced prominently in the report, noted in the custody log, and set exit code 4. A capture with drops has holes, and holes in evidence must be visible.

Its own detectability

Arachnid does not hide. It is designed so a SOC can allow it narrowly: no child processes but the one you name, no writes outside -o, no network, no persistence, read-only registry. The release build fails if the subcommand names are not visible to strings.

This is a security property, not a cosmetic one. A tool that hides from defenders gets treated as malware — and being quarantined mid-collection on the one host that matters is a real failure mode, not a hypothetical one.


What it does not defend against

These are limitations of live triage itself, not gaps to be patched. State them in your notes.

A compromised kernel lies

Every collector reads through OS APIs. A rootkit that hooks those APIs — a malicious LKM, an SSDT hook, a hypervisor-level implant — can hide processes, sockets and files from Arachnid as easily as from ps.

The countermeasure is memory acquisition and offline analysis, which is why collect supports acquiring an image. Correlate; do not trust live enumeration alone against a kernel-level adversary.

Signs worth escalating on: a kernel module with no on-disk file, a process whose image cannot be hashed while you are privileged, a socket with no owning PID when you are root.

Ephemeral-key containers prove integrity, not origin

Without --signing-key, a key is generated per run. Anyone who can rewrite the whole container can also swap the key and re-sign everything. verify then proves only that the container is self-consistent.

It proves origin only when the key fingerprint matches one recorded out-of-band.

For chain of custody that must survive challenge in a proceeding, issue each responder a persistent key and always pass --signing-key.

The fingerprint is printed at the end of every run precisely so it can be recorded. See Workflow 8.

Collection is not atomic

The host keeps running while collectors execute. A process can exit between the process-table read and the connection-table read; a file can be deleted between being listed and being hashed.

Timestamps in the custody log let you reconstruct the order; they cannot give you a consistent snapshot. Only a memory image can.

This is why both clocks exist: ts_utc for what you cite, mono_ns for ordering that survives a host whose wall clock moves mid-collection.

The operator’s privilege is the ceiling

Arachnid never escalates. It uses the token it was launched with, and never adjusts, impersonates, or retries a failed access with more rights.

Running as a normal user yields materially less evidence — unreadable /proc/<pid>/maps, sockets with no attributable owner, inaccessible HKLM values — and says so in warnings.

Anti-forensics that predates collection

A cleared utmp, a deleted unit file, a scheduled task removed before you arrived: already gone. Arachnid Core records what is present; it does not recover what was removed. That is Arachnid Recover’s job, against an acquired image — and what it recovers comes back labelled with how much of it can be trusted, because a deleted file’s blocks are free and may have been reused since.

The known specific case: Windows scheduled tasks are read from the on-disk System32\Tasks store, so a task registered only in the registry TaskCache with no matching file is missed. Documented in Collectors and on the function itself.

Encrypted traffic

Arachnid reads the plaintext TLS handshake for SNI and does not attempt to decrypt anything. Encrypted ClientHello yields no SNI. HTTP/2 and HTTP/3 inside TLS yield IPs and SNI only.

A triage tool that decrypted traffic would need keys it has no business holding.

The examined host observing the capture

Packet capture is not invisible. Expect AF_PACKET socket creation and SO_ATTACH_FILTER on Linux, or a handle to \Device\NPCAP\<iface> on Windows. An attacker with kernel visibility can see a capture starting.

--promiscuous is off by default specifically because enabling it changes the interface’s receive mode, which is an observable change to the host — but the capture itself is never fully hidden, and Arachnid does not pretend otherwise.


Non-goals

These are hard design constraints, enforced in review and in deny.toml. Arachnid Core contains no:

If a future feature would require any of the above, the design is out of scope and gets flagged rather than implemented.

arachnid-sanitize shares every one of these non-goals — no network, no scheduling, no persistence, no self-deletion, no log clearing — while inverting the read-only rule, and only for the device the operator names.

That is not a promise about intent; it is enforced by CI. See below.


Supply chain

Dependencies are few, audited in CI, and constrained by policy.

Banned outright

deny.toml denies, at the dependency level:

Crate Reason
reqwest, hyper Arachnid Core never makes outbound requests
openssl-sys no TLS client belongs in a triage binary
libloading no dynamic code loading in the shipped binary
dlopen same

libloading is permitted only as a build-time dependency of clang-sys (bindgen’s libclang probe) and pcap (its wpcap.dll build-script probe). Both run on the build host and contribute no code to the shipped binary. If either ever becomes a normal dependency, the check fails — which is the point.

On Windows, wpcap.dll is a normal import-library link (delay-loaded), not a runtime LoadLibrary of attacker-reachable code.

Sources

unknown-registry = "deny"
unknown-git      = "deny"
allow-git        = []       # no git dependencies

Every input is a versioned, checksummed crates.io release. wildcards = "deny" — no unpinned version requirements.

Advisories

cargo deny check and cargo audit both run in CI against the RustSec database. One documented exception:

RUSTSEC-2024-0436paste is archived-but-correct, reached via netstat2 → netlink-packet-*. It is a compile-time proc-macro contributing no code to the shipped binary, and no vulnerability is known against it. Reviewed 2026-08-27; the rationale and revisit criteria are in deny.toml, and .cargo/audit.toml is kept in sync so a bare cargo audit agrees with CI.

An exception with a review date is a decision. An exception without one is a hole.

Build integrity

Prefer allowlisting by code-signing certificate or GPG key over by hash, so patch releases do not require a new rule.


Hostile input

Everything Arachnid collects is attacker-controllable: process command lines, DNS names, HTTP headers, User-Agents, persistence values, file paths.

The rule is:

Store verbatim. Escape on output.

Anything downstream that renders this data must escape it too. If you build a dashboard on report.json, treat every string field as untrusted input. The JSON is faithful, not safe — and that is the correct trade.

Parsers are written defensively against the same principle:


Authorization

Arachnid Core is for authorized analysts on systems they have permission to examine.

The tool does not, and cannot, enforce authorization scope. That is a process control, not a software one. What it does provide is a record of what was done: the custody log holds the full invocation, the operator identity, and a timestamped entry for every artifact produced.

Operationally that means:


Reporting a security issue

If Arachnid Core does something not described in this wiki or in docs/SOC-ALLOWLISTING.md, that is a defect and we want the report.

Include:

Between them, those record every action the tool took.

For a vulnerability, describe the class of problem rather than publishing a working exploit path.


← Workflows · Home · Next: Development →