Hearth is money. A consensus bug is not a defect report, it is a loss of funds, so this policy is written to be usable rather than decorative.
Do not open a public issue, pull request or discussion for a security problem.
Report privately through GitHub's private vulnerability reporting on this repository: Security → Advisories → Report a vulnerability (https://github.com/cloudsforge-online/hearth/security/advisories/new). This is the only monitored intake channel and it is end-to-end private to the maintainers.
Please include:
- what the issue is and what an attacker gains,
- how to reproduce it — a proof of concept, a failing test, or a transaction or block that triggers it,
- the affected component (
node/,web/,contracts/,rust/hearthd/) and the commit hash or published version, - whether you believe it is already being exploited.
A note on contact channels. There is currently no monitored security@
mailbox and no published PGP key. Both are open gaps, tracked in
docs/listing-checklist.md §5. Until they exist,
GitHub private reporting is the route that actually reaches a human, and we would
rather say that than publish an address nobody reads.
| Acknowledgement | within 72 hours |
| Initial assessment (severity, whether we can reproduce) | within 7 days |
| Status updates while a fix is in progress | at least every 14 days |
| Coordinated disclosure window | 90 days from acknowledgement, or sooner once a fix ships and is adopted |
If we cannot reproduce an issue we will say so and tell you what we tried, rather than closing silently. If we disagree that something is a vulnerability we will say that too, with reasoning, and you remain free to publish.
Credit is given in the advisory unless you ask us not to.
This is a small project. These windows are what we can actually meet, not what sounds impressive.
In scope
node/src/— consensus, validation, fork choice, reorg, the emission and anti-inflation rules, the mempool, P2P, and the REST/JSON-RPC surface.node/src/crypto/,node/src/state/,node/src/evm/— the EVM implementation. Any divergence from Ethereum semantics is in scope, whether or not it is currently exploitable: a contract that behaves differently here than where it was audited is the failure mode this codebase most needs reported.node/src/jsonrpc/— theeth_*surface, including anything that would make a client read a wrong value as a correct one (the QUANTITY/DATA distinction above all).node/src/pow.js,node/src/mining.jsand the template/submit protocol.web/assets/wallet/— the current secp256k1 browser wallet: key generation, PBKDF2/AES-GCM sealing at rest, the signing path, and anything that could expose a private key. Any divergence betweenweb/assets/wallet/{secp256k1,rlp,transaction}.jsand theirnode/srcoriginals is in scope, because a wallet that signs slightly differently from the node does not bounce — it pays the wrong person.web/assets/mining/— the browser miner, including any divergence from the node's Homefire digest.node/src/cli/andnode/bin/hearth.js— the terminal tool, particularly the keystore.contracts/src/— the AMM sources, even though nothing is deployed.
The retired pre-EVM modules — web/assets/wallet-core.js,
web/assets/keystore.js and web/assets/vendor/noble-ed25519.js — have been
deleted. They were imported by no page and survived only because a test still
exercised them; there is no longer any Ed25519 key handling in web/, and a
report about it is a report about code that is not shipped.
Out of scope
rust/hearthd/— a self-check binary and a benchmark. It has no block type, no chain, no fork choice and no P2P server, and two of its modules are known to diverge from consensus (seeMAP.md§3.3). It is documented as not being a second implementation. Findings are welcome but are not treated as consensus issues.proto/— teaching scripts, not imported by the node.web/pay-demo.html— a mockup that settles nothing on a timer and says so on the control.site/— the marketing site, except for anything that could compromise a visitor.- Missing hardening on the node's HTTP interface. The RPC has no
authentication, no API key and no rate limiting beyond a request-body cap, and
CORS is
*. This is documented, deliberate for a node intended to sit behind a proxy, and not a finding. Reports that it should be exposed safely to the internet will be closed as "do not expose it". - Denial of service requiring more resources than the attack yields, and volumetric attacks generally.
- Anything requiring physical access to a user's device.
Especially wanted
- Anything that mints EMBER outside the subsidy schedule, spends an output twice, or makes two honest nodes disagree about the same block.
- Any state root, gas cost or opcode behaviour that differs from Ethereum's under Shanghai semantics — ideally as a failing conformance vector.
- Anything that extracts a private key from the browser wallet or the node's keystore.
These are documented, deliberate, and tracked. A report restating one of them without new impact will be closed with a pointer here.
- Homefire is not a non-outsourceable puzzle. The seed binds only the
coinbase public key (
node/src/pow.js:45-47), so a pool operator can distribute work and sign blocks itself. This is an open consensus decision recorded atnode/src/pow.js:8-15and inWHITEPAPER.md§2.3. - Consensus parameters in this tree are dev-tuned — a 64 KiB Homefire pad,
256 walk steps, coinbase maturity 10 (
node/src/params.js:51-52,:95). They must be raised before mainnet and are tracked indocs/listing-checklist.md§7. - Reorgs have no depth limit. Fork choice is heaviest-cumulative-work with no checkpointing and no finality gadget, by design.
- No RPC authentication or rate limiting — see "Out of scope" above.
- Pre-EIP-155 transactions are accepted on the account-model chain, which
makes an unprotected transaction cross-chain replayable. This is deliberate and
is the same trade Ethereum makes; the reasoning is in
docs/evm-spec.md§3. PREVRANDAOis miner-influenceable. It returns the parent block's Homefire digest (node/src/evm/interpreter.js:211-214), and a miner who dislikes an outcome can discard the block and grind another. Contracts must not use it as a randomness source for anything an adversarial miner would profit from biasing.- Precompiles
0x06–0x09fail hard where0x01–0x05fail soft. Both conventions are consensus and they are opposites;0x01–0x05answer a malformed input with empty output and a successful call, while0x06–0x09fail the call and burn every drop of forwarded gas. All nine are implemented, and the interpreter retains the machinery to fail a warmed-but-unimplemented address because a call to a codeless address succeeds and returns empty (docs/decisions.md§1.3). A report that "the precompile reverted on bad input" is this, working. BASEFEEpushes zero. v1 has no fee market; the opcode exists only because Shanghai includes EIP-3198.- The browser wallet has no recovery — one key per browser, no seed phrase, no HD derivation.
- A crafted block still costs about 13x an ordinary one.
StateDBused to re-root both tries on every mutation — 443 MB and 65 s for one 30M-gas transaction against a 15-second block time (docs/robustness-review.md§1). Hashing is deferred now and the same transaction measures 5.2 s and 9.2 MiB, gated bynode/test/bench/block-execution.js. It is inside the block interval rather than four times it, which is a bound and not a comfortable one; the storage root is still materialised per write. - The proof of work is 64 KiB and not meaningfully memory-hard. The 2 GiB
the documents used to promise measures at 185.7 s per evaluation and a
validator pays one per block received, so the parameter is bounded by
verification (
docs/pow-parameters.md).params.jsrefuses to start above 4 MiB. Closing this needs an amortised dataset. RLP.decodehas no nesting cap. Roughly 7–12 KB of nested input — insideMAX_TX_BYTES— exhausts the JS stack with an untypedRangeError, and the threshold moves with remaining stack, so the same bytes can decode from one call site and throw from another (docs/robustness-review.md§4,node/test/fuzz/finding 1).transaction.validate()catches it and reportsRLP_ERROR, so it is latent. A reachable path that turns this into a consensus disagreement is very much wanted.isNormalized(tx)is not a complete test. It checksnonce,dataandto(node/src/chain/transaction.js:281-285); the remaining fields are read in whatever representation the caller left them in. A decimal-stringvalueon an otherwise-normalised draft yields a differentsigningHashthan the same draft normalised. Nothing on the node's own path reaches it —decode()normalises — so it is a wallet/caller-facing footgun, and reports that reach it through the node are in scope.- Three findings are live against a running
hearthdtoday — a 39-byte message that buys a full copy of the UTXO set,txgossip with no verification budget, and a self-fed side branch stored and relayed forever (docs/robustness-review.md§2, §3, §5). Documented and not yet fixed; re-reporting them adds nothing, but a cheaper variant does. - The browser miner and the node currently disagree about the coinbase key.
The miner signs secp256k1;
GET /mining/templatestill requires an 88-hex Ed25519 SPKI DER key (node/src/rpc.js:130-134) andnode/src/block.js:45still verifies with Ed25519. Phase 5 owns the node half. This is a known, documented transition state (MAP.md§9.2), not a vulnerability.
Pre-mainnet. Nothing here has been independently audited, and no mainnet exists.
The account-model EVM chain is under construction. What is built and gated on
published reference vectors: the primitives, the Merkle Patricia Trie and
StateDB, the interpreter (609/609 VMTests), transactions/receipts/bloom
(188/188 TransactionTests), the state transition (20,077/20,077
GeneralStateTests), all nine precompiles,
and the eth_* JSON-RPC surface. Uniswap V2 deploys and swaps on it
(node/test/dex.js).
What is not built is a public network. Blocks are produced, validated and
reorged — two real nodes partition and converge in node/test/evm-p2p-fork.js,
and three run under docker-compose.testnet.yml — but every port binds
127.0.0.1, no genesis outlives the process that mined it, and there is no
mainnet. The class of bug that only appears when state is carried across blocks,
reorged or persisted has had a few thousand blocks to show itself, not a few
million, and nothing here has ever run under adversarial load or at production
proof-of-work parameters (docs/pow-parameters.md).
docs/evm-spec.md §8 tracks the phases,
docs/decisions.md records why the non-obvious choices were
made, and MAP.md is the verified inventory.
Two internal reviews exist, and neither is an audit or may be cited as one.
docs/security-review.md covers the UTXO-era code
and its findings are implemented. docs/robustness-review.md
is a measured resource-bounds review of the EVM, state and chain layers; its
findings are recorded and not yet fixed, and finding 1 is why nothing produces
an account-model block. The intended audit scope is in
docs/listing-checklist.md §4.
Do not put value on this network. There is nothing of value on it, and until there is a mainnet with demonstrated hashrate, an independent audit, and the parameter changes in the checklist, there should not be.
There is no funded bug bounty today. A bounty for consensus, cryptographic and fund-loss findings is intended, funded from the Commons treasury — which currently has no implemented spend mechanism, so this is a statement of intent and not a promise of payment. It is listed as a gap rather than a feature.
Until mainnet, only main is supported. The published npm package
@cloudsforge/hearth-node tracks main and older versions receive no fixes.