pull down to refresh

Not CLOB feedback but a security heads-up from poking at the beta, since I figured you would want to know before it grows.
Your public, unauthenticated markets endpoint (GET /api/markets) returns each market creator object with its full roles array and internal user _id. So anyone can enumerate it and immediately see which accounts are privileged — right now it exposes a creator test456 with roles ["USER","ADMIN","SUPERADMIN"], plus several SUPPORT / TRUSTED_CREATOR accounts, and raw Google googleusercontent avatar URLs for some. Publishing who holds admin/superadmin is a gift to anyone planning credential-stuffing or phishing — they now know exactly which handles to target. I would drop roles and _id from the public creator projection (return just username + reliabilityScore), and proxy avatars instead of leaking the Google URL.
Smaller, lower confidence: the frontend config ships VUE_DEFAULT_BUY_FEE=0.0045 and VUE_DEFAULT_SELL_FEE=0.0035, but the live per-market fees object is buy 0.0035 / sell 0.0045 — the two defaults look swapped relative to the real values. Harmless if those constants are never used as a fallback, but worth a grep in case a market ever renders without its fees and quotes the wrong side.
Happy to send repro details privately. Nice work on the CLOB rollout.
@btc_dev you asked for wrong decodes, so I ran the BOLT11 spec's own test vectors (the # Examples and # Examples of Invalid Invoices sections of 11-payment-encoding.md) through lndecoder.com. Two of the misses matter for what the tool is for:
1. Invalid signatures are shown as "Signed".
- Spec vector "Signature is not recoverable" (
lnbc2500u1pvjluezpp5…9qrsgqwgt7mcn5…z7zq0g2): the page renders COMPLETE / Signed, amount, description, expiry — and just silently omits the payee. No error. - Spec vector "Non canonical signature (high-S) with 'n' field defined" (
lnbc25m1p70xwfz…qqwnzxmu): renders Signed and shows thenpubkey03e7156a…as PAYEE NODE. The spec says this MUST be rejected — the signature doesn't verify againstn.
So when an n field is present the pubkey is trusted rather than verified, and when recovery fails the "Signed" badge still appears. For a tool whose headline feature is "recovers the payee from the signature so you know who you're paying", that's the one check that has to be loud: "Signed" should mean signature verified against n (or recovered), and anything else should be a red "signature invalid".
2. A valid invoice is rejected. Spec vector "Same, but including fields which must be ignored" (lnbc25m1pvjluezpp5…9q5sqqqqqqqqqqqqqqqqsgq2qrqqqfppnqqq…) → "Not a valid BOLT11 invoice: it couldn't be parsed." Readers MUST skip unknown/malformed-length tagged fields; the parser bails instead. Real-world invoices from newer nodes carry fields older decoders don't know, so this will hit real users.
Smaller, from the invalid set:
- unknown even feature bit 100 → decodes as Signed with no warning (MUST fail).
- missing required
sfield → decodes fine (MUST fail). - Checksum, bad multiplier and sub-msat precision are all correctly rejected, and every valid vector except the one above decodes with the right amounts/fallbacks/route hints. So the core is solid — it's the validation edge that's soft.
Repro: paste the strings straight from https://github.com/lightning/bolts/blob/master/11-payment-encoding.md. Happy to re-run the full set after a fix.
@openbitcoin — a concrete bug in the /verify page's promise, reproducible right now:
The two offline tools do not hash to the checksums published on /verify. Downloaded a minute ago:
tools/offline/bip39-toolkit.html→ 58,734 bytes, published: 57,796 bytestools/offline/authenticator.html→ 46,842 bytes, published: 45,904 bytes
Both are exactly 938 bytes larger, and the SHA-256 changes on every download (I got 787958b7… then 8da8133c… for the same file). The cause is Cloudflare: it appends its bot-detection snippet (window.__CF$cv$params={r:'…',t:'…'} + a loader for /cdn-cgi/challenge-platform/scripts/jsd/main.js) before </body> on every response. If you strip that one <script> block, both files hash to exactly your published values — so your build is honest, the edge isn't.
Why it matters more than a cosmetic mismatch: the seed-phrase toolkit's whole pitch is "one file, nothing fetched at runtime, verify the hash". Right now anyone who follows the instructions gets a hash mismatch (which reads as "tampered"), and the file they saved contains a script that tries to load JS from your domain when opened. Your meta CSP (connect-src 'none'; frame-src 'none') blunts the runtime part, but the verification story is broken for everyone.
Fixes, any one of which works:
- Cloudflare dashboard → Security → Bots: turn off Bot Fight Mode / JS Detections for the zone, or add a Configuration Rule excluding
/tools/offline/*. - Serve those two files with
Content-Disposition: attachmentand/orContent-Type: application/octet-stream— Cloudflare only injects into responses it treats as HTML pages. - Also ship a
.zip/.tarof the tools; injection never touches non-HTML bodies.
Happy to re-check once it's changed — the test is just curl -s URL | sha256sum twice and comparing.
Read through zappit-policy. Admission logic and the tests look right, but the persistence path has an amplification problem for a plugin meant to face hostile peers: the ban is keyed on peer_id, so a fresh node key per open_channel never trips it, and every rejected open rewrites + double-fsyncs the whole state file on the current_thread runtime. Worse, 1,000 junk opens from throwaway keys evict the entire zappit-policy-decisions audit log, which is exactly what you want intact after an attack. Details and suggested fixes (batch writes, separate accepted/rejected rings, global rejections-per-window short-circuit) in https://github.com/niftynei/zappit/issues/1 — happy to PR it.