Skip to content

Conversation

@Addy-shetty
Copy link
Owner

No description provided.

- Create PricingPage with 3 tier plans (Starter/Pro/Ultimate)
- Add animated pricing cards with hover effects
- Include FAQ section and trust indicators
- Add CreditDisplay component in navbar
- Show credit count with low credit warning
- Add pricing link to navigation
- Match existing app theme and animations
- Responsive design for all devices
- Add refundCredit function to useCredits hook
- Add decrementAnonymousGeneration for anonymous users
- Create refund_credit database function
- Wrap generation in try-catch to refund on failure
- Show toast notification when credit is refunded
- Fix CreditDisplay to use credits.creditsRemaining
- Ensure credits only deducted on successful generation
Copilot AI review requested due to automatic review settings January 6, 2026 05:23
@vercel
Copy link

vercel bot commented Jan 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
vibe-prompting Ready Ready Preview, Comment Jan 6, 2026 5:27am

@github-advanced-security
Copy link

This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation.

Comment on lines 10 to +33
return input
.trim()
.replace(/[<>]/g, '') // Remove < and >
.replace(/javascript:/gi, '') // Remove javascript: protocol
.replace(/on\w+\s*=/gi, '') // Remove event handlers
// Remove HTML tags
.replace(/<\/?[^>]+(>|$)/g, '')
// Remove javascript: protocol
.replace(/javascript:/gi, '')
// Remove data: protocol (can be used for XSS)
.replace(/data:text\/html/gi, '')
// Remove event handlers
.replace(/on\w+\s*=/gi, '')

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
on
, which may cause an HTML attribute injection vulnerability.

Copilot Autofix

AI 4 days ago

In general, to fix incomplete multi-character sanitization you either (1) switch to a dedicated, well-tested sanitization library, or (2) transform the sanitization so that multi-character patterns cannot reappear after a single pass—e.g., by iterating replacements until the string stabilizes (no further changes) or by replacing with single-character-based patterns. Given the current code and the requirement not to change external behavior drastically, the least intrusive fix is to make the existing sanitization loop until no further replacements are applied.

Concretely, we will refactor sanitizeInput to:

  • Perform the same sequence of .replace(...) operations inside a loop.
  • Re-run that sequence until the string stops changing (fixed point).
  • Preserve the existing trimming and length limiting semantics.

To avoid unnecessary computation, we’ll apply .trim() once at the beginning, then loop over the dangerous-pattern replacements, and finally apply .slice(0, 10000) after the loop. This preserves observable behavior except that inputs which previously might leave behind regenerated "on..." or other multi-pattern combinations will now be fully cleaned. All changes are within src/lib/security.ts in the sanitizeInput function; no new imports or helper methods are required.

Suggested changeset 1
src/lib/security.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/security.ts b/src/lib/security.ts
--- a/src/lib/security.ts
+++ b/src/lib/security.ts
@@ -20,21 +20,28 @@
  */
 export function sanitizeInput(input: string): string {
   if (!input || typeof input !== 'string') return ''
-  
-  return input
-    .trim()
-    // Remove HTML tags
-    .replace(/<\/?[^>]+(>|$)/g, '')
-    // Remove javascript: protocol
-    .replace(/javascript:/gi, '')
-    // Remove data: protocol (can be used for XSS)
-    .replace(/data:text\/html/gi, '')
-    // Remove event handlers
-    .replace(/on\w+\s*=/gi, '')
-    // Remove null bytes
-    .replace(/\0/g, '')
-    // Limit to reasonable length
-    .slice(0, 10000)
+
+  let sanitized = input.trim()
+  let previous: string
+
+  // Apply replacements repeatedly until no further changes occur
+  do {
+    previous = sanitized
+    sanitized = sanitized
+      // Remove HTML tags
+      .replace(/<\/?[^>]+(>|$)/g, '')
+      // Remove javascript: protocol
+      .replace(/javascript:/gi, '')
+      // Remove data: protocol (can be used for XSS)
+      .replace(/data:text\/html/gi, '')
+      // Remove event handlers
+      .replace(/on\w+\s*=/gi, '')
+      // Remove null bytes
+      .replace(/\0/g, '')
+  } while (sanitized !== previous)
+
+  // Limit to reasonable length
+  return sanitized.slice(0, 10000)
 }
 
 /**
EOF
@@ -20,21 +20,28 @@
*/
export function sanitizeInput(input: string): string {
if (!input || typeof input !== 'string') return ''

return input
.trim()
// Remove HTML tags
.replace(/<\/?[^>]+(>|$)/g, '')
// Remove javascript: protocol
.replace(/javascript:/gi, '')
// Remove data: protocol (can be used for XSS)
.replace(/data:text\/html/gi, '')
// Remove event handlers
.replace(/on\w+\s*=/gi, '')
// Remove null bytes
.replace(/\0/g, '')
// Limit to reasonable length
.slice(0, 10000)

let sanitized = input.trim()
let previous: string

// Apply replacements repeatedly until no further changes occur
do {
previous = sanitized
sanitized = sanitized
// Remove HTML tags
.replace(/<\/?[^>]+(>|$)/g, '')
// Remove javascript: protocol
.replace(/javascript:/gi, '')
// Remove data: protocol (can be used for XSS)
.replace(/data:text\/html/gi, '')
// Remove event handlers
.replace(/on\w+\s*=/gi, '')
// Remove null bytes
.replace(/\0/g, '')
} while (sanitized !== previous)

// Limit to reasonable length
return sanitized.slice(0, 10000)
}

/**
Copilot is powered by AI and may make mistakes. Always verify output.
@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 6, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
7 Security Hotspots
6.5% Duplication on New Code (required ≤ 3%)
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a comprehensive "Development" update to the Vibe Prompting application, transforming it into a production-ready AI prompt generation platform with significant enhancements to security, architecture, and user experience.

Key Changes:

  • Security Hardening: Implements v2 atomic credit system, CSRF protection, session management, rate limiting, and security headers
  • Database Migration: Consolidates schema with new v2 security system, request logging, rate limiting tables, and feedback collection
  • UI Overhaul: Complete redesign with Neo-Brutalist aesthetic, replacing previous theme with bold borders, shadows, and vibrant colors
  • Backend Refactoring: New Edge Functions architecture with fallback mechanisms, improved error handling, and secure credit consumption

Reviewed changes

Copilot reviewed 58 out of 61 changed files in this pull request and generated 20 comments.

Show a summary per file
File Description
vite.config.ts Adds production optimizations: Terser minification, console removal, code splitting for vendor bundles, explicit dev/preview ports
vercel.json Implements comprehensive security headers including CSP, X-Frame-Options, and permissions policies
tailwind.config.cjs Extends theme with Neo-Brutalist color palette, custom shadows, animations, and typography
supabase/migrations/* Consolidates and updates database schema with v2 atomic credit system, RLS policies, and helper functions
supabase/functions/* New get-provider-info endpoint and completely rewritten generate-prompt with validation and credit checks
src/pages/* Redesigned pages with Neo-Brutalist styling; adds new DashboardPage, ExplorePage, PricingPage; replaces GeneratePromptPage
src/lib/* New security utilities (CSRF, session management), refactored Supabase client, API layer with fallback logic
src/hooks/* Replaces useCredits with useCreditsSecure for read-only credit fetching with real-time updates
src/components/* Updated Navbar with credit display and feedback modal; redesigned UI components with Neo-Brutalist theme
src/styles/index.css Complete CSS overhaul with Neo-Brutalist design system, custom utility classes, and Google Fonts integration
package.json Updates Vite to v7.2.2 and adds Terser for minification

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +69 to +75
// Check honeypot field using native form elements
const form = document.querySelector('form')
const honeypot = form?.querySelector('input[name="honeypot_website"]') as HTMLInputElement
if (honeypot?.value) {
console.warn('Bot detected - honeypot field filled')
return
}
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The honeypot field check uses DOM manipulation which is fragile and can be bypassed. The field is checked using document.querySelector('form') which could select the wrong form if multiple forms exist on the page. Instead, use React refs or pass the honeypot value through the form's controlled state to ensure you're checking the correct field value.

Copilot uses AI. Check for mistakes.
minify: 'terser',
terserOptions: {
compress: {
drop_console: mode === 'production', // Remove console.log in production
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition mode === 'production' for dropping console statements should be more specific. This will only work if you explicitly set NODE_ENV or pass --mode production. Consider also checking for 'build' mode or using process.env.NODE_ENV === 'production' to ensure console logs are consistently removed in production builds.

Copilot uses AI. Check for mistakes.
},
{
"key": "Content-Security-Policy",
"value": "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://*.supabase.co https://generativelanguage.googleapis.com https://openrouter.ai https://va.vercel-scripts.com; frame-ancestors 'none';"
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CSP 'unsafe-inline' and 'unsafe-eval' directives for script-src significantly weaken the Content Security Policy and expose the application to XSS attacks. Consider using nonces or hashes for inline scripts instead, and avoid eval-based operations. If these are truly necessary, document why they're required and what mitigations are in place.

Copilot uses AI. Check for mistakes.
Comment on lines +87 to +98
CREATE POLICY "profiles_update_policy"
ON profiles FOR UPDATE
USING (auth.uid() = id)
WITH CHECK (
auth.uid() = id
AND (
-- Allow if credits haven't changed
credits = (SELECT credits FROM profiles WHERE id = auth.uid())
-- Or if service role (for RPC functions)
OR auth.jwt()->>'role' = 'service_role'
)
);
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RLS policy for profiles_update_policy allows users to bypass credit deduction constraints by checking auth.jwt()->>'role' = 'service_role'. However, this JWT claim can potentially be manipulated on the client side. The service role check should only be used server-side with proper authentication. This could allow users to grant themselves unlimited credits.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +20
CREATE TABLE IF NOT EXISTS public.profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
username TEXT UNIQUE,
full_name TEXT,
avatar_url TEXT,
bio TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing email field in the profiles table schema. Line 139 in handle_new_user() references NEW.email when inserting into profiles, but the CREATE TABLE statement for profiles (lines 12-20) doesn't include an email column. This will cause the trigger to fail when new users sign up.

Copilot uses AI. Check for mistakes.
'General Development': Code,
}

const CATEGORY_COLORS: Record<string, string> = {
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable CATEGORY_COLORS.

Copilot uses AI. Check for mistakes.

export default function ExplorePage() {
const { theme } = useTheme()
const { user } = useAuth()
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable user.

Copilot uses AI. Check for mistakes.
export default function ExplorePage() {
const { theme } = useTheme()
const { user } = useAuth()
const navigate = useNavigate()
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable navigate.

Copilot uses AI. Check for mistakes.
import { useAuth } from '@/context/AuthContext'
import { useNavigate } from 'react-router-dom'
import { useCredits } from '@/hooks/useCredits'
import { useCredits } from '@/hooks/useCreditsSecure'
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import useCredits.

Copilot uses AI. Check for mistakes.
Comment on lines +104 to +175
CREATE OR REPLACE FUNCTION consume_user_credits(
p_user_id UUID,
p_credits_to_consume INTEGER,
p_request_id TEXT,
p_action TEXT DEFAULT 'generate_prompt',
p_metadata JSONB DEFAULT '{}'
)
RETURNS JSONB
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
v_current_credits INTEGER;
v_new_credits INTEGER;
v_tier TEXT;
BEGIN
-- Check for duplicate request (idempotency)
IF EXISTS (SELECT 1 FROM request_log WHERE request_id = p_request_id) THEN
RETURN jsonb_build_object(
'success', false,
'error', 'duplicate_request',
'message', 'This request has already been processed'
);
END IF;

-- Lock the user's row and get current credits
SELECT credits, tier INTO v_current_credits, v_tier
FROM profiles
WHERE id = p_user_id
FOR UPDATE; -- Critical: prevents race conditions

-- Check if user exists
IF NOT FOUND THEN
RETURN jsonb_build_object(
'success', false,
'error', 'user_not_found',
'message', 'User profile not found'
);
END IF;

-- Check sufficient credits
IF v_current_credits < p_credits_to_consume THEN
RETURN jsonb_build_object(
'success', false,
'error', 'insufficient_credits',
'message', 'Not enough credits',
'current_credits', v_current_credits,
'required_credits', p_credits_to_consume
);
END IF;

-- Deduct credits
v_new_credits := v_current_credits - p_credits_to_consume;

UPDATE profiles
SET credits = v_new_credits,
updated_at = NOW()
WHERE id = p_user_id;

-- Log the transaction
INSERT INTO request_log (user_id, request_id, action, credits_consumed, metadata)
VALUES (p_user_id, p_request_id, p_action, p_credits_to_consume, p_metadata);

-- Return success
RETURN jsonb_build_object(
'success', true,
'credits_consumed', p_credits_to_consume,
'credits_remaining', v_new_credits,
'tier', v_tier
);
END;
$$;
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The consume_user_credits function is defined as SECURITY DEFINER and takes a caller-supplied p_user_id and p_credits_to_consume without verifying that p_user_id matches auth.uid() or that the credit amount is positive. Because this function runs with elevated privileges and is callable by regular authenticated clients (see the GRANT below), an attacker who knows another user's UUID can deduct or even add credits to any account by passing another user's ID or a negative p_credits_to_consume. This breaks tenant isolation for the credit system; restrict this function to operating only on auth.uid() and enforce a strictly positive credit amount before updating profiles.credits.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants