WAL and last-record files created with 0666 permissions, forgeable CRC64 integrity
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 72/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- go
- Domain
- distributed-systems, security
Research direction
Read wal/wal.go and wal/last_record.go to trace how the WAL and last-record files are created and recreated. Run the WAL package tests, then verify under a zero umask that newly created consensus-state files grant no group or other access; done means both creation paths meet that permission criterion.
Written by the indexing model from the issue text.
Description
Details
Every file the WAL package creates — the append-only consensus log (wal.go) and the last-record crash-recovery file (last_record.go) — is opened with mode 0666. The effective permissions are 0666 masked by the process umask: under the common 022 umask the files are world-readable; under 002 they are group-writable; under a 0 umask (not unusual for daemons/containers that set it explicitly) they are world-writable.
These files are the node's durable consensus safety state: signed votes, notarizations, finalizations, and block records that are replayed verbatim into the consensus engine at startup (Epoch.restoreFromWal), and the last-record file that overrides the replayed state. The only integrity mechanism on the stored records is a CRC64/ECMA checksum, which is a public, linear, non-cryptographic function — any party able to write the file can recompute valid checksums for arbitrary record bytes.
Concrete exploit: on a multi-user host (or a container/host where another compromised low-privilege service shares the filesystem) with a permissive umask, a local unprivileged user opens the WAL file, replaces or appends records (e.g., deletes the record showing the node voted for block B in round r, or injects a fabricated record), recomputes the CRC64 framing, and waits for the node to restart. Replay accepts the forged log wholesale — record framing and CRC both validate — so the attacker controls the node's remembered consensus state, e.g. inducing it to re-vote (equivocate) or to resume from attacker-chosen rounds. Even with the default 022 umask, the world-readable mode discloses the node's full vote/notarization history to any local account.
Since the files carry security-critical state, they should be created 0600 (or the package should accept a caller-specified restrictive mode) rather than delegating protection entirely to the deployment's umask.
Evidence
- wal/wal.go:12–14
WalPermissions is 0666: the consensus WAL file is requested world-readable and world-writable; the effective mode is only reduced by the process umask (commonly 022, still leaving the file world-readable; umask 002/000 leaves it group/world-writable). - wal/wal.go:34
os.OpenFile creates the WAL file with the 0666 mode on first append/read. - wal/last_record.go:75
The last-record side file — the crash-recovery anchor that overrides WAL state at startup — is also created with WalPermissions (0666). - wal/last_record.go:107–109
Truncate() re-creates the last-record file with the same 0666 mode. - wal/record.go:26–34
Record integrity is protected only by CRC64/ECMA, which is non-cryptographic and computable by anyone; a local user with write access can rewrite or inject records that pass all replay validation.
Impact
Confidentiality LOW: WAL contents (votes, blocks) are largely public consensus data, so local read exposure is limited. Integrity HIGH in the writable-umask case: full forgery of replayed consensus state, since CRC64 provides no protection against deliberate modification. Availability LOW: a local writer can also corrupt the log, triggering truncation/crash paths.
Reproduction steps
- Requires a local account (or co-resident compromised service) on the node's host — PR LOW, AV LOCAL. Read access works under the default 022 umask; write/tamper access additionally requires the daemon to run with a permissive umask (002/000) and a restart of the node to replay the forged log — deployment conditions, so AT PRESENT. No user interaction; no defenses to defeat (CRC64 is trivially forgeable).
Recommended fix
Security-critical WAL and last-record files are created with permissive 0666 mode, relying on the deployment umask; combined with the forgeable CRC64 framing, any principal with write access can fabricate valid consensus replay state. Fix criteria: Files holding consensus state must be created with owner-only permissions (0600) or an explicit caller-provided restrictive mode, independent of umask. Verified by creating a WAL under a 0 umask and asserting the resulting file mode grants no group/other access.
Severity: MEDIUM
Status: Open
Category: Incorrect permissions
CWE: CWE-276
Repository: ava-labs/Simplex
Branch: main
Date created: 2026-08-21
- Dominant language
- Go
- Stars
- 22
- Forks
- 4
- Avg merge
- 3d 9h
- Merged PRs (30d)
- 16
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from ava-labs/Simplex
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 45/100
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 40/100
Maintainers usually reply within 1 day
-
Verification accepts aux info appends after the history is sufficient, changing the approval digestOpen
Difficulty 3/5 1-2 days Newbie friendliness 74/100
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
Maintainers usually reply within 1 day
All issues in ava-labs/Simplex
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
praetorian-inc/augustus#334 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
TestTOMLBigFileParsesInLinearTime: a 1s wall-clock bound on a 3 MB parse fails under load (1.27s)Open
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
peasant-labs/village#293 ·
Maintainers usually reply within 1 day