{"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":"c6d53098-3c49-4c24-9bbc-abae95729474","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"6489635a655c1457b1a5a42e7507dbf791eeb54394e4d57505e2e04345eea580","dependsOn":[],"execution":{"mustProduce":["dist/index.html"],"network":true,"profile":"none","requires":["network"],"skillHash":"d85feeeba61710fcde95b6484d4ed21af1a49b2b609a1b0ea33f16d5a47ec9ca","skillId":"import-site","tools":[]},"key":"import_site","kind":"code","role":"implement","skillHash":"d85feeeba61710fcde95b6484d4ed21af1a49b2b609a1b0ea33f16d5a47ec9ca","skillId":"import-site","state":"accepted"},{"acceptedSubmissionHash":"06f091406e33ac71084d665c303f98d7f99245b7a7152f3fa1a109bb4ef570c3","dependsOn":["import_site"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"8189a3059fc9bb774ad7dcee66b87f32e25d781025f0e9f82a4c75182fe0ef19","skillId":"site-content-check","tools":[]},"key":"site_content_check","kind":"code","role":"review","skillHash":"8189a3059fc9bb774ad7dcee66b87f32e25d781025f0e9f82a4c75182fe0ef19","skillId":"site-content-check","state":"accepted"}],"objective":"Project: Courier World website, a backup copy on IMD hosting.\n\nPlease host the Courier World website as a new IMD site named courierworld (https://courierworld.sites.imd.fun/). It is a backup of https://courierworld.fun (on Vercel, currently offline); both serve the same game.\n\nRepo: github.com/AdamNakamoto/courierworld (commit f28bea71e63e53f211fa608b39656fc89ff5e3c5)\nBuild: npm run build (no dependencies to install). It copies the web/ folder to dist/. Serve dist/ as the site root (dist/index.html is the home page), with every file and subfolder in it.\n\nWhat the site is: Courier World is a static web game (HTML/JS, no backend of its own) on Robinhood Chain: a tiny planet where players open post offices that earn $STAMP, mint Courier Skins and Planets, launch tokens, fish, and hunt for token coins, all through the visitor's own browser wallet. Multiplayer, chat, the treasure hunt and fishing run on a separate server (courier-world-mp.courier-world-mp.workers.dev), which already accepts this address.\n\nAfter publishing, please confirm on courierworld.sites.imd.fun:\n- / returns 200 and shows the title screen (the planet and the \"Begin\" button)\n- /main.js, /chain.js, /drop-pick.js, /net.js, /office.js, /deployments/robinhood.json, /hunt-spots.json, /orb.json and /brand/mine-token.png return 200\n- /deployments/robinhood.json contains \"drops2\": \"0x35E75cbE2EACb407D2dEB068AF0665E7858BE75F\"\n- after Begin, the top of the screen shows the treasure hunt's running line (it reads the chain), and the player count shows (it connects to the multiplayer server)\n- /docs.html returns 200\n\nPlease host it as-is: don't change files or push to the repository; report any finding and I will fix it in the repository.\n\nKnown limits: the post office leaderboard's history comes from Robinhood Chain's official RPC (or the Vercel relay); while both are down it doesn't load, and the rest of the game is unaffected.","parentJobId":null,"planHash":"cd8bdb05c9d6b1fdc8561a171c1679207a7313d84781a24e1e6a2a0feebc24ae","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"c6d53098-3c49-4c24-9bbc-abae95729474","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":"53938","feedbackHash":"a904b53ee547cc603c1f6d150b9bc4f31dfefc4b920017f94788e76ca6b3aaf8","nodeKey":"import_site","submissionHash":"6489635a655c1457b1a5a42e7507dbf791eeb54394e4d57505e2e04345eea580","tag1":"verification:structural","tag2":"acceptance-v2","value":1},{"agentId":"52141","feedbackHash":"1f4f019c81816e6232f46d85a67a06f92ed284b0d88041b87c389737e2734cc0","nodeKey":"site_content_check","submissionHash":"06f091406e33ac71084d665c303f98d7f99245b7a7152f3fa1a109bb4ef570c3","tag1":"review:submission","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"364335fd8c2d3214f0da329559d5fe03183866fa4380560829b674a621499f76","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"0fde2559e5db10f2","findings":[{"citation":"resolved","description":"The entry point loads Three.js from esm.sh, and its module graph also loads viem from esm.sh. The current response from courierworld.sites.imd.fun carries Content-Security-Policy with script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval', which does not permit that origin. Serving this export under that policy prevents main.js from evaluating: the planet is absent and Begin has no handler. dist/studio.html:14 also loads JSZip from cdnjs.cloudflare.com, another origin excluded by this policy. This is a hosting compatibility defect, not evidence of malicious dependencies. The target currently returns 404; post-publication headers still need verification.","line":1,"path":"dist/main.js","reproduction":"Retrieve the Content-Security-Policy header from https://courierworld.sites.imd.fun/ (observed 2026-10-16). Serve the unchanged dist/ with that header and open / in Chromium. The console reports that https://esm.sh/three@0.160.0 violates script-src and is blocked. The canvas remains its default 300x150 size; clicking Begin leaves #hud.hidden true. Expected: the planet renders and Begin starts the game/login flow. Reproduced locally with the exact target header. Make the exported imports compatible with the final host's policy before publishing.","severity":"medium","snippet":"import * as THREE from \"https://esm.sh/three@0.160.0\";","title":"External module imports are blocked by the target host's current script policy"},{"citation":"resolved","description":"main.js accepts any ?mp= WebSocket endpoint. net.js passes the fstate message object to main.js without validating its fields, and this template inserts fs.max directly into HTML assigned to #officeMore.innerHTML. A crafted max field therefore executes an event handler in the site origin when the Post Office panel is shown. A link to the legitimate game can select an attacker-operated multiplayer server; no compromise of the official server is needed. The attacker can then alter wallet-facing UI and read same-origin game session tokens. No wallet secret or asset transfer was used in the reproduction. Validate incoming numeric fields and render them as text; restrict the production multiplayer endpoint.","line":721,"path":"dist/office.js","reproduction":"Serve the unchanged dist/ and use a test multiplayer WebSocket selected with /?mp=wss://YOUR-TEST-HOST/ws. With chain reads succeeding so that the Post Office snapshot includes the configured fish contract, send the welcome frame [\"welcome\",\"review\",[],\"test-code\",[]], followed by [\"fstate\",{\"on\":true,\"day\":20742,\"today\":0,\"max\":\"<img src=missing-proof-image onerror=window.courierReviewXss=1>\",\"days\":[],\"caught\":{}}]. Enter the game and open Post office (P), with the fish contract configured as in deployments/robinhood.json. Expected: reject the nonnumeric max value or display it as text. Actual: the img is inserted and window.courierReviewXss becomes 1. Independently reproduced in Chromium by importing the unchanged office.js into a minimal DOM with #office, #officeBody, #officeMore and #trade, calling createOffice with snapshot() returning {seed:1n,game:true,account:null,minted:3333,saleOpen:false,price:0n,nft:\"0x0000000000000000000000000000000000000000\",fish:{species:[],owned:{},paused:false}} and fish.state() returning that status, then calling show(true). The marker became 1 without logging in or signing. Also reproduced through the unchanged net.js createNet(): an intercepted test WebSocket sent the welcome and fstate frames above; onFish forwarded the object to the unchanged createOffice renderer, and the same marker became 1.","severity":"medium","snippet":"        <p class=\"note\">Stand on the pier, a bridge over the bay or the water's edge, face the water and ${matchMedia(\"(pointer: coarse)\").matches ? \"tap Hi\" : \"press E\"}. Hook it when the float dips, then keep the line in the green. Up to ${fs?.max ?? FISH_PER_DAY} fish a day, free for post office owners: each one is yours to mint as a Courier Fish NFT, paying only gas.</p>`;","title":"A multiplayer endpoint supplied in the URL can inject JavaScript through fishing status"}],"hash":"06f091406e33ac71084d665c303f98d7f99245b7a7152f3fa1a109bb4ef570c3","nodeId":"bacf6af1-6bce-4ed1-a7d0-d89010d7c696","outcome":"completed","summary":"Saved two medium findings in [.imd-findings.json](/home/seat/.identitymd/work/c6d53098-3c49-4c24-9bbc-abae95729474/bacf6af1-6bce-4ed1-a7d0-d89010d7c696/.imd-findings.json):\n\n- Fishing status permits JavaScript injection through a URL-selected multiplayer server.\n- External scripts conflict with the target host’s observed CSP.\n\nReviewed all exported pages/scripts and assets. No critical/high findings identified. Local build, title screen, required assets and `drops2` checks passed.\n\nLive confirmation remains incomplete: the host returns 404, and post-Begin checks encountered timeouts/RPC failures. Only the findings file was changed.","treeHash":null,"usage":{"cachedInputTokens":8942208,"inputTokens":390303,"model":"gpt-6-astra","outputTokens":32003,"runtime":"codex","turns":11,"wallClockMs":1484625}},{"artifacts":[],"attempt":1,"bundleHash":"b7756155a565d1a0d2d5f63eec346383b050856373e6035638ee56f51e75614e","device":"01695e9524859621","findings":[],"hash":"6489635a655c1457b1a5a42e7507dbf791eeb54394e4d57505e2e04345eea580","nodeId":"2711f814-24a8-4c55-91f8-5784b26d3f9c","outcome":"completed","summary":"Built with **npm** using **`npm run build`**, writing to **`dist/`** with `dist/index.html`.\n\n- All 843 output files match the repository’s build byte-for-byte.\n- Required assets exist; `drops2` matches the requested address.\n- Site sources, configuration and dependencies are unchanged. Only the `dist/` ignore entry was removed.\n\nPublishing remains unconfirmed: no publishing tool is available, and all requested URLs at `courierworld.sites.imd.fun` return **404**. Browser gameplay checks remain unverified.\n\nThe complete output is **11.17 MiB**, exceeding the reference’s **8 MiB** upload limit. No files were omitted.","treeHash":"135aad6c0ac982f87d8f5ebbc5dfd51d2154899d","usage":{"cachedInputTokens":116992,"inputTokens":37229,"model":"gpt-6-astra","outputTokens":1877,"runtime":"codex","turns":3,"wallClockMs":74939}}],"verification":[{"checks":[],"detail":"paths and tree verified; no suite was run for this kind of work","evaluation":"structural","profile":"none","status":"accepted","submissionHash":"6489635a655c1457b1a5a42e7507dbf791eeb54394e4d57505e2e04345eea580","verifiedTreeHash":"135aad6c0ac982f87d8f5ebbc5dfd51d2154899d","verifierVersion":"0.1.0+d952fceb"}]}