Conversation
Priority 1 (security blockers): - Add NextAuth v5 middleware protecting /dashboard/* routes - Add CSP and HSTS security headers to vercel.json - Create Privacy Policy and Terms of Service pages - Restrict CORS to production domains (shield.q-grid.ca, Vercel previews) - Replace hardcoded localhost API rewrite with SHIELD_API_URL env var Priority 2 (launch readiness): - Add robots.ts and sitemap.ts via Next.js metadata API - Add Open Graph and Twitter Card meta tags to root layout - Add favicon (SVG + generated PNG), apple-touch-icon, and web manifest - Add ErrorBoundary with timeout-controlled error reporting - Add GDPR-compliant cookie consent banner with hydration guard Code quality (from /simplify review): - Extract PolicyLayout component to eliminate privacy/terms duplication - Create SITE_URL constant to centralize domain references - Add AbortController timeout to error boundary fetch - Move env var reads to module scope in next.config.js Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…lidation, IDOR checks - Add structured logger (src/lib/logger.ts) replacing 235+ console.log calls - Add API key auth guard + JSON schema validation on all POST routes (server.js) - Add IDOR ownership check on transfer endpoint - Replace CORS wildcard with explicit origin whitelist (server.ts) - Add IPFS CID format validation + gateway allowlist (IPFSService.ts) - Fix deprecated X-XSS-Protection header (vercel.json) - Migrate 4 service files to structured logging (GridDB, IPFS, MirrorNode, NFTShield) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| } else { | ||
| const prefix = { debug: '🔍', info: 'ℹ️ ', warn: '⚠️ ', error: '❌', silent: '' }[level]; | ||
| const output = level === 'error' ? console.error : level === 'warn' ? console.warn : console.log; | ||
| output(`${prefix} [${context}] ${message}`); |
Check warning
Code scanning / CodeQL
Log injection Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 12 hours ago
In general, to fix log injection for plaintext logs, any user-controlled input that is written into a log line should be sanitized so it cannot break the log structure. For text logs, this typically means removing or normalizing newline and carriage-return characters (and optionally other control characters) from user-controlled strings before interpolating them into log messages.
The best way to fix this here without changing existing semantics is to centralize sanitization inside the logger: ensure that message (and optionally context) are passed through a small helper that strips \r and \n when constructing the human-readable (non-production) log line. The production branch already uses JSON.stringify, which escapes these characters and is not vulnerable in the same way, so we only need to modify the non-production path. We should introduce a private sanitizeLogText function in src/lib/logger.ts and use it when building the string for console.log/console.warn/console.error in the development branch:
- Add a helper like
function sanitizeLogText(value: string): string { return value.replace(/[\r\n]/g, ' '); }. - In
formatMessage, in the non-productionelseblock, computeconst safeContext = sanitizeLogText(context); const safeMessage = sanitizeLogText(message);and then log`${prefix} [${safeContext}] ${safeMessage}`. - Keep the
dataobject logged as-is; it is logged as a separate argument and not concatenated into the log line, so it does not affect log structure in the same way.
All required changes are limited to src/lib/logger.ts; no new imports or external dependencies are needed.
| @@ -28,6 +28,11 @@ | ||
| return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[configuredLevel]; | ||
| } | ||
|
|
||
| function sanitizeLogText(value: string): string { | ||
| // Prevent log injection by removing line breaks and carriage returns from log text | ||
| return value.replace(/[\r\n]/g, ' '); | ||
| } | ||
|
|
||
| function formatMessage(level: LogLevel, context: string, message: string, data?: unknown): void { | ||
| if (!shouldLog(level)) return; | ||
|
|
||
| @@ -47,7 +52,9 @@ | ||
| } else { | ||
| const prefix = { debug: '🔍', info: 'ℹ️ ', warn: '⚠️ ', error: '❌', silent: '' }[level]; | ||
| const output = level === 'error' ? console.error : level === 'warn' ? console.warn : console.log; | ||
| output(`${prefix} [${context}] ${message}`); | ||
| const safeContext = sanitizeLogText(context); | ||
| const safeMessage = sanitizeLogText(message); | ||
| output(`${prefix} [${safeContext}] ${safeMessage}`); | ||
| if (data !== undefined) { | ||
| output(data); | ||
| } |
| error: Error | null; | ||
| } | ||
|
|
||
| export class ErrorBoundary extends Component<Props, State> { |
Check warning
Code scanning / CodeQL
Unused or undefined state property Warning
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 15 hours ago
In general, to fix “state property is written but never read” you either (a) remove the unused state property and any writes to it, or (b) make use of the state property in the component (for example, by rendering it or using it in logic). Here, because the presence of error in State and the setting of it in getDerivedStateFromError suggests the author intended to surface error details, the best fix is to read and render this.state.error in the fallback UI, instead of removing it.
Concretely in web/src/components/error-boundary.tsx:
- Keep the existing
Stateinterface anderrorwrites as-is. - Update the
rendermethod’s error branch to:- Destructure
const { error } = this.state;. - Conditionally render extra diagnostic text when
erroris non-null, e.g. showerror.message(and possibly a short generic label) in the fallback content.
- Destructure
- This introduces a read of
this.state.error, satisfying CodeQL and preserving theTry Againbehavior and error reporting. No new imports or external dependencies are needed; we only add a few JSX nodes using the existing Tailwind-like classNames.
All changes are confined to the render method in this file.
| @@ -60,6 +60,8 @@ | ||
| return this.props.fallback; | ||
| } | ||
|
|
||
| const { error } = this.state; | ||
|
|
||
| return ( | ||
| <div className="min-h-[400px] flex items-center justify-center p-8"> | ||
| <div className="text-center space-y-4 max-w-md"> | ||
| @@ -70,6 +72,11 @@ | ||
| <p className="text-sm text-muted-foreground"> | ||
| An unexpected error occurred. Please refresh the page or try again later. | ||
| </p> | ||
| {error && ( | ||
| <p className="text-xs text-muted-foreground break-words"> | ||
| Error details: {error.message} | ||
| </p> | ||
| )} | ||
| <button | ||
| onClick={() => this.setState({ hasError: false, error: null })} | ||
| className="inline-flex items-center justify-center px-4 py-2 bg-primary text-primary-foreground rounded-lg text-sm font-medium hover:bg-primary/90 transition-colors" |
- Use crypto.timingSafeEqual() for API key comparison (prevents timing attacks) - Add requireApiKey to GET /shield/:id, /migration/*, /stats (prevents info leak) - Remove 'unsafe-eval' from CSP (XSS hardening) - Tighten CORS regex to quantum-shield-nft*.vercel.app only - Add upper bound to CID regex (prevents DoS via long strings) - Validate LOG_LEVEL env var against allowlist (prevents silent log suppression) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Code Review Complete — All Critical Issues FixedFixes Applied (commit
|
| Severity | Issue | Fix |
|---|---|---|
| CRITICAL | API key comparison vulnerable to timing attacks | crypto.timingSafeEqual() |
| CRITICAL | CSP allowed 'unsafe-eval' |
Removed from script-src |
| HIGH | GET /shield/:id unauthenticated (leaked owner data) |
Added requireApiKey |
| HIGH | Migration/stats endpoints unauthenticated | Added requireApiKey |
| HIGH | CORS regex matched ANY *.vercel.app subdomain |
Restricted to quantum-shield-nft* |
| HIGH | CID regex had no upper length bound | Added max {58,100} |
| MEDIUM | Invalid LOG_LEVEL silently suppressed all logs |
Added allowlist validation |
Review Status
- CodeRabbit AI review: Complete (3 critical, 4 high, 5 medium, 4 low found → 3 critical + 4 high + 1 medium fixed)
- Remaining medium/low items tracked for follow-up
@E-Fdz Ready for your review.
🤖 Generated with Claude Code
E-Fdz
left a comment
There was a problem hiding this comment.
/code-rabbit + Human in the loop
Summary
Comprehensive OWASP Top 10 security audit and remediation for the Quantum-Shield-NFT platform.
Changes (2 commits)
Commit 1: Launch Readiness Hardening
Commit 2: OWASP Audit Remediation
src/lib/logger.ts): Replaces 235+ rawconsole.logcalls with env-aware structured logging (JSON in production, human-readable in dev)server.js): All state-changing POST endpoints now require API key viapreHandlerserver.js): JSON schema validation on all POST routes withadditionalProperties: falseserver.js): Transfer endpoint verifiescurrentOwnermatches stored owner before allowing transferserver.ts): Replacedorigin: '*'wildcard with explicit domain whitelistIPFSService.ts): Regex-based CIDv0/CIDv1 format validation + gateway allowlist to prevent SSRFvercel.json): Changed from deprecated1; mode=blockto0(CSP replaces this header)OWASP Categories Addressed
Test plan
npm test)🤖 Generated with Claude Code