page and components#1
Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub. |
Greptile SummaryThis is the initial commit for Memetaverse, a Next.js dApp that lets users upload memes to IPFS via Pinata and register them on the Monad testnet through a Solidity
Confidence Score: 2/5Not safe to merge as-is — a live Alchemy API key is committed to the repository in three files and will be shipped in the browser bundle. An Alchemy API key is hardcoded verbatim in both client-rendered pages and a committed debug script, exposing it to anyone who inspects the bundle or browses the repo. The key is now in git history regardless of future edits. Additionally, onChainMemes.reverse() mutates state inside useMemo, which can silently break meme ordering and memo recomputation. pages/index.js, pages/explore.js, and scratch/check_memes.mjs all contain the hardcoded API key; pages/index.js also has the state-mutation bug in useMemo.
|
| Filename | Overview |
|---|---|
| pages/index.js | Main page with globe, search, and upload flow — contains a hardcoded Alchemy API key in the client bundle and directly mutates onChainMemes state inside useMemo via .reverse(). |
| pages/explore.js | Meme detail page that reads from on-chain or static data — same hardcoded Alchemy API key fallback as index.js, exposed in the browser bundle. |
| scratch/check_memes.mjs | Ad-hoc debug script committed to the repo with the Alchemy API key and contract address hardcoded — should be removed before merging. |
| pages/api/pinata/upload.js | Pinata upload API route — correctly gates on PINATA_JWT and handles temp-file cleanup, but lacks server-side MIME type validation allowing any file type to be uploaded. |
| context/WalletContext.js | Custom wallet context not wired into _app.js (wagmi/RainbowKit is used instead) — dead code that also exposes the ethers provider and signer as window globals. |
| components/FileUploadCard.js | Multi-file upload card with metadata form and animated progress — well-structured; simulated progress with setInterval is acceptable given fetch limitations. |
| meme-contract/contracts/MemeRegistry.sol | Simple Solidity registry contract with create/read operations — no access control issues; getMeme correctly validates the ID range. |
| lib/wagmiConfig.js | Wagmi/RainbowKit configuration — projectId now correctly falls back to env var before the placeholder string. |
| components/MemeDropZone.js | Drop-zone upload component with proper blob URL cleanup via previewUrlRef and useEffect — previously flagged memory-leak and UX issues appear addressed in this version. |
Comments Outside Diff (2)
-
pages/index.js, line 783 (link)Alchemy API key hardcoded in client-side bundle
The fallback RPC URL
"https://monad-testnet.g.alchemy.com/v2/EuLqamhK_5ymLb8952SSc"embeds an Alchemy API key directly in the Next.js page component. Becausepages/index.jsis included in the browser bundle, anyone who opens DevTools can extract this key and use your Alchemy quota. The same key also appears verbatim inpages/explore.jsandscratch/check_memes.mjs. Rotate the key immediately in the Alchemy dashboard, then supply it only via a server-side environment variable (neverNEXT_PUBLIC_) and proxy RPC calls through an API route, or at minimum keep it exclusively inNEXT_PUBLIC_MONAD_RPC_URLso it's not also baked into the source.Prompt To Fix With AI
This is a comment left during a code review. Path: pages/index.js Line: 783 Comment: **Alchemy API key hardcoded in client-side bundle** The fallback RPC URL `"https://monad-testnet.g.alchemy.com/v2/EuLqamhK_5ymLb8952SSc"` embeds an Alchemy API key directly in the Next.js page component. Because `pages/index.js` is included in the browser bundle, anyone who opens DevTools can extract this key and use your Alchemy quota. The same key also appears verbatim in `pages/explore.js` and `scratch/check_memes.mjs`. Rotate the key immediately in the Alchemy dashboard, then supply it only via a server-side environment variable (never `NEXT_PUBLIC_`) and proxy RPC calls through an API route, or at minimum keep it exclusively in `NEXT_PUBLIC_MONAD_RPC_URL` so it's not also baked into the source. How can I resolve this? If you propose a fix, please make it concise.
-
pages/index.js, line 674-676 (link)onChainMemes.reverse()directly mutates React stateArray.prototype.reverse()sorts the array in-place, soonChainMemes.reverse()mutates the state array before spreading it. React'suseMemouses a shallow reference comparison for its dependency; after the first call the reference is the same mutated array, so subsequent renders may not recompute the memo correctly and the order of on-chain memes in the UI can become non-deterministic. Copy the array before reversing to avoid the mutation.Prompt To Fix With AI
This is a comment left during a code review. Path: pages/index.js Line: 674-676 Comment: **`onChainMemes.reverse()` directly mutates React state** `Array.prototype.reverse()` sorts the array in-place, so `onChainMemes.reverse()` mutates the state array before spreading it. React's `useMemo` uses a shallow reference comparison for its dependency; after the first call the reference is the same mutated array, so subsequent renders may not recompute the memo correctly and the order of on-chain memes in the UI can become non-deterministic. Copy the array before reversing to avoid the mutation. How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 6 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 6
pages/index.js:783
**Alchemy API key hardcoded in client-side bundle**
The fallback RPC URL `"https://monad-testnet.g.alchemy.com/v2/EuLqamhK_5ymLb8952SSc"` embeds an Alchemy API key directly in the Next.js page component. Because `pages/index.js` is included in the browser bundle, anyone who opens DevTools can extract this key and use your Alchemy quota. The same key also appears verbatim in `pages/explore.js` and `scratch/check_memes.mjs`. Rotate the key immediately in the Alchemy dashboard, then supply it only via a server-side environment variable (never `NEXT_PUBLIC_`) and proxy RPC calls through an API route, or at minimum keep it exclusively in `NEXT_PUBLIC_MONAD_RPC_URL` so it's not also baked into the source.
### Issue 2 of 6
pages/index.js:674-676
**`onChainMemes.reverse()` directly mutates React state**
`Array.prototype.reverse()` sorts the array in-place, so `onChainMemes.reverse()` mutates the state array before spreading it. React's `useMemo` uses a shallow reference comparison for its dependency; after the first call the reference is the same mutated array, so subsequent renders may not recompute the memo correctly and the order of on-chain memes in the UI can become non-deterministic. Copy the array before reversing to avoid the mutation.
```suggestion
const allMemes = useMemo(() => {
return [[...onChainMemes].reverse(), ...MEMES];
}, [onChainMemes]);
```
### Issue 3 of 6
pages/explore.js:506
**Alchemy API key hardcoded in client-side page**
Same hardcoded fallback URL `"https://monad-testnet.g.alchemy.com/v2/EuLqamhK_5ymLb8952SSc"` as in `pages/index.js`. See the comment there for details and remediation steps.
### Issue 4 of 6
scratch/check_memes.mjs:9
**Debug script with hardcoded API key committed to repo**
This one-off helper embeds the same Alchemy API key at line 9 and commits a concrete contract address. Debug/scratch scripts like this should live in a `.gitignore`d directory or be removed before the PR is merged to prevent credential exposure through version history.
### Issue 5 of 6
context/WalletContext.js:22-23
**Provider and signer assigned to `window` globals**
`window.provider` and `window.signer` expose the ethers `BrowserProvider` and `Signer` objects as mutable globals, making them accessible to any third-party script running in the same page. Any XSS payload or malicious browser extension can now call `window.signer.signTransaction(...)` without user interaction. Note that `WalletContext` is not wired into `_app.js` (which uses wagmi/RainbowKit instead), so this file appears to be dead code — consider removing it entirely.
### Issue 6 of 6
pages/api/pinata/upload.js:24-30
**No server-side file-type validation**
The upload handler accepts any MIME type from `formidable` and forwards it to Pinata without checking the content type. A user can submit a `.exe`, `.php`, or any other non-media file with the content type spoofed. While Pinata itself is content-agnostic, the front-end `FileUploadCard` declares `accept="image/*,video/*"` — a trivially bypassed browser hint. Add a server-side allowlist check on `uploaded.mimetype` before reading the file buffer.
Reviews (5): Last reviewed commit: "readme" | Re-trigger Greptile
…mation dependencies
…opups for highlighted memes
… delaying render until mounted
| ]; | ||
|
|
||
| async function main() { | ||
| const provider = new ethers.JsonRpcProvider("https://monad-testnet.g.alchemy.com/v2/EuLqamhK_5ymLb8952SSc"); |
There was a problem hiding this comment.
Debug script with hardcoded API key committed to repo
This one-off helper embeds the same Alchemy API key at line 9 and commits a concrete contract address. Debug/scratch scripts like this should live in a .gitignored directory or be removed before the PR is merged to prevent credential exposure through version history.
Prompt To Fix With AI
This is a comment left during a code review.
Path: scratch/check_memes.mjs
Line: 9
Comment:
**Debug script with hardcoded API key committed to repo**
This one-off helper embeds the same Alchemy API key at line 9 and commits a concrete contract address. Debug/scratch scripts like this should live in a `.gitignore`d directory or be removed before the PR is merged to prevent credential exposure through version history.
How can I resolve this? If you propose a fix, please make it concise.| // Expose provider and signer globally or simply know they are available when connected | ||
| window.provider = provider; |
There was a problem hiding this comment.
Provider and signer assigned to
window globals
window.provider and window.signer expose the ethers BrowserProvider and Signer objects as mutable globals, making them accessible to any third-party script running in the same page. Any XSS payload or malicious browser extension can now call window.signer.signTransaction(...) without user interaction. Note that WalletContext is not wired into _app.js (which uses wagmi/RainbowKit instead), so this file appears to be dead code — consider removing it entirely.
Prompt To Fix With AI
This is a comment left during a code review.
Path: context/WalletContext.js
Line: 22-23
Comment:
**Provider and signer assigned to `window` globals**
`window.provider` and `window.signer` expose the ethers `BrowserProvider` and `Signer` objects as mutable globals, making them accessible to any third-party script running in the same page. Any XSS payload or malicious browser extension can now call `window.signer.signTransaction(...)` without user interaction. Note that `WalletContext` is not wired into `_app.js` (which uses wagmi/RainbowKit instead), so this file appears to be dead code — consider removing it entirely.
How can I resolve this? If you propose a fix, please make it concise.| } | ||
|
|
||
| // Extract metadata fields matching MemeRegistry contract | ||
| const title = fields.title?.[0] || ''; | ||
| const description = fields.description?.[0] || ''; | ||
| const country = fields.country?.[0] || ''; | ||
| const category = fields.category?.[0] || ''; |
There was a problem hiding this comment.
No server-side file-type validation
The upload handler accepts any MIME type from formidable and forwards it to Pinata without checking the content type. A user can submit a .exe, .php, or any other non-media file with the content type spoofed. While Pinata itself is content-agnostic, the front-end FileUploadCard declares accept="image/*,video/*" — a trivially bypassed browser hint. Add a server-side allowlist check on uploaded.mimetype before reading the file buffer.
Prompt To Fix With AI
This is a comment left during a code review.
Path: pages/api/pinata/upload.js
Line: 24-30
Comment:
**No server-side file-type validation**
The upload handler accepts any MIME type from `formidable` and forwards it to Pinata without checking the content type. A user can submit a `.exe`, `.php`, or any other non-media file with the content type spoofed. While Pinata itself is content-agnostic, the front-end `FileUploadCard` declares `accept="image/*,video/*"` — a trivially bypassed browser hint. Add a server-side allowlist check on `uploaded.mimetype` before reading the file buffer.
How can I resolve this? If you propose a fix, please make it concise.
No description provided.