Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

WAL and last-record files created with 0666 permissions, forgeable CRC64 integrity

Open
#561 0 comments 0 reactions 0 assignees View on GitHub

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

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

medium security wal

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

  1. 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).
  2. wal/wal.go:34
    os.OpenFile creates the WAL file with the 0666 mode on first append/read.
  3. 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).
  4. wal/last_record.go:107–109
    Truncate() re-creates the last-record file with the same 0666 mode.
  5. 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

  1. 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from ava-labs/Simplex

All issues in ava-labs/Simplex

Similar issues

More Go issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.