WARP

No More Fear With Vercel — A Practical Website Security Guide for Vibe Coding Beginners

2026-02-25濱本 隆太

A practical breakdown of website security in a Vercel × Next.js environment. Covers WAF configuration, spam protection, API key management, and security headers — the full picture.

No More Fear With Vercel — A Practical Website Security Guide for Vibe Coding Beginners
シェア

Hello, this is Hamamoto from TIMEWELL. Today I want to cover something on the technical side.

"Vibe coding" has become a common phrase lately — using AI to build websites and apps even without deep programming experience. The combination of Next.js and Vercel has been spreading rapidly, especially among individual developers, thanks to how easy and high-performance it is.

But the thing that tends to get pushed to the back burner when building becomes this accessible is security. "It's a personal project, it's a small site" — let your guard down and it will cost you. When a data breach or site defacement happens, the developer bears the responsibility. User trust, once lost, takes an enormous amount of time to rebuild.

This article covers the security measures you absolutely need to have in place when building with Vercel — with concrete code examples. I've focused on the points that, from building client sites myself, I've come to feel are the non-negotiable minimum.

Why Security Matters in the First Place

"My site is small, so attackers won't bother targeting it." This thinking is the most dangerous.

The majority of modern cyberattacks don't target specific sites. Programs automatically scan the internet for vulnerable sites and launch attacks automatically. Site size is irrelevant — anything published on the internet is a potential target.

The threats individual developers are most likely to face:

Threat Type What Happens
Site defacement Your homepage gets rewritten. Phishing links may be embedded.
Form spam and bot attacks Your contact form floods with meaningless text and ads, burying legitimate inquiries
API key leakage An API key written into source code gets exposed and exploited by third parties — sometimes resulting in massive bills
DDoS attack Overwhelming traffic takes down the server, making the site unreachable

The direct damage is bad enough, but secondary damage is serious too. A defaced site destroys visitor trust. Dealing with spam consumes time you need for actual work. A personal data breach can lead to liability claims.

Security is a technical topic — but it's equally a business risk topic.

What Vercel Protects You With Out of the Box

Security might sound intimidating, but using Vercel already means a substantial amount of protection is handled automatically. Start by understanding these built-in benefits.

HTTPS/SSL Automation

Whether your site URL starts with https:// — that "s" stands for Secure, meaning communication between the browser and server is encrypted with SSL/TLS. It prevents third parties from eavesdropping or tampering with data, is a basic requirement, and affects Google search rankings.

Normally, obtaining and renewing SSL certificates takes effort. With Vercel, simply configuring a custom domain triggers free SSL certificate issuance and automatic renewal. You don't need to think about certificate management at all. This is a quietly valuable feature.

DDoS Protection

A DDoS attack overwhelms a target server with traffic from large numbers of computers, taking down the service. Even personal project sites can be targeted.

Vercel provides platform-wide DDoS protection as standard across all plans. Its globally distributed edge network detects abnormal traffic and blocks it automatically. No special configuration needed.

Data Encryption at Rest

Data stored on Vercel's infrastructure is encrypted with AES-256 — the encryption standard used by the US government. Even if data were physically stolen, decryption would be extremely difficult.

This infrastructure-level protection is what lets us focus on application development with confidence. But beyond this point, you enter the territory of "things that won't protect you unless you configure them yourself."

Looking for AI training and consulting?

Learn about WARP training programs and consulting services in our materials.

Mastering Vercel Firewall

In addition to Vercel's standard DDoS protection, the Vercel Firewall — specifically its WAF (Web Application Firewall) capabilities — lets you build a second layer of defense.

If the standard DDoS protection is an army guarding the national border, the WAF is a security guard standing at the door to your building. You decide who to let in and who to turn away, with fine-grained rules of your own.

WAF is available on all plans. In the dashboard, navigate to Your Project → Settings → Firewall to open the settings. Four capabilities to know about:

IP Blocking

Completely blocks access from specific IP addresses. If you're seeing your access logs and the same IP is making repeated login attempts, you can block that IP by name.

The Country Blocking feature also enables blocking by country. Useful when your service is Japan-focused but you're seeing large volumes of overseas spam.

Custom Rules

More flexible access control than IP blocking. Define "if this condition is met, take this action" rules of your own choosing.

For example: restrict access to the admin panel (/admin, etc.) to only your home or office IP. Block access from User-Agents used by specific attack tools. Custom rules are where these fine-grained adjustments become possible.

Managed Rule Sets

"Creating rules myself sounds hard" — don't worry. Vercel's security team has created and maintains a pre-built rule collection.

Rules covering well-known attack patterns like SQL injection and XSS (cross-site scripting) are bundled together. Enable them in the dashboard and you're done. Honestly, there's no reason not to enable these.

Attack Challenge Mode

Rather than a binary allow/block decision for every visitor, this feature issues a JavaScript challenge to traffic that's "a bit suspicious but not conclusive." Reduces the risk of mistakenly blocking legitimate users while effectively filtering out bots.

Start by opening the dashboard and browsing what settings are available. Hands-on, it's simpler than it looks.

Three Weapons for Protecting Forms from Spam

Once you publish a website, your contact form becoming a spam target is almost unavoidable. Bots flood it with ads and meaningless strings.

In the past, the standard approach was "I'm not a robot" checkboxes or distorted image CAPTCHAs — but those are nothing but friction for users. Having someone abandon a form mid-completion because it became a nuisance is completely self-defeating.

Now, the mainstream approach is to filter bots intelligently on the backend without requiring any user action. Three tools available in a Next.js + Vercel environment:

Honeypot

True to its name, a "honey trap" for bots. The mechanism is simple: plant an invisible dummy input field in the form.

Humans don't fill in what they can't see. But bots programmatically search for all fields in a form and dutifully try to fill them all. So if the invisible field has a value, "this is a bot" is the conclusion.

An old-school technique, but easy to implement and effective against simple bots. This is the first line of defense you want in place from the start.

Add a dummy field to the form component and use CSS to push it off-screen so it's invisible.

// components/ContactForm.jsx

<form action={...}>
  {/* Normal input fields */}

  {/* Honeypot: hidden with CSS */}
  <div className="hidden" aria-hidden="true">
    <label htmlFor="honeypot">Leave this field empty</label>
    <input type="text" id="honeypot" name="honeypot" tabIndex={-1} autoComplete="off" />
  </div>

  <button type="submit">Submit</button>
</form>

/* global.css */
.hidden {
  position: absolute;
  left: -5000px;
  opacity: 0;
}

On the server side, check whether this field has a value:

// app/actions.js
'use server';

export async function submitForm(formData) {
  // Honeypot check
  if (formData.get('honeypot')) {
    // Identified as bot. Return as if successful without doing anything
    return { success: true };
  }

  // Continue processing as a human request
}

The key: when identified as a bot, don't return an error. Returning an error tells the bot side that this defense is in place.

Vercel BotID

Honeypot handles simple bots, but smarter bots that interpret CSS and only fill visible fields also exist. That's where Vercel's proprietary BotID comes in.

BotID is an "invisible CAPTCHA" that requires absolutely no action from users. Running in the background, it uses machine learning to analyze thousands of signals — mouse movements, keyboard patterns, browser environment — and determines human vs. bot.

Two levels are available: Basic, which is free and provides challenge verification; and Deep Analysis, which is paid but can counter advanced bots using Playwright or Puppeteer.

In the dashboard, enable BotID Deep Analysis under Firewall → Rules, then call checkBotId() in your server-side code:

// app/actions.js
'use server';

import { checkBotId } from '@vercel/bot-id';

export async function submitForm(formData) {
  try {
    await checkBotId();
  } catch (error) {
    // Identified as a bot
    console.error('Bot detected:', error);
    return { success: false, message: 'Bot detection failed.' };
  }

  // Continue processing as a human request
}

Google reCAPTCHA v3

The third option is Google's reCAPTCHA v3 — completely different from v2's checkbox approach, and v3 also requires zero user interaction.

reCAPTCHA v3 analyzes user behavior as they navigate the site and assigns a score from 0.0 (likely a bot) to 1.0 (likely human) indicating how human-like the request is. Retrieve this score at form submission and set a threshold like "below 0.5, treat as a bot" — a flexible approach.

The google-recaptcha-v3 library makes implementation convenient.

First, obtain a site key and secret key from Google and set them as environment variables. NEXT_PUBLIC_RECAPTCHA_V3_SITE_KEY is used on the client side; RECAPTCHA_V3_SECRET_KEY on the server side.

On the frontend, obtain a token when the form is submitted:

// components/ContactForm.jsx
import { GoogleReCaptchaProvider, useGoogleReCaptcha } from 'google-recaptcha-v3';

const FormComponent = () => {
  const { executeRecaptcha } = useGoogleReCaptcha();

  const handleSubmit = async (event) => {
    event.preventDefault();
    if (!executeRecaptcha) return;

    const token = await executeRecaptcha('contactForm');
    // Pass form data and token to the Server Action
  };

  return <form onSubmit={handleSubmit}>...</form>;
}

const ContactForm = () => (
  <GoogleReCaptchaProvider reCaptchaKey={process.env.NEXT_PUBLIC_RECAPTCHA_V3_SITE_KEY}>
    <FormComponent />
  </GoogleReCaptchaProvider>
);

On the backend, send the received token to Google's API and verify the score:

// app/actions.js
'use server';

export async function submitForm(formData, token) {
  const response = await fetch(
    `https://www.google.com/recaptcha/api/siteverify?secret=${process.env.RECAPTCHA_V3_SECRET_KEY}&response=${token}`,
    { method: 'POST' }
  );
  const data = await response.json();

  if (!data.success || data.score < 0.5) {
    return { success: false, message: 'Bot detection failed.' };
  }

  // Continue processing as a human request
}

Personally, I consider all three to be the ideal setup. Honeypot filters crude bots, BotID catches mid-level bots, and reCAPTCHA v3 handles sophisticated ones. Defense in depth. Adding all three is invisible to users, so there's zero UX impact. No reason not to.

Where Do You Hide API Keys? Proper Environment Variable Management

Whenever vibe coding involves integrating external services, API keys inevitably appear. Databases, AI services, email sending services — all accessed using an API key, a "secret key" for that service.

If that API key leaks, third parties can impersonate you and misuse the service. Data theft, floods of requests driving up enormous bills — the most common individual developer security incidents involve exactly this kind of accidental leakage.

Hard-Coding Into Source Code Is Absolutely Not Okay

The worst thing you can do is write API keys directly into code. This is called hard-coding.

// Never do this
const apiKey = 'sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx';

// Push this code to GitHub and... the API key is publicly visible to the entire world

Even if your GitHub repository is private, hard-coding should be avoided whenever there's any possibility of sharing code with others. Manage API keys using environment variables.

How to Set Up Environment Variables

An environment variable is a configuration value stored in the application's execution environment, separate from the code itself. The code references the "name" of the environment variable, not the API key itself.

During local development, create a .env.local file at the project root and write your API keys there.

# .env.local
DATABASE_URL="postgres://..."
OPENAI_API_KEY="sk_..."

The one thing you absolutely cannot forget: exclude .env.local from Git management. Verify that .env.local is in the .gitignore file. If you created the Next.js project with create-next-app, it's included by default — but get into the habit of visually confirming this.

In Vercel's production environment, navigate to Settings → Environment Variables in the dashboard and register the same names and values there. This lets you handle API keys safely in both local and production environments without changing any code.

The NEXT_PUBLIC_ Prefix Trap

This is the most dangerous pitfall.

In Next.js, environment variables beginning with NEXT_PUBLIC_ are embedded into client-side JavaScript and become visible to anyone through the browser developer tools.

This is designed for values that are meant to be public — like a Google Analytics tracking ID — but the number of people who don't know this and accidentally add NEXT_PUBLIC_ to API keys never seems to go down.

Variable Type Visible To Example Uses
DATABASE_URL Server side only Database connection strings, API keys, anything that must stay secret
NEXT_PUBLIC_GA_ID Published to the browser too Google Analytics ID and other information that's safe to be public

Never add NEXT_PUBLIC_ to anything that must remain secret. This is a rule to internalize at the very start of vibe coding.

Taking Defense One Step Further With Security Headers

On top of all of the above, for one more layer of protection: security headers. These are HTTP headers added to server responses that activate browser security features to prevent specific attacks.

In Next.js, writing in next.config.js adds headers to every page's response:

// next.config.js

const securityHeaders = [
  {
    key: 'X-Content-Type-Options',
    value: 'nosniff'
  },
  {
    key: 'X-Frame-Options',
    value: 'SAMEORIGIN'
  },
  {
    key: 'Strict-Transport-Security',
    value: 'max-age=63072000; includeSubDomains; preload'
  }
];

module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: securityHeaders,
      },
    ];
  },
};

A brief explanation of what each header protects:

Content-Security-Policy (CSP)

A powerful defense against XSS attacks. Lets you strictly specify which domains can serve resources the page is allowed to load. Scripts from domains not on the allowlist get blocked by the browser — so even if a malicious script gets injected, it can't execute.

A note: starting with CSP set too restrictively can accidentally block your own site's Google Fonts or Analytics scripts. A realistic approach is to start in report-only mode, confirm there are no unintended blocks, and then tighten gradually.

X-Frame-Options

Prevents your site from being embedded in another site's iframe. Protection against "clickjacking" — where a malicious site covers your site with a transparent iframe and tricks users into clicking buttons they didn't mean to. Setting SAMEORIGIN allows embedding only from within your own site.

X-Content-Type-Options

Setting nosniff prevents browsers from ignoring server instructions and guessing a file's format on their own (MIME sniffing). Guards against attacks that would cause a text file to be mistakenly executed as a script.

Strict-Transport-Security (HSTS)

Instructs browsers to force HTTPS connections for any user who has previously accessed the site via HTTPS. Even if a user accidentally navigates to http://, unencrypted communication doesn't happen.

These headers work automatically once set, making them a high-value-per-effort measure.

Pre-Launch Security Checklist

Everything covered in this article, organized as a final check before publishing your site. Work through it one by one to send your website into the world with confidence.

Vercel Firewall / WAF

  • Have you enabled Managed Rulesets? (Settings → Firewall → Managed Rulesets)
  • Have you set up blocking for suspicious IPs or countries? (IP Blocking / Country Blocking)
  • Have you restricted access to specific paths (like the admin panel) by IP? (Custom Rules)

Form Spam and Bot Protection

  • Have you implemented a Honeypot (invisible input field) in the form?
  • Does the server-side logic abort processing when the Honeypot field has a value?
  • Have you enabled Vercel BotID and called checkBotId() server-side?
  • Have you implemented Google reCAPTCHA v3 and verified the score server-side?

Sensitive Information Management

  • Have you avoided writing API keys or database connection strings directly into source code?
  • Are all sensitive values managed in the .env.local file?
  • Have you confirmed that .env.local is in the .gitignore file?
  • Have you set all production environment variables in the Vercel dashboard?
  • Have you reviewed all environment variables to confirm no secret API keys have the NEXT_PUBLIC_ prefix?

Security Headers

  • Have you configured security headers (X-Content-Type-Options, X-Frame-Options, HSTS) in next.config.js?
  • Have you considered introducing Content-Security-Policy (CSP), at least in report-only mode?

Dependency Management

  • Have you run npm audit or yarn audit to check for known vulnerabilities in your packages?
  • Have you addressed any discovered vulnerabilities through package updates or other means?

I hope this checklist serves as a useful reference in your development process.

Security Is Not "Set It and Forget It"

This article has covered security in a Vercel environment from six angles.

Vercel's standard protections, Firewall (WAF) access control, layered bot defense with Honeypot / BotID / reCAPTCHA v3, sensitive information management with environment variables, and browser-level defense with security headers. None of these are difficult to configure on their own.

That said — honestly — security configuration is not something you do once and finish. New vulnerabilities are discovered every day, and attack methods keep evolving. The right posture is to regularly check the official documentation of the frameworks and services you use and keep your knowledge current.

If you have concerns about technology selection or security architecture, please consider TIMEWELL's WARP program. Former DX and data strategy specialists from major enterprises provide monthly support for building and operating sites using modern tech stacks including Vercel + Next.js — covering everything from security design through implementation.

There's no need to aim for perfection from day one. Start by putting in the basic measures covered in this article one by one, and your site's security will improve in a concrete, measurable way. A secure website is the foundation of trust with your users. Start with what you can do today, and enjoy vibe coding with confidence.

Considering AI adoption for your organization?

Our DX and data strategy experts will design the optimal AI adoption plan for your business. First consultation is free.

Share this article if you found it useful

シェア

Newsletter

Get the latest AI and DX insights delivered weekly

Your email will only be used for newsletter delivery.

無料診断ツール

あなたのAIリテラシー、診断してみませんか?

5分で分かるAIリテラシー診断。活用レベルからセキュリティ意識まで、7つの観点で評価します。

Learn More About WARP

Discover the features and case studies for WARP.