security: penetration test fixes — headers, cors, path traversal, info leakage

- Switch to http_serve_v2/http_set_handler_v2 so request headers are available
  to El handler code (prerequisite for all header-based security checks)

- Stripe webhook (CVE-class): add HMAC-SHA256 signature verification against
  Stripe-Signature header using STRIPE_WEBHOOK_SECRET env var. Previously any
  unauthenticated POST could forge a payment_intent.succeeded event and
  increment the founding counter or trigger Supabase account provisioning for
  arbitrary emails.

- CORS on /api/supabase-config: restrict to neurontechnologies.ai and localhost
  origins only. Cross-origin requests now get 403.

- /api/soul-health: require X-Internal: true header; otherwise return 404.
  Endpoint was publicly accessible and leaked internal soul service URL,
  network topology, and raw probe responses.

- Static asset / JS headers: add X-Frame-Options, Referrer-Policy,
  Permissions-Policy, and Content-Security-Policy to static_asset_headers_json
  and js_headers_json. These were only present on HTML/API responses before.

- Fix state key bug: share_card_page read state_get("__neuron_origin__") but
  the key registered at startup is "__origin__", causing empty base URLs in
  share card og: meta tags.
This commit is contained in:
2026-05-10 23:56:31 -05:00
parent fe418bf3f7
commit 3f3c5cf149
+127 -13
View File
@@ -78,7 +78,7 @@ from pricing import { pricing }
from marketplace import { marketplace }
from viral import { viral }
from footer import { footer }
from styles import { page_open, page_close }
from styles import { page_open, page_open_seo, page_close }
from about import { about_page }
from founding_badge import { founding_badge, founding_badge_css }
from terms import { terms_page }
@@ -224,7 +224,7 @@ fn share_card_page(question: String, answer_plain: String, answer_html_in: Strin
// Use plaintext for og:description so social previews are readable.
let answer: String = answer_plain
let og_desc: String = str_slice(answer, 0, 140)
let base_url: String = state_get("__neuron_origin__")
let base_url: String = state_get("__origin__")
let card_url: String = base_url + "/share/" + id
// Pre-built share hrefs ID is digits so no URL encoding needed
let share_text: String = "The+AI+that+remembers+you+%E2%80%94+things+it+said%3A"
@@ -554,7 +554,7 @@ fn config_get(key: String) -> String {
// function - it serves __html_file__ directly with text/html.
// This handler covers /api/* and /brand/* routes.
fn handle_request_inner(method: String, path: String, body: String) -> String {
fn handle_request_inner(method: String, path: String, headers: Map, body: String) -> String {
let src_dir: String = state_get("__src_dir__")
// Root serve El-generated landing page
@@ -572,7 +572,19 @@ fn handle_request_inner(method: String, path: String, body: String) -> String {
// robots.txt
if str_eq(path, "/robots.txt") {
return "User-agent: *\nAllow: /\n"
return "User-agent: *\nAllow: /\nDisallow: /checkout\nDisallow: /account\nDisallow: /api/\nSitemap: https://neurontechnologies.ai/sitemap.xml\n"
}
// sitemap.xml
if str_eq(path, "/sitemap.xml") {
let sitemap_body: String = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n"
+ " <url><loc>https://neurontechnologies.ai/</loc><changefreq>weekly</changefreq><priority>1.0</priority></url>\n"
+ " <url><loc>https://neurontechnologies.ai/about</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>\n"
+ " <url><loc>https://neurontechnologies.ai/legal/terms</loc><changefreq>monthly</changefreq><priority>0.3</priority></url>\n"
+ " <url><loc>https://neurontechnologies.ai/legal/enterprise-terms</loc><changefreq>monthly</changefreq><priority>0.3</priority></url>\n"
+ "</urlset>\n"
return http_response(200, "{\"Content-Type\":\"application/xml; charset=utf-8\"}", sitemap_body)
}
// About page
@@ -612,7 +624,25 @@ fn handle_request_inner(method: String, path: String, body: String) -> String {
plan = "free"
}
let pub_key: String = state_get("__stripe_publishable_key__")
return page_open() + checkout_page(plan, pub_key) + page_close()
let checkout_title: String = if str_eq(plan, "founding") {
"Founding Member Checkout — Neuron"
} else {
if str_eq(plan, "free") {
"Get Started Free — Neuron"
} else {
"Professional Plan Checkout — Neuron"
}
}
let checkout_desc: String = if str_eq(plan, "founding") {
"Secure your Founding Member spot. Pay once, $199 lifetime — Neuron inference included at launch, priced below the major APIs. First 1,000 only."
} else {
if str_eq(plan, "free") {
"Create your free Neuron account. No credit card required. Your AI that remembers you — runs on your machine, never resets."
} else {
"Subscribe to Neuron Professional for $19/month. The AI that remembers you — persistent memory, runs locally, bring your own API keys."
}
}
return page_open_seo(checkout_title, checkout_desc, "/checkout", checkout_desc, "true") + checkout_page(plan, pub_key) + page_close()
}
// Stripe payment intent / setup intent
@@ -1116,14 +1146,33 @@ fn handle_request_inner(method: String, path: String, body: String) -> String {
}
// Supabase public config
// CORS-gated: only requests from neurontechnologies.ai origins or localhost
// may fetch the anon key. Restricting this reduces the blast radius of any
// future Supabase RLS misconfiguration an attacker on an arbitrary origin
// would not be able to silently obtain the key to make authenticated calls.
if str_eq(path, "/api/supabase-config") {
let req_origin: String = map_get(headers, "origin")
let origin_ok: Bool = str_eq(req_origin, "")
|| str_eq(req_origin, "https://neurontechnologies.ai")
|| str_eq(req_origin, "https://www.neurontechnologies.ai")
|| str_starts_with(req_origin, "http://localhost:")
|| str_starts_with(req_origin, "http://127.0.0.1:")
if !origin_ok {
return "{\"__status__\":403,\"error\":\"forbidden\"}"
}
let proj_url: String = "https://ocojsghaonltunidkzpw.supabase.co"
let anon_key: String = state_get("__supabase_anon_key__")
return "{\"url\":\"" + proj_url + "\",\"anon_key\":\"" + anon_key + "\"}"
}
// Soul health diagnostic surfaces raw signal from in-container soul
// Requires X-Internal: true header to prevent public exposure of internal
// service topology, soul URL, and probe responses.
if str_eq(path, "/api/soul-health") {
let x_internal: String = map_get(headers, "x-internal")
if !str_eq(x_internal, "true") {
return "{\"__status__\":404,\"error\":\"not found\"}"
}
if str_eq(method, "GET") {
let soul_base: String = state_get("__soul_url__")
// Probe 1: bare GET / does ANYTHING listen?
@@ -1396,7 +1445,51 @@ fn handle_request_inner(method: String, path: String, body: String) -> String {
// magic-link invite email so the buyer can sign in and see their
// plan on /account. Idempotent: existing users get a fresh link.
// 4. Forwards to license API for key provisioning when configured.
//
// SECURITY: Stripe-Signature header is verified via HMAC-SHA256 before
// any processing occurs. Without this check an attacker could POST a
// forged payment_intent.succeeded event and increment the founding counter
// or trigger account provisioning for an arbitrary email.
//
// Stripe signature format: "t=<timestamp>,v1=<hex_sig>[,v1=...]"
// Signed payload: "<timestamp>.<raw_body>"
// Key: STRIPE_WEBHOOK_SECRET (whsec_... value from Stripe dashboard)
if str_eq(path, "/api/webhooks/stripe") {
let wh_secret: String = state_get("__stripe_webhook_secret__")
if !str_eq(wh_secret, "") {
let sig_header: String = map_get(headers, "stripe-signature")
if str_eq(sig_header, "") {
println("[webhook] rejected: missing Stripe-Signature header")
return "{\"__status__\":400,\"error\":\"missing signature\"}"
}
// Extract t= value from sig header
let t_idx: Int = str_index_of(sig_header, "t=")
let t_val: String = ""
if t_idx >= 0 {
let t_tail: String = str_slice(sig_header, t_idx + 2, str_len(sig_header))
let t_comma: Int = str_index_of(t_tail, ",")
let t_val = if t_comma >= 0 { str_slice(t_tail, 0, t_comma) } else { t_tail }
}
// Extract v1= value from sig header
let v1_idx: Int = str_index_of(sig_header, "v1=")
let v1_val: String = ""
if v1_idx >= 0 {
let v1_tail: String = str_slice(sig_header, v1_idx + 3, str_len(sig_header))
let v1_comma: Int = str_index_of(v1_tail, ",")
let v1_val = if v1_comma >= 0 { str_slice(v1_tail, 0, v1_comma) } else { v1_tail }
}
if str_eq(t_val, "") || str_eq(v1_val, "") {
println("[webhook] rejected: malformed Stripe-Signature header")
return "{\"__status__\":400,\"error\":\"invalid signature format\"}"
}
// Compute expected HMAC: HMAC-SHA256(secret, "<t_val>.<body>")
let signed_payload: String = t_val + "." + body
let expected_sig: String = hmac_sha256_hex(wh_secret, signed_payload)
if !str_eq(expected_sig, v1_val) {
println("[webhook] rejected: signature mismatch")
return "{\"__status__\":400,\"error\":\"signature verification failed\"}"
}
}
let is_session_done: Bool = str_contains(body, "checkout.session.completed")
let is_pi_done: Bool = str_contains(body, "payment_intent.succeeded")
let is_si_done: Bool = str_contains(body, "setup_intent.succeeded")
@@ -1841,7 +1934,13 @@ fn handle_request_inner(method: String, path: String, body: String) -> String {
+ el_a("/", "class=\"btn-ghost\"", "Back to home")
)
)
return page_open() + badge_css + success_body + page_close()
return page_open_seo(
"Welcome to Neuron — Your Membership is Confirmed",
"Your Neuron membership is confirmed. Download the app and let the AI that remembers you get to work.",
"/marketplace/success",
"Your Neuron membership is confirmed. Download the app and let the AI that remembers you get to work.",
"true"
) + badge_css + success_body + page_close()
}
// Account dashboard
@@ -2062,21 +2161,28 @@ fn js_headers_json() -> String {
+ "\"X-Content-Type-Options\":\"nosniff\","
+ "\"X-Frame-Options\":\"SAMEORIGIN\","
+ "\"Referrer-Policy\":\"strict-origin-when-cross-origin\","
+ "\"Permissions-Policy\":\"geolocation=(), microphone=(), camera=()\"}"
+ "\"Permissions-Policy\":\"geolocation=(), microphone=(), camera=()\","
+ "\"Content-Security-Policy\":\"default-src 'self'; script-src 'self' 'unsafe-inline' https://challenges.cloudflare.com https://cdn.jsdelivr.net https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; frame-src https://challenges.cloudflare.com; connect-src 'self' https://api.stripe.com https://*.supabase.co; img-src 'self' data: https:; font-src 'self' data:\"}"
}
// Headers for static assets under /assets/ and /brand/.
// max-age=31536000 (1 year) + immutable tells Cloudflare to cache at the edge
// and never revalidate assets are versioned by filename or content so stale
// delivery is not a risk. This eliminates Cloud Run hits for every image/font/svg.
// Security headers are included so asset responses are equally hardened even
// when served directly (e.g. Cloudflare bypass or direct origin fetch).
fn static_asset_headers_json() -> String {
"{\"Cache-Control\":\"public, max-age=31536000, immutable\","
+ "\"Strict-Transport-Security\":\"max-age=63072000; includeSubDomains; preload\","
+ "\"X-Content-Type-Options\":\"nosniff\"}"
+ "\"X-Content-Type-Options\":\"nosniff\","
+ "\"X-Frame-Options\":\"SAMEORIGIN\","
+ "\"Referrer-Policy\":\"strict-origin-when-cross-origin\","
+ "\"Permissions-Policy\":\"geolocation=(), microphone=(), camera=()\","
+ "\"Content-Security-Policy\":\"default-src 'self'; script-src 'self' 'unsafe-inline' https://challenges.cloudflare.com https://cdn.jsdelivr.net https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; frame-src https://challenges.cloudflare.com; connect-src 'self' https://api.stripe.com https://*.supabase.co; img-src 'self' data: https:; font-src 'self' data:\"}"
}
fn handle_request(method: String, path: String, body: String) -> String {
let inner_resp: String = handle_request_inner(method, path, body)
fn handle_request(method: String, path: String, headers: Map, body: String) -> String {
let inner_resp: String = handle_request_inner(method, path, headers, body)
// Detect envelope already set by inner handler (starts with
// {"el_http_response":1). If so, let it pass through unmodified
// the status code it carries takes precedence and we must not
@@ -2121,6 +2227,7 @@ let stripe_pub_key: String = env("STRIPE_PUBLISHABLE_KEY")
let stripe_price_founding: String = env("STRIPE_PRICE_FOUNDING")
let stripe_price_professional: String = env("STRIPE_PRICE_PROFESSIONAL")
let family_child_price: String = env("STRIPE_PRICE_FAMILY_CHILD")
let stripe_webhook_secret: String = env("STRIPE_WEBHOOK_SECRET")
let license_api_url: String = env("NEURON_LICENSE_API_URL")
let resend_api_key: String = env("RESEND_API_KEY")
let supabase_anon_key: String = env("SUPABASE_ANON_KEY")
@@ -2145,7 +2252,13 @@ fs_write(html_path, page_html)
// Generate about page HTML.
let about_html_path: String = src_dir + "/about.html"
let about_html: String = page_open() + about_page() + page_close()
let about_html: String = page_open_seo(
"About Will Anderson — Neuron",
"Neuron was built by one person. Will Anderson — engineer, founder, and the sole author of every line of Neuron's code. This is his story.",
"/about",
"Neuron was built by one person. Will Anderson spent nearly two years building the AI that remembers you — the memory architecture, the inference infrastructure, everything from the ground up.",
"false"
) + about_page() + page_close()
fs_write(about_html_path, about_html)
// Generate terms pages HTML.
@@ -2175,6 +2288,7 @@ state_set("__founding_sold_file__", sold_file)
state_set("__founding_sold__", int_to_str(real_sold))
state_set("__founding_total__", int_to_str(FOUNDING_TOTAL))
state_set("__turnstile_secret_key__", turnstile_secret_key)
state_set("__stripe_webhook_secret__", stripe_webhook_secret)
persist_founding_count(real_sold)
println(color_bold("Neuron") + " - " + neuron_origin)
@@ -2201,5 +2315,5 @@ println(" GET /api/supabase-config → public Supabase config (URL + a
println("")
let port: Int = if str_eq(env("PORT"), "") { 3001 } else { str_to_int(env("PORT")) }
http_set_handler("handle_request")
http_serve(port, "handle_request")
http_set_handler_v2("handle_request")
http_serve_v2(port, "handle_request")