Laptop, security shield and review checklist illustrating the security checks needed for an AI-generated website
Website quality, SEO and AI

AI-Generated Website Security: The Mistakes You Need to Catch

A defensive checklist for reviewing AI-generated website code, including secrets, browser boundaries, forms, permissions, dependencies and deployment.

By 8 min read

Treat AI-generated website code as untrusted until it has been reviewed and tested. Check first for exposed secrets, privileged actions running in the browser, missing authorisation, weak input and upload handling, unnecessary dependencies and unsafe deployment settings. A site that works in a demo has not yet proved that it is safe to publish.

This is not an argument against AI coding tools. They can remove repetitive work and help a developer explore an approach quickly. The danger is their ability to produce code that looks complete while silently crossing a security boundary.

Start with a simple threat model

Classify what the site protects and who may act

Before reviewing individual files, write down what the website protects and who may try to misuse it. A brochure site with a contact form has a smaller attack surface than an account portal connected to payments and customer records.

Identify:

  • public information that anybody may read;

  • personal or commercial data that must remain private;

  • actions available to signed-out visitors, customers, staff and administrators;

  • external systems such as payment, email and database providers;

  • files that users can upload;

  • credentials that allow the application or deployment pipeline to act.

Turn the map into denied-case tests

This map turns “make it secure” into testable questions. Can one customer request another customer’s record? Can a public form trigger unlimited expensive work? Can a browser obtain a key that bypasses database controls?

A senior developer reviewing code, deployment permissions and a physical security checklist
Review the exact permissions and deployment path. A polished interface says nothing about who can call the underlying action.

Do not confuse environment variables with secrecy

Public configuration carries no privileged authority

An environment variable is only secret if it remains inside a trusted server or deployment service. Frontend build tools deliberately copy selected variables into browser code. Vite’s environment documentation warns that variables prefixed with VITE_ are exposed in the client bundle.

That is appropriate for public configuration such as a site URL or a publishable API key designed to work with server-enforced permissions. It is catastrophic for a database password, payment secret or administrative service key.

The rule is straightforward:

  • Public configuration may enter the browser and must carry no authority by itself.

  • Secrets stay in server functions, workers or a secrets manager and never appear in generated HTML, JavaScript, source maps, URLs or logs.

For a concrete example, Supabase distinguishes publishable and secret keys. A publishable key can be used in a browser when Row Level Security and least-privilege grants protect the data. A secret or legacy service-role key bypasses those controls and must remain server-side.

Search the output as well as the source

Search the built site, not only the source repository. A value excluded from Git can still be embedded by the build step. If a real secret has appeared in a browser bundle or public repository, assume it is compromised.

Keep authority on the server

Authentication is not authorisation

Browser code runs on a visitor’s machine. They can inspect it, change it and send requests without using your interface. Hiding a button or validating a form in React improves usability; it does not enforce permission.

The server must independently verify identity, authorisation and input for every protected action. Payment amounts, ownership checks, role changes, publication commands and access to private records should never rely on a value the browser can alter.

Authentication answers “who is this?” Authorisation answers “may this person do this to this record?” OWASP’s authorisation guidance recommends least privilege, deny by default and permission checks on every request.

Test the cases that must be denied

Test signed out, wrong owner, lower role, expired session and guessed record identifiers. Do not test only the successful path.

For database-backed browser apps, enforce the same boundary in the data layer. Supabase’s Row Level Security guidance explains that grants decide which operations a role may attempt and policies decide which rows it may reach. Both need tests; a policy that is too permissive may fail silently by returning data it should have withheld.

Validate forms where the data is processed

Check syntax, meaning and cost

Client-side validation gives fast feedback, but a malicious or broken client can bypass it. Validate the request again in the server function or database command that performs the action.

Check syntax and meaning. An email field should be structurally plausible; a booking end date should also follow the start date. Apply length and size limits before expensive work. Collect only the data the business needs, protect it in transit and avoid writing personal data into general application logs.

Control abuse and repeat requests

Public forms also need abuse controls appropriate to their effect: rate limits, bot filtering, idempotency for repeat submissions and safe failure messages. Error responses should help a legitimate user without exposing stack traces, SQL details or environment values.

The OWASP input-validation guide treats all externally supplied data as untrusted. That includes feeds and partner systems, as well as text typed by an anonymous visitor.

File uploads need their own security design

Quarantine, inspect and promote

An upload feature is not an ordinary text field. Restrict accepted types and sizes, generate storage names, inspect the real file rather than trusting its declared content type and keep unreviewed objects away from public delivery.

OWASP’s file-upload checklist recommends allowlisted extensions, content validation, application-generated filenames, authorisation and storage outside the web root where possible. Images can be decoded and re-encoded to prove they are valid and strip unwanted data.

A credible workflow is quarantine, inspect, promote. The public site should only receive the reviewed derivative, not the original object simply because its filename ends in .jpg.

Illustration of image files moving from a private quarantine through inspection to a public derivative
Only the inspected derivative moves into public delivery; the original upload remains outside the public website.

Review generated dependencies

Prefer removing unnecessary code to maintaining it forever

AI tools often solve a small problem by installing another package. Every dependency expands the software supply chain, adds update work and may execute during installation or build.

Ask whether the package is needed, maintained and appropriate for the runtime. Commit the lockfile, run the ecosystem’s vulnerability checks and review major updates rather than accepting them automatically. The NCSC’s secure-development guidance recommends peer review and explicit consideration of external-dependency history.

Removing an unnecessary dependency is often a better security fix than configuring it perfectly.

Watch for unsafe HTML and permissive browser policies

Rich text needs a narrow, trusted renderer

Generated interfaces sometimes render stored content as raw HTML or interpolate data into scripts. If untrusted input reaches those sinks without strict sanitisation, cross-site scripting can execute in another user’s session.

Prefer framework text rendering, which escapes content by default. Where rich text is genuinely required, use a narrow allowlist for supported elements and attributes, reject scripts and event handlers, and render through a trusted pipeline. Add a Content Security Policy as defence in depth, not as permission to keep unsafe rendering.

CORS is not an authentication system

CORS controls which browser pages can read a response; it does not prove that the requester is an authorised user. Avoid a wildcard configuration on endpoints that handle credentials or private data.

Check the deployment, not only the code

Test the real deployed boundary

Security can change between a local preview and production. Review the exact build command, deployed functions, environment scopes, redirects, headers and public files.

Before launch:

  • force HTTPS and remove mixed-content requests;

  • separate preview and production credentials;

  • ensure error pages and logs do not reveal internals;

  • disable test endpoints, setup tokens and temporary import routes;

  • confirm backups and a recovery procedure exist;

  • run dependency, secret and static checks in continuous integration;

  • require review before a deployment reaches the live domain;

  • test protected operations against the deployed environment.

The NCSC recommends small, reviewable changes and peer review inside the deployment pipeline. AI speed makes that discipline more important: a large generated diff is difficult for a human to understand and easy to approve superficially.

What to do if a secret has already leaked

Rotate first, then close the path

Do not merely delete the line and redeploy. Revoke or rotate the credential at its provider, replace it everywhere it is legitimately used and check access logs for unexpected activity. Remove the value from build artefacts and repository history where appropriate, but assume copies may remain.

OWASP’s secrets-management guidance treats rotation, access control and auditability as part of the secret lifecycle. Record the incident and close the path that caused it, such as an unsafe frontend prefix or verbose build log, before issuing the replacement.

A pre-deployment AI website security review

An AI-assisted site is not ready until you can answer yes to these checks:

  • All browser-visible configuration has been classified as public.

  • No privileged key appears in source, Git history, build output, source maps or logs.

  • Every protected server action authenticates and authorises the request.

  • Database grants and row policies have positive and negative tests.

  • Forms are validated server-side and have proportionate abuse controls.

  • Rich text is allowlisted and user content cannot introduce executable markup.

  • Uploads are restricted, inspected and kept private until approved.

  • Dependencies are necessary, locked, scanned and maintained.

  • Preview and production environments use separate, correctly scoped configuration.

  • Recovery, rotation and rollback procedures have been rehearsed.

If the site handles payments, health data, significant personal information or business-critical workflows, obtain specialist security review. A checklist catches common errors; it is not a penetration test or certification.

How this applies to Elkwood

Elkwood’s public marketing and editorial pages are generated as static output wherever possible, reducing the amount of live application code exposed to visitors. Customer accounts, payments and editorial administration remain separate protected systems with narrow server-side responsibilities.

That architecture reduces attack surface but does not eliminate security work. We still test permissions, keep privileged credentials server-side and treat uploads as untrusted until reviewed. The public what’s included page explains the managed service, while pricing sets the commercial scope. We do not claim that a £25 brochure-site service replaces specialist engineering for a complex application.

Sources checked

Quick answers

Frequently asked questions

Is AI-generated code secure?

It can be, but generation is not evidence of security. Treat the output as untrusted code, review the trust boundaries and test both allowed and denied behaviour before deployment.

Can I put an API key in frontend code?

Only if the provider explicitly defines it as publishable and the backend enforces all real permissions. Secret, administrative and service role keys must never enter browser code.

What should go in environment variables?

Configuration belongs there, but only server scoped variables protect secrets. Any variable copied into a frontend build is public regardless of the .env filename.

How do I secure website forms?

Validate on the server, limit size and frequency, encode output safely, minimise collected data and prevent repeat requests from triggering duplicate or expensive actions.

Should AI code be reviewed before deployment?

Yes. Review it in small changes, test security boundaries and inspect the actual production build. A functioning preview can hide exposed credentials or missing denied case checks.

What if a secret has already been exposed?

Revoke or rotate it immediately, update legitimate consumers, inspect access logs and remove it from public artefacts. Deleting the visible line alone does not make the old credential safe.

Related reading