Why AI-built apps ship bare cookies
The default is set wherever the cookie is created, and AI scaffolding rarely sets it deliberately. A prompt like add login or set up Supabase auth produces a working session on the first try. The cookie is written, the user stays logged in, the app demos correctly. Nothing in that loop forces a decision about Secure, HttpOnly, or SameSite, so the framework or library default stands.
Several patterns push toward bare cookies specifically:
None of this is unique to one tool. It is the same pattern across AI-built apps: the cookie that makes login work is created, but the flags that protect it are never chosen.
- Hand-rolled session code. AI-generated Express or custom handlers often call a response cookie helper with just a name and value. Many helpers leave Secure and HttpOnly off unless you pass them explicitly, so the generated line ships without them.
- Local development assumptions. Code written and tested on http://localhost cannot use Secure (the browser drops Secure cookies on plain HTTP locally), so generated examples frequently omit it, and that omission rides straight to production.
- Magic-link and OTP flows. AI builds wire up passwordless auth quickly, but the redirect-and-set-session step is where session cookie flags belong, and the generated flow usually sets the session without specifying them.
- Library defaults that depend on config. Some auth libraries set sane flags only when they detect a production URL or an explicit secure setting. If the deploy config never tells the library it is in production, the cookie can be issued without Secure.
Read your own Set-Cookie headers
You can confirm every flag on your own app without any attack, from a clean browser session. Log in to your deployed app, open DevTools, go to the Network tab, and find the request that logs you in (often a call to a path like /auth, /login, /callback, or a Supabase auth endpoint). Click it and read the Response Headers. Every Set-Cookie line shows its flags in plain text.
You can also list the stored cookies directly: in DevTools open Application, then Cookies, and select your origin. The table shows columns for Secure, HttpOnly, SameSite, and Domain per cookie. Look specifically at the cookie that holds the session, not analytics or preference cookies.
Read each session cookie against this list:
One caveat on what you are reading. SameSite is enforced by the browser, so an older or unusual client may treat a blank SameSite differently. Setting the flag explicitly removes that ambiguity rather than relying on the current default.
- Secure present: safer result. Absent: suspicious for any cookie that authenticates the user, because it can travel over plain HTTP.
- HttpOnly present: safer result for a session token. Absent: suspicious, because page JavaScript can read it.
- SameSite is Lax or Strict: safer default for a same-site session cookie. SameSite=None set with Secure is a deliberate cross-site choice; SameSite=None without Secure is rejected by modern browsers, and a blank SameSite falls back to Lax in current browsers but is worth setting explicitly.
- Domain and Path scoped tightly: a cookie scoped to a broad parent domain is reachable by more subdomains than you may intend.
Set the flags where the cookie is created
The fix lives at the line that issues the cookie, and it is usually one option object. For a session or auth cookie, the safe baseline is Secure on, HttpOnly on, and SameSite set to Lax (or Strict if the session never needs to survive a cross-site top-level navigation). A typical Express-style cookie call takes options such as httpOnly true, secure true, and sameSite lax. In framework or library config, the equivalent is a cookie or session options block with the same three settings; many auth libraries expose a single cookieOptions or cookie setting for this. If you serve over HTTPS in production but develop on localhost, gate Secure on an is-production check so local login still works while production cookies stay Secure.
Be precise about what each flag does and does not cover:
If your session legitimately spans origins (a separate API domain, an embedded widget), SameSite=None with Secure is the correct combination, but it changes your CORS and cross-origin cookie story. That tradeoff is its own topic; see the note on SameSite=None and cross-origin cookies.
- HttpOnly stops document.cookie from reading the token. It does not stop XSS. A script with code execution on your page can still act as the user; HttpOnly only prevents it from exfiltrating the cookie value directly. Fixing the underlying XSS is a separate job.
- SameSite reduces cross-site request forgery by limiting when the cookie is sent. It is a browser-enforced control, not a CSRF token. For state-changing requests, a server-side anti-CSRF token or an origin check is still the authoritative defense, and SameSite=None reopens the cross-site path on purpose.
- Secure prevents the cookie from riding plain HTTP. It does not give you HTTPS; you still need TLS and an HTTP-to-HTTPS redirect at the host or edge so there is no cleartext hop in the first place.
Where VibeCodeGuard fits, and what it does not prove
VibeCodeGuard's Launch Check reads the Set-Cookie response headers your public surface sends and flags session cookies missing Secure, HttpOnly, or SameSite, with severity and fix direction. It reads what an outside visitor's browser would receive, so it needs no login and no code access, and it sits alongside the other response-header checks covered in security headers for AI-built apps. The clickjacking note covers the frame controls on the same header surface.
What it cannot do is confirm an exploit. A missing HttpOnly flag is a real weakening of your session defense, but the scan does not prove you have an XSS bug for it to combine with, and a missing SameSite does not prove a working CSRF chain. Those require code review and behavioral testing. The scan also cannot see cookies set only after a login it does not perform, or flags applied conditionally in code paths it never triggers.
Next step: log in to your own deployed app, read the Set-Cookie line on the auth response, and add any missing Secure, HttpOnly, or SameSite at the point the cookie is issued. Then run a focused Launch Check from a clean browser session before sharing the URL, so a bare session cookie shows up in your scan and not in someone else's.
A clean cookie-flag result on the public surface means the headers the scan saw carried the right flags. It does not prove every session cookie in every flow is set correctly, that your CSRF defense is complete, or that there is no XSS to contain. Treat a missing Secure or HttpOnly on a session cookie as a launch blocker, and treat a clean result as one signal, not a guarantee.
> launch check
Scan the public surface before launch.
Get severity, evidence, and practical fix guidance for the checks VibeCodeGuard can run from the outside.