Security
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
This repository now has a **separate mainnet candidate profile**, not an audited or launched production network. Shipping code does not establish independent miners, economic security, an operational public network, or a safe real-money market. **Payments remain mocked on every profile.**
|
||||
|
||||
**Current production decision: NO-GO.** See the [2026-10-20 security review](security-review.md) and [operator evidence register and launch procedure](operator-launch.md). The read-only `launch:preflight` package script (or node entry-point `--launch-preflight`) reports local gates and unresolved blockers without starting a node or setting approvals. It deliberately exits nonzero while production readiness is blocked.
|
||||
|
||||
## What is implemented
|
||||
|
||||
| Property | Testnet default | Mainnet candidate |
|
||||
|
||||
@@ -67,6 +67,8 @@ Back up the ledger, marketplace SQLite databases and their WAL state consistentl
|
||||
|
||||
The service writes delivery intent before submitting to the ledger. A crash between these steps is reconciled by deterministic transfer ID; the seller can resubmit the same delivery if still valid. Background reconciliation runs every 15 seconds, and marketplace commands reconcile before mutation. A closed server does not send payouts or advance its local journal until restarted; deadline enforcement still uses absolute timestamps.
|
||||
|
||||
Canonical and pending sale delivery is recognized by the agreed seller/buyer/card/sequence even if submitted through the normal transfer endpoint or peer gossip rather than the marketplace command. Direct delivery without a recorded mock payment enters review instead of paying the seller. A refund check cannot cancel a previously signed transfer that arrives later or after a reorganization; this is a [production settlement blocker](security-review.md), not a solved atomic-exchange guarantee.
|
||||
|
||||
For **review**, preserve backups and inspect canonical blocks, pending transfers, signed order terms and transfer ID. Do not clear a payout marker, auto-refund, or blindly resubmit a payout. This release intentionally has no real-fund recovery controls.
|
||||
|
||||
## SHKeeper production boundary
|
||||
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
# Operator launch preparation and hold points
|
||||
|
||||
**Current decision: HOLD / NO-GO.** Review [the security findings](security-review.md) before scheduling production. The automated preflight intentionally exits nonzero while known production blockers remain. An environment variable, successful container startup or genesis timestamp cannot substitute for closing these findings.
|
||||
|
||||
## 1. Safe inspection — does not launch anything
|
||||
|
||||
Use Node.js 24 and a clean reviewed checkout. For mainnet assessment on a host, select `WIKIDECK_NETWORK=mainnet` in the process environment, then run the `launch:preflight` package script. It runs the node entry point with `--launch-preflight`, prints JSON and exits. `--network-manifest` remains available for identity inspection only.
|
||||
|
||||
The preflight:
|
||||
|
||||
- Selects the pinned profile and reports network, chain/genesis, fixed fee policy and local gate status.
|
||||
- Does **not** open/create a ledger or wallet, start a RandomX engine/listener, contact peers or SHKeeper, or write approval settings.
|
||||
- Does not print environment values or payment credentials. Reports are still operational information; review them before publishing.
|
||||
- Lists code blockers and missing external evidence. `productionReady` remains false even if startup approval variables are supplied. Fixes and independently reviewed evidence must be reflected in a future reviewed release; do not turn the report green by deleting findings.
|
||||
|
||||
The runtime image can execute the entry point with `--launch-preflight` as well; it does not include the package-script dev runner or need `tsx`. A Docker `test` target is provided for Node 24 build/test validation with Linux-native RandomX. No production launch command is supplied here while the decision is NO-GO.
|
||||
|
||||
**Important:** the report is an assessment, not an additional enforcement layer. Existing startup approval checks are still accident-prevention gates; an operator editing source or setting all approvals can bypass the intended process. Keep release/deployment permissions restricted.
|
||||
|
||||
## 2. Evidence register — all required before production sign-off
|
||||
|
||||
For each item record **owner, artifact/release ID, date, evidence location, reviewer and disposition**. Empty means unverified, not passed.
|
||||
|
||||
| Hold point | Required evidence | Current status |
|
||||
| --- | --- | --- |
|
||||
| Independent protocol/application review | Report against the exact release; critical/high findings fixed and retested; reviewed accepted residual risks | Missing |
|
||||
| Consensus launch design | Final genesis and manifest; measured starting target/hashpower; reviewed timestamp/retarget/partition/reorg attack analysis | Missing |
|
||||
| Node availability | Bounded public APIs/client; global resource/admission controls; realistic long-chain and hostile traffic capacity report | Missing |
|
||||
| Production wallet | At-rest/unlock/signing policy, same-origin compromise analysis, user confirmation and offline recovery drill | Missing |
|
||||
| Real-money market, if offered | Reviewed SHKeeper invoice/payment checks, invoice quote authorization, seller destination registration, fee-recipient allocation, custody policy, durable payout intents, timeout/partial-success reconciliation, refund/reorg dispute controls | Not implemented; real payment must stay blocked |
|
||||
| Mock-market policy | Ensure public users cannot mistake buyer-triggered mock payment for money; disable sandbox selling/delivery for valuable mainnet cards unless explicitly confined to a valueless trial | Unresolved |
|
||||
| Peer/miner topology | Multiple independently administered hosts/operators/failure domains; actual online matching manifests and sufficient independent hashpower, not just two URL strings | Unverified |
|
||||
| Edge and host security | TLS/certificate renewal, firewall, loopback backend, reviewed proxy IP trust, connection/global limits, restricted administration, patched hosts, time synchronization | Unverified |
|
||||
| Monitoring/on-call | Alert routes and successful drills for node isolation/tip lag, native failure, deep reorgs, WAL/disk exhaustion, queue/latency saturation and market review states | Unverified |
|
||||
| Restore/reconciliation | Consistent ledger + market SQLite/WAL backup and clean restore/revalidation; original market identity and idempotency history preserved; offline wallet recovery verified | Unverified |
|
||||
| Release supply chain | Lockfile, reviewed base/native/toolchain versions, runtime image digest, SBOM/advisory/native/container scans, signed provenance and restricted release access | Partial: npm advisory queries and local tests only |
|
||||
| Incident/governance | Named decision owners, market stop/containment procedure, fork/upgrade policy, communications, rollback criteria; custody/legal review if real money | Missing |
|
||||
|
||||
## 3. Freeze and rehearse before authorization
|
||||
|
||||
1. Close the security-review blockers in a separate reviewed release. Do not change consensus rules/difficulty under an existing launched chain ID. Prelaunch changes must generate a new pinned manifest and approval target where applicable.
|
||||
2. Freeze the actual UTC genesis date. **2027-01-01 is a candidate placeholder, not an announced launch.** On the review date (2026-10-20), that time gate is not satisfied.
|
||||
3. Freeze the exact image digest and review artifact hashes, network manifest, selected build/runtime profile, fee policy and intended public origins/peers. Confirm testnet data/backups are not reused.
|
||||
4. Rehearse on isolated, disposable nonvaluable networks with the reviewed rules: initial synchronization, competing miners, partitions/reconnects, invalid traffic, restart after crash, disk pressure and full restore. Never delete production data or lower confirmations to make a rehearsal pass.
|
||||
5. Verify the **intended production hosts**: DNS/TLS, proxy forwarded-IP handling, no direct backend access, matching chain IDs, data permissions, disk/memory/CPU capacity and observable peer freshness. `/healthz` alone is not acceptance evidence.
|
||||
6. Confirm fee address control out of band, without requesting or transmitting any seed/private key. Checksum validation alone does not prove control. No live test payment is authorized by this document.
|
||||
|
||||
## 4. Explicit operator go/no-go meeting
|
||||
|
||||
Record the final release digest, immutable manifest, all hold-point dispositions, change window, operator/reviewer names, monitoring/on-call contacts, recovery point/RTO, stop conditions and signatures/approvals in your controlled operations system.
|
||||
|
||||
Only after independent evidence has been reviewed should the authorized operator intentionally supply the existing chain-specific startup approval and review attestation. **This internal coding review is not the independent review referenced by that attestation.** Do not put private keys, seed phrases, payout credentials or backup passwords in the approval record, source tree or browser environment.
|
||||
|
||||
The launch preflight must not be repurposed to auto-populate approvals. No approval variables have been written by this work. Payments remain mocked even if network startup is later authorized; changing that requires a separately reviewed live-settlement release and explicit payment activation process.
|
||||
|
||||
## 5. Stop conditions and containment
|
||||
|
||||
- Halt new marketplace activity and investigate if invoice identity/amounts disagree, delivery is ambiguous, a settled order enters review, or payout status is unknown. Do not replay an ambiguous payout or automatically clear payout markers.
|
||||
- Treat deep reorgs, isolation, divergent manifests, sustained queue/latency overload, disk/WAL exhaustion, native-engine failure, key compromise or loss of monitoring as incidents. Stop accepting new risk using the approved containment procedure.
|
||||
- Stopping a node does not undo confirmed transactions or cancel previously signed transfers. Do not promise financial rollback from a software rollback.
|
||||
- Preserve logs and consistent backups. Never delete the ledger/market database, shorten history or change genesis to get a node to start. Remove a stale lock only after verifying that its process is stopped and completing the documented recovery review.
|
||||
- Resolve conflicting chains by the reviewed consensus/incident policy; do not silently install an ad hoc checkpoint or restore stale payment state against a newer chain.
|
||||
|
||||
After a controlled launch, observe the agreed soak period and obtain a second operational acceptance before expanding exposure. Real payments must not be part of a mock-market soak.
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
# Security review and production readiness — 2026-10-20
|
||||
|
||||
## Decision: NO-GO for public production or valuable assets
|
||||
|
||||
This is an internal, source-assisted review with automated regression and dependency checks, **not an independent security audit, penetration test, formal consensus proof, or production certification**. The candidate has not been launched and no approval/attestation was set. Do not interpret passing tests, the existence of a mainnet profile, or the arrival of its candidate genesis date as permission to launch.
|
||||
|
||||
Scope: current consensus/ledger/P2P/RandomX integration, HTTP entry point, browser wallet/backups, marketplace authorization/accounting/reconciliation, Docker configuration and candidate startup gates. The operating hosts, real reverse proxy, public peers, SHKeeper instance, wallets and funds were **not** accessed or assessed. No active Internet-facing adversarial load test or independent native-code audit was performed.
|
||||
|
||||
## Findings that block production
|
||||
|
||||
| ID | Priority / scope | Evidence and impact | Required disposition |
|
||||
| --- | --- | --- | --- |
|
||||
| SEC-01 | High · public node availability | [HTTP full-state routes](../server/testnet/http.ts#L63) return [full cloned canonical snapshots](../server/testnet/ledger.ts#L223). The ledger retains [all DAG nodes in memory](../server/testnet/ledger.ts#L29); state-root calculation rebuilds the NFT set. Read cost and startup replay grow with chain/fork history. Per-IP request limits do not impose a global CPU, response-byte, memory or disk budget. | Bounded/paged public RPC and a compatible paged client; tested caching/indexing; validation admission budgets; disk/fork retention or a reviewed archival strategy. Demonstrate the intended workload and malicious traffic do not starve consensus or trigger OOM/disk exhaustion. Do not add an arbitrary consensus height cap. |
|
||||
| SEC-02 | High · chain security | [Initial target](../server/testnet/consensus.ts#L12) succeeds with probability approximately 1/16 per hash, and [retarget](../server/testnet/consensus.ts#L172) uses ten-block windows. This is inherited testnet calibration, not evidence of a secure 15-minute production launch. Timestamp/retarget manipulation, hashpower concentration and private-chain rewrites require quantified analysis. | Independent consensus/economic review; measured launch hashpower; adversarial retarget/clock/partition simulations; choose and freeze final launch parameters and genesis before approval. Changing these changes chain identity. RandomX's shared algorithm does **not** inherit Monero's hashpower or security. |
|
||||
| SEC-03 | High · valuable NFT keys | [Browser wallet creation/storage](../src/wallet.ts#L76) persists an extractable P-256 private key without password encryption in IndexedDB. Encrypted portable backups do not encrypt that stored key. Same-origin script compromise, profile access or a sufficiently privileged extension can sign/export it. | A reviewed production wallet model with encrypted-at-rest storage/unlock lifecycle or isolated/hardware signing, explicit XSS threat model and tested recovery. Non-extractable keys alone do not stop malicious same-origin signing; storage encryption does not protect an already unlocked page. |
|
||||
| SEC-04 | High · real-money marketplace | [Payment adapter](../server/market/payments.ts) is deliberately mock-only. Buyer-controlled mock payment can lead a seller to sign a **real** card transfer. Listing reservations are not consensus locks. There is no reviewed live invoice verification, seller XMR destination registration, payout reconciliation, fee-recipient payout, refund/dispute system or custody controls. | Keep real money blocked. For valuable cards, disable mock-sale delivery/listings or keep the entire deployment explicitly valueless. Build/review the real SHKeeper settlement path separately; do not replace the mock adapter with a simple HTTP call. |
|
||||
| SEC-05 | High · future live refunds/finality | [NFT transfer signatures](../shared/testnet.ts#L54) have no expiry/revocation and payment state is not a consensus commitment. A transfer absent during refund review may be rebroadcast or reappear after a reorg. An off-chain refund cannot cancel a previously signed NFT transfer. Recognizing current canonical delivery (fixed below) does not solve this general issue. | Explicit escrow/atomic-settlement design or a reviewed reserve/dispute/manual risk policy, late-payment/delivery rules, and recovery tools. Never promise trustless exchange or unconditional automatic real refunds. No finite confirmation count guarantees finality on a small PoW network. |
|
||||
| SEC-06 | Medium · market availability | [Reconciliation](../server/market/store.ts#L115) synchronously scans journal rows/chain and writes journal state. Public browsing invokes it. Lifetime [10,000-listing/order caps](../server/market/store.ts) stop new business without a built-in archival workflow; signed unfunded bids and reservations have little economic cost. Nonces/receipts are not an economic spam defense. | Separate/cached read paths and indexed incremental reconciliation; measured event-loop/IO budgets; account/global anti-abuse policy; bounded receipt/storage management and a tested archive process that preserves payout/idempotency history. |
|
||||
| SEC-07 | Medium · deployment availability | The app leaves Express proxy trust at its default. Behind a reverse proxy, IP-based limits may group clients under the proxy IP, allowing one client to throttle everyone. Conversely, blindly enabling proxy trust would permit spoofed forwarded IPs. [Health](../server/testnet/http.ts#L50) reports process liveness, not peer synchronization, native-engine readiness or market reconciliation health. | Configure trusted proxy hops/CIDRs against the real topology; reject direct backend access and untrusted forwarded headers; apply edge/global limits and connection/time/body budgets. Add private monitoring for peer freshness, tip lag, reorgs, queues, RandomX failures, disk/WAL usage and market review states. Test actual TLS/HSTS/certificate renewal. |
|
||||
| SEC-08 | Medium · release supply chain | Lockfile installation and the pinned RandomX commit help, but [Docker base tags](../Dockerfile) and OS package selection are mutable. Native self-tests and npm advisory checks are not native/container security scans. Current builds require network retrieval. | Pin reviewed base image digests and publish exact resolved dependency/toolchain/native revisions, SBOM, image digest/signatures and provenance. Scan the actual runtime image and native build; protect CI/release access. Add native fuzz/sanitizer and reproducibility checks. |
|
||||
| SEC-09 | Operational blocker | [Startup gates](../server/launch.ts) check configuration syntax/approvals/date, not actual independent review, peer independence/online status, TLS reachability, data recovery or economic security. No real topology, backups, alerting or incident ownership was verified here. | Named operator/reviewer sign-off with attached evidence, multi-host rehearsal and restore drill. Do not set `independent-review-complete` merely because this internal report exists. |
|
||||
|
||||
These are prioritized risks/readiness gaps, not claims that each is an already exploited vulnerability. In particular, the mock adapter cannot presently lose real XMR because it never sends or accepts any.
|
||||
|
||||
## Fixed during this review
|
||||
|
||||
### SEC-F01 · delivery submitted outside the market could be missed
|
||||
|
||||
Before the correction, reconciliation recognized delivery only using an order's stored `transferId`, which was set by the market's `deliver` command. A seller could pay/agree to a sale and submit its exact NFT transfer through the normal transfer endpoint, CLI or peer gossip. The market saw the buyer own the card but had no stored delivery identity, so it could classify the paid order as refund-required. That created incorrect mock accounting and would be dangerous if copied into live settlement.
|
||||
|
||||
The [new deterministic delivery identity](../server/market/store.ts#L108) derives from the agreed card, seller, buyer, sequence and chain, independent of submission route/signature bytes. Canonical and pending checks and the refund guard use that identity. Direct delivery of an **unpaid** order enters review instead of triggering a payout. Regression tests cover direct canonical delivery, direct pending delivery, refused duplicate refund, and unpaid delivery. This does **not** solve SEC-05's late/reorged-signature problem.
|
||||
|
||||
### SEC-F02 · overly broad Docker build context
|
||||
|
||||
The prior [Docker exclusions](../.dockerignore) covered only dependencies and compiled UI. The build stage's `COPY . .` could incorporate local environment files, ledger/market databases, Git history, host native binaries or wallet backups into build layers/cache. No evidence of an actual leaked secret was obtained, and no sensitive files were intentionally opened to investigate.
|
||||
|
||||
Added exclusions for the data directory, Git metadata, environment files, common wallet/backup/database/private-key formats, host native builds and editor state. This is defense in depth, **not** a guarantee against an arbitrarily named secret. Build from a clean controlled checkout, keep secrets outside the build tree, and review images/cache access. If a sensitive checkout was previously built or pushed, assess exposure, remove affected artifacts according to retention policy, and rotate affected secrets; a later ignore rule does not remove an old layer.
|
||||
|
||||
## Controls checked and retained
|
||||
|
||||
- Network/chain/signature domain separation, strict public-key/curve/SPKI checks and NFT sequence/maturity validation. Both counterparties sign atomic card trades.
|
||||
- SQLite transactional ledger updates and serialized mutations; no automatic reset on chain mismatch/corruption. Marketplace instance/actor/action/nonce/expiry binding and fee policy signatures.
|
||||
- Fixed peer-origin configuration, bounded uncompressed responses/timeouts, DNS answer checks and connection-pinned lookup, no automatic redirect following. Fixed Wikimedia HTTPS sources and bounded API responses.
|
||||
- Pinned upstream RandomX source commit, bounded native input parsing and subprocess queues, shell-free spawning, and secure JIT/W^X flags. No selectable fake PoW production fallback.
|
||||
- Local backup PBKDF2-SHA256 / AES-256-GCM with authenticated headers, bounded input, key-pair validation and network checking. This is separate from the browser-storage issue above.
|
||||
- Non-root runtime, dropped capabilities, no-new-privileges, read-only root and separate data volume in candidate Compose. These settings do not establish host security.
|
||||
- Mock-only payment enforcement on all profiles; fixed 1% fee rate/recipient is public policy, **not a hardcoded secret**. It is disclosed and bound to sale signatures and order accounting. Existing orders are not silently repriced.
|
||||
|
||||
Intentional behaviors **not** reported as vulnerabilities: first-seen equal-work ties; exact auction deadline rejection; delivery window beginning at payment; seller delivery recipient checks; fail-closed handling of corrupted persisted transactions; and keeping settled orders in manual review after reorg rather than risking a second payout. The source checks the buyer and sequence on each delivery; a claim that an alternate recipient can be submitted through that endpoint was not supported.
|
||||
|
||||
USD authorization followed by a separately displayed XMR quote is not itself a critical exploit in this mock-only implementation. A future live checkout must bind/review the actual invoice ID, currency, destination, amount, expiry and fee allocation at the payment authorization step; that work remains part of SEC-04.
|
||||
|
||||
## Checks performed
|
||||
|
||||
- Node 24 TypeScript/Vite build: passed.
|
||||
- Full suite after corrections: **78 passed, 0 failed, 0 skipped**, including real reference RandomX known-vector/build coverage and two-node HTTP marketplace/transfer integration. Tests include the new read-only preflight and direct-delivery regressions.
|
||||
- npm production-only and full dependency advisory queries: **0 known advisories reported** for the locked tree at review time. This does not cover unpublished issues, malicious packages, Alpine/Node/native vulnerabilities or registry availability. Repeat against the final artifact before release.
|
||||
- Fixed fee address decoded independently as **95-character Monero Base58, 69 decoded bytes, prefix 18 (mainnet standard address)**; Keccak-256 checksum matched (`c752185b`). This proves formatting/checksum only, **not** ownership or intended recipient. Verify control out of band before any future live transfer; never share seed/private keys.
|
||||
- Mainnet preflight exercised with approvals absent: reports `NO-GO`, `productionReady: false`, `paymentMode: mock`; no node/ledger/network startup. Mainnet manifest/configuration remains candidate-only.
|
||||
|
||||
Not performed: independent audit, production-host penetration test, adversarial sustained load/fuzz campaign, private-key/hardware review, actual XMR invoice/payment/payout, SHKeeper instance verification, real peer/miner independence validation, or a production backup/restore exercise. See [operator launch procedure](operator-launch.md) for evidence required before explicit approval.
|
||||
Reference in New Issue
Block a user