{"assessments":[],"deployments":[],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"4bd31cfb-1151-497f-9b27-40e668dea372","kind":"skill:research-report","nodes":[{"acceptedSubmissionHash":"07c6bda9f8ffe859122e263b275e0ed21925f40efa3f804f9609227a7102e70b","dependsOn":[],"execution":{"network":true,"profile":"none","requires":["network"],"skillHash":"3ddca93330036359dd721585e58e67820336a0398b7927b3c89369d6134f30f6","skillId":"research-report","tools":[]},"key":"research_report","kind":"code","role":"implement","skillHash":"3ddca93330036359dd721585e58e67820336a0398b7927b3c89369d6134f30f6","skillId":"research-report","state":"accepted"}],"objective":"IMD Ember World (https://imdember.com) wallet sign-in security review (World only)\n\nQuestion: Is it safe for a player to connect a wallet and sign in at https://imdember.com, Worker \"imd-world\" version beac62be-27ff-40cd-9dc4-3cbbdc6add4b, built from commit 0def8cb5b80083d32545c59bc707fbbc92a4758d?\n\nMaterial:\n- Review repo: https://github.com/tungweb3/imd-ember-world-review at commit c2a8c33d2c3b1f643bb8c369527d56e51f88e9e5\n- Start with README.md and SCOPE.md; SHA256SUMS covers every file; DEPLOYMENT_MATCH.md maps source/build/live hashes; source/ has the whole server side, wallet client and tests.\n- Docs are claims, not evidence: verify against the code, the live bundle and your own runs.\n\nCheck:\n1. Every wallet RPC call reachable in connect, sign-in, session restore and \"my home\". Tell SIWE/personal_sign apart from transactions, typed data, Permit/Permit2, approve, setApprovalForAll, batch calls, session keys. Re-count on the live JS.\n2. SIWE message fields, server-side verification incl. ERC-1271, one-time nonce, replay, burn on failure, sign-in budgets, limiters failing closed.\n3. Session cookie flags, CSRF/Origin, logout, expiry, account/chain switch, tabs, late responses.\n4. Owner APIs take the wallet only from the server session; no WebSocket.\n5. Ownership is mainnet ownerOf on 0x0000ec93127baa929e58e97dd0095a2bfb38ec1d; roster and index are only candidates; transfers, chain failures, caching. Rule: one house per wallet, sized by counted seats (not a defect). #361/#921 get no privilege.\n6. Rebuild the Worker bundle from source/ (expected SHA-256 4ec73351afbcc9af133fd487d7e2d33c1df6713bfa1aced881f412d38e0eccf3); compare live index/JS/CSS hashes.\n7. Dependencies, dynamic modules, CSP/headers, XSS and supply-chain exposure.\n8. World/Mint boundary (origin, cookies, bundle, routes, data, signer); a future Genesis Mint page will be a same-origin sub-page using this session; say \"unknown\" when unknown.\n9. Separate confirmed World issues, shared-boundary issues, unverified items, Genesis to-dos.\n\nOut of scope: Genesis Mint (contracts, mint flow, signer, metadata/IPFS) and withheld code (3D world, art, music, house placement, WorldApp.tsx) beyond the public bundle.\n\nTesting limits: on production only a few low-rate public GETs (an edge rule blocks IPs over 20 /api/ requests per 10 s); no POST, sign-in, fuzzing, scanning or exploits. Reproduce locally per README.md (Node 24.19.0, TESTS/stubs one-liner) with synthetic keys and mocks. No real wallets, signatures or transactions; do not change the target.\n\nDeliverable: a report in Traditional Chinese (English technical terms kept): scope and version/hashes; each finding with severity, file:line or URL evidence and repro steps; the wallet-method inventory; a deployment-match verdict (verified/partial/unverified) with reasons; your commands and output, apart from owner logs; what could not be verified. Do not call the site safe, secure, audited or certified; imply no endorsement.","parentJobId":null,"planHash":"f63350e785dffa65b432c60a4fe2bf2323f6e5824be77c74eb6f6774484c7c36","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"4bd31cfb-1151-497f-9b27-40e668dea372","publication":{"commit":null,"deliveredAt":null,"repoUrl":null},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51336","feedbackHash":"36c5d07fa1e100ba806d493b397647f1ea13eb2a2a59bb3395c000022234665e","nodeKey":"research_report","submissionHash":"07c6bda9f8ffe859122e263b275e0ed21925f40efa3f804f9609227a7102e70b","tag1":"verification:structural","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"d69f852b4ad3a7f3958724d5baa5ff51a1ad3bd4c954d703724f00dcf43351fa","state":"completed","submissions":[{"artifacts":[{"bytes":36294,"hash":"a4addfe1ce612bd0f598df0120a93113bfa0ca7a906c061e01165dcf1569c234","mediaType":"text/markdown","name":"report","path":"artifacts/report.md"}],"attempt":1,"bundleHash":null,"device":"00d95fd75f8b224c","findings":[],"hash":"07c6bda9f8ffe859122e263b275e0ed21925f40efa3f804f9609227a7102e70b","nodeId":"23c0fae1-197d-4a40-adb2-cb4f9bf58f52","outcome":"completed","summary":"I've written the report to `artifacts/report.md` (Traditional Chinese, English technical terms kept), plus `artifacts/README.md`. The report does not call the site safe, audited or certified. What the evidence supports: in this version, sign-in asks for one plain-text signature and nothing that can move assets. I found no way to sign in as someone else's wallet without their signature.\n\n**Wallet calls.** The source and the live JS agree. The site calls only `eth_accounts`, `eth_requestAccounts` and `personal_sign` (for sign-in only), and only listens for `accountsChanged`. Transactions, typed data, Permit/Permit2, `approve`, `setApprovalForAll`, batch calls, session keys and chain switching all count 0 in the live JS. Restoring a session and \"my home\" make no wallet calls at all.\n\n**Server checks** (source, 112 existing tests plus 7 probes of my own, run locally with synthetic keys and mocks): nonces work only once, and a failed signature voids the challenge. Rate limiters refuse requests when misconfigured. Cookies use the `__Host-` prefix, HttpOnly and Secure. POSTs from any other origin are rejected. `/api/me/home` takes the wallet only from the session, and there is no WebSocket. Ownership is checked with a mainnet `ownerOf` call on 0x0000ec93…ec1d; the roster and index are only used to find candidates.\n\n**Deployment match: partial.**\n- **Worker bundle:** my rebuild from `source/` matches the expected `4ec73351…0eccf3` byte for byte.\n- **Live site:** the index, JS and CSS hashes match what the snapshot states.\n- **Not verifiable from outside:** the Worker actually running on Cloudflare, its secrets, the D1 schema, the limiter bindings and the WAF rule.\n- **Frontend:** it can't be rebuilt from the public source, so I checked the live JS bytes directly.\n\n**Findings.** Nothing rated High or Critical.\n\n| # | Severity | What happens | Reproduced locally |\n|---|---|---|---|\n| F-1 | Medium (shared with future Mint); Low for World today | A script can fake the Origin header, fetch a real sign-in message for a victim's address, and get a 7-day session if the victim signs it on a phishing page. This is a general SIWE limit, not a code bug; the defence is the wallet's domain check. The project docs don't mention it. | Yes |\n| F-2 | Low/Info | A smart-contract wallet that approves any signature lets anyone sign in as it. If it holds a seat, they get owner mode for it. | Yes |\n| F-3 | Low (availability) | Junk signatures from about 7 IPv4 /24 networks use up one Cloudflare location's smart-wallet check budget. Real smart wallets there then get `429 CHAIN_BUSY`. | Yes |\n| F-4 | Low | Logging out ends only this browser's session. There is no way to log out every device for an address. | Yes |\n| F-5 | Low (already disclosed in code comments) | About 20 IPv4 /24 networks can keep the site-wide sign-in limit closed for everyone. | Yes |\n| F-6 | Info | `npm audit` finds 5 issues, all in build and dev tools; runtime dependencies have 0. | — |\n\nRight now a session only unlocks read-only \"my home\" views and local house moves, so most of this has limited impact on World. It matters more for the planned Genesis Mint page, which will sit on the same origin and reuse this session. The report lists seven to-dos for that, starting with requiring a separate, clearly worded signature for mint instead of the current session.\n\n**Not verified:** anything with a real browser or real wallets, including whether wallets warn on the domain mismatch that F-1 relies on. Also Cloudflare's running configuration, and the Mint design, which was out of scope. On production I made only 6 slow GET requests: no POST, no sign-in, no scanning.\n\nThe probe tests and their output are in `artifacts/probes/`, so the reproductions can be re-run. Everything under `artifacts/` is untracked and not committed.\n\nFiles are in `artifacts/`:\n- report.md\n- README.md\n- probes/reviewer-probes.test.mjs\n- probes/reviewer-probes-output.txt","treeHash":"4b825dc642cb6eb9a060e54bf8d69288fbee4904","usage":{"cachedInputTokens":3838549,"inputTokens":66,"model":"claude-opus-5-5","outputTokens":43878,"runtime":"claude","turns":37,"wallClockMs":691061}}],"verification":[{"checks":[],"detail":"paths and tree verified; no suite was run for this kind of work","evaluation":"structural","profile":"none","status":"accepted","submissionHash":"07c6bda9f8ffe859122e263b275e0ed21925f40efa3f804f9609227a7102e70b","verifiedTreeHash":"4b825dc642cb6eb9a060e54bf8d69288fbee4904","verifierVersion":"0.1.0+78c54e29"}]}